Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
a6b44da636
@ -14,6 +14,7 @@
|
|||||||
stage: build
|
stage: build
|
||||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||||
needs: []
|
needs: []
|
||||||
|
timeout: 80m
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
- source .gitlab-ci.d/cirrus/$NAME.vars
|
- source .gitlab-ci.d/cirrus/$NAME.vars
|
||||||
@ -40,6 +41,9 @@
|
|||||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||||
rules:
|
rules:
|
||||||
|
# Allow on 'staging' branch and 'stable-X.Y-staging' branches only
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/'
|
||||||
|
when: never
|
||||||
- if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN"
|
- if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN"
|
||||||
|
|
||||||
x64-freebsd-12-build:
|
x64-freebsd-12-build:
|
||||||
|
@ -13,238 +13,7 @@
|
|||||||
variables:
|
variables:
|
||||||
GIT_STRATEGY: clone
|
GIT_STRATEGY: clone
|
||||||
|
|
||||||
# All ubuntu-18.04 jobs should run successfully in an environment
|
include:
|
||||||
# setup by the scripts/ci/setup/build-environment.yml task
|
- local: '/.gitlab-ci.d/custom-runners/ubuntu-18.04-s390x.yml'
|
||||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
- local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml'
|
||||||
ubuntu-18.04-s390x-all-linux-static:
|
- local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml'
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_18.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
|
||||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
- make --output-sync -j`nproc` check-tcg V=1
|
|
||||||
|
|
||||||
ubuntu-18.04-s390x-all:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_18.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
ubuntu-18.04-s390x-alldbg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_18.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug --disable-libssh
|
|
||||||
- make clean
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
ubuntu-18.04-s390x-clang:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_18.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
ubuntu-18.04-s390x-tci:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_18.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
|
|
||||||
ubuntu-18.04-s390x-notcg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_18.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --disable-tcg
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
# All ubuntu-20.04 jobs should run successfully in an environment
|
|
||||||
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
|
||||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
|
||||||
ubuntu-20.04-aarch64-all-linux-static:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
|
||||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
- make --output-sync -j`nproc` check-tcg V=1
|
|
||||||
|
|
||||||
ubuntu-20.04-aarch64-all:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
ubuntu-20.04-aarch64-alldbg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug --disable-libssh
|
|
||||||
- make clean
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
ubuntu-20.04-aarch64-clang:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
|
||||||
ubuntu-20.04-aarch64-tci:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
|
|
||||||
ubuntu-20.04-aarch64-notcg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --disable-tcg
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|
28
.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml
Normal file
28
.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
centos-stream-8-x86_64:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- centos_stream_8
|
||||||
|
- x86_64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE"
|
||||||
|
artifacts:
|
||||||
|
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||||
|
when: on_failure
|
||||||
|
expire_in: 7 days
|
||||||
|
paths:
|
||||||
|
- build/tests/results/latest/results.xml
|
||||||
|
- build/tests/results/latest/test-results
|
||||||
|
reports:
|
||||||
|
junit: build/tests/results/latest/results.xml
|
||||||
|
before_script:
|
||||||
|
- JOBS=$(expr $(nproc) + 1)
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../scripts/ci/org.centos/stream/8/x86_64/configure
|
||||||
|
- make -j"$JOBS"
|
||||||
|
- make NINJA=":" check
|
||||||
|
- ../scripts/ci/org.centos/stream/8/x86_64/test-avocado
|
118
.gitlab-ci.d/custom-runners/ubuntu-18.04-s390x.yml
Normal file
118
.gitlab-ci.d/custom-runners/ubuntu-18.04-s390x.yml
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# All ubuntu-18.04 jobs should run successfully in an environment
|
||||||
|
# setup by the scripts/ci/setup/build-environment.yml task
|
||||||
|
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-all-linux-static:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||||
|
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
- make --output-sync -j`nproc` check-tcg V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-all:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-alldbg:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --disable-libssh
|
||||||
|
- make clean
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-clang:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-tci:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-notcg:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --disable-tcg
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
118
.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml
Normal file
118
.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# All ubuntu-20.04 jobs should run successfully in an environment
|
||||||
|
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
||||||
|
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-all-linux-static:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||||
|
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
- make --output-sync -j`nproc` check-tcg V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-all:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-alldbg:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --disable-libssh
|
||||||
|
- make clean
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-clang:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-tci:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-notcg:
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --disable-tcg
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
@ -10,7 +10,7 @@ tcg_ss.add(files(
|
|||||||
))
|
))
|
||||||
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
||||||
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
|
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
|
||||||
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
|
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')])
|
||||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
||||||
|
|
||||||
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||||
|
235
block.c
235
block.c
@ -87,8 +87,10 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
|
|||||||
static bool bdrv_recurse_has_child(BlockDriverState *bs,
|
static bool bdrv_recurse_has_child(BlockDriverState *bs,
|
||||||
BlockDriverState *child);
|
BlockDriverState *child);
|
||||||
|
|
||||||
static void bdrv_replace_child_noperm(BdrvChild *child,
|
static void bdrv_child_free(BdrvChild *child);
|
||||||
BlockDriverState *new_bs);
|
static void bdrv_replace_child_noperm(BdrvChild **child,
|
||||||
|
BlockDriverState *new_bs,
|
||||||
|
bool free_empty_child);
|
||||||
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
|
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
|
||||||
BdrvChild *child,
|
BdrvChild *child,
|
||||||
Transaction *tran);
|
Transaction *tran);
|
||||||
@ -1387,6 +1389,8 @@ static void bdrv_child_cb_attach(BdrvChild *child)
|
|||||||
{
|
{
|
||||||
BlockDriverState *bs = child->opaque;
|
BlockDriverState *bs = child->opaque;
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD(&bs->children, child, next);
|
||||||
|
|
||||||
if (child->role & BDRV_CHILD_COW) {
|
if (child->role & BDRV_CHILD_COW) {
|
||||||
bdrv_backing_attach(child);
|
bdrv_backing_attach(child);
|
||||||
}
|
}
|
||||||
@ -1403,6 +1407,8 @@ static void bdrv_child_cb_detach(BdrvChild *child)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bdrv_unapply_subtree_drain(child, bs);
|
bdrv_unapply_subtree_drain(child, bs);
|
||||||
|
|
||||||
|
QLIST_REMOVE(child, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
|
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
|
||||||
@ -2250,13 +2256,18 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
|
|||||||
|
|
||||||
typedef struct BdrvReplaceChildState {
|
typedef struct BdrvReplaceChildState {
|
||||||
BdrvChild *child;
|
BdrvChild *child;
|
||||||
|
BdrvChild **childp;
|
||||||
BlockDriverState *old_bs;
|
BlockDriverState *old_bs;
|
||||||
|
bool free_empty_child;
|
||||||
} BdrvReplaceChildState;
|
} BdrvReplaceChildState;
|
||||||
|
|
||||||
static void bdrv_replace_child_commit(void *opaque)
|
static void bdrv_replace_child_commit(void *opaque)
|
||||||
{
|
{
|
||||||
BdrvReplaceChildState *s = opaque;
|
BdrvReplaceChildState *s = opaque;
|
||||||
|
|
||||||
|
if (s->free_empty_child && !s->child->bs) {
|
||||||
|
bdrv_child_free(s->child);
|
||||||
|
}
|
||||||
bdrv_unref(s->old_bs);
|
bdrv_unref(s->old_bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2265,8 +2276,34 @@ static void bdrv_replace_child_abort(void *opaque)
|
|||||||
BdrvReplaceChildState *s = opaque;
|
BdrvReplaceChildState *s = opaque;
|
||||||
BlockDriverState *new_bs = s->child->bs;
|
BlockDriverState *new_bs = s->child->bs;
|
||||||
|
|
||||||
/* old_bs reference is transparently moved from @s to @s->child */
|
/*
|
||||||
bdrv_replace_child_noperm(s->child, s->old_bs);
|
* old_bs reference is transparently moved from @s to s->child.
|
||||||
|
*
|
||||||
|
* Pass &s->child here instead of s->childp, because:
|
||||||
|
* (1) s->old_bs must be non-NULL, so bdrv_replace_child_noperm() will not
|
||||||
|
* modify the BdrvChild * pointer we indirectly pass to it, i.e. it
|
||||||
|
* will not modify s->child. From that perspective, it does not matter
|
||||||
|
* whether we pass s->childp or &s->child.
|
||||||
|
* (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use
|
||||||
|
* it here.
|
||||||
|
* (3) If new_bs is NULL, *s->childp will have been NULLed by
|
||||||
|
* bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we
|
||||||
|
* must not pass a NULL *s->childp here.
|
||||||
|
*
|
||||||
|
* So whether new_bs was NULL or not, we cannot pass s->childp here; and in
|
||||||
|
* any case, there is no reason to pass it anyway.
|
||||||
|
*/
|
||||||
|
bdrv_replace_child_noperm(&s->child, s->old_bs, true);
|
||||||
|
/*
|
||||||
|
* The child was pre-existing, so s->old_bs must be non-NULL, and
|
||||||
|
* s->child thus must not have been freed
|
||||||
|
*/
|
||||||
|
assert(s->child != NULL);
|
||||||
|
if (!new_bs) {
|
||||||
|
/* As described above, *s->childp was cleared, so restore it */
|
||||||
|
assert(s->childp != NULL);
|
||||||
|
*s->childp = s->child;
|
||||||
|
}
|
||||||
bdrv_unref(new_bs);
|
bdrv_unref(new_bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2282,22 +2319,46 @@ static TransactionActionDrv bdrv_replace_child_drv = {
|
|||||||
* Note: real unref of old_bs is done only on commit.
|
* Note: real unref of old_bs is done only on commit.
|
||||||
*
|
*
|
||||||
* The function doesn't update permissions, caller is responsible for this.
|
* The function doesn't update permissions, caller is responsible for this.
|
||||||
|
*
|
||||||
|
* (*childp)->bs must not be NULL.
|
||||||
|
*
|
||||||
|
* Note that if new_bs == NULL, @childp is stored in a state object attached
|
||||||
|
* to @tran, so that the old child can be reinstated in the abort handler.
|
||||||
|
* Therefore, if @new_bs can be NULL, @childp must stay valid until the
|
||||||
|
* transaction is committed or aborted.
|
||||||
|
*
|
||||||
|
* If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
|
||||||
|
* freed (on commit). @free_empty_child should only be false if the
|
||||||
|
* caller will free the BDrvChild themselves (which may be important
|
||||||
|
* if this is in turn called in another transactional context).
|
||||||
*/
|
*/
|
||||||
static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
|
static void bdrv_replace_child_tran(BdrvChild **childp,
|
||||||
Transaction *tran)
|
BlockDriverState *new_bs,
|
||||||
|
Transaction *tran,
|
||||||
|
bool free_empty_child)
|
||||||
{
|
{
|
||||||
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
|
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
|
||||||
*s = (BdrvReplaceChildState) {
|
*s = (BdrvReplaceChildState) {
|
||||||
.child = child,
|
.child = *childp,
|
||||||
.old_bs = child->bs,
|
.childp = new_bs == NULL ? childp : NULL,
|
||||||
|
.old_bs = (*childp)->bs,
|
||||||
|
.free_empty_child = free_empty_child,
|
||||||
};
|
};
|
||||||
tran_add(tran, &bdrv_replace_child_drv, s);
|
tran_add(tran, &bdrv_replace_child_drv, s);
|
||||||
|
|
||||||
|
/* The abort handler relies on this */
|
||||||
|
assert(s->old_bs != NULL);
|
||||||
|
|
||||||
if (new_bs) {
|
if (new_bs) {
|
||||||
bdrv_ref(new_bs);
|
bdrv_ref(new_bs);
|
||||||
}
|
}
|
||||||
bdrv_replace_child_noperm(child, new_bs);
|
/*
|
||||||
/* old_bs reference is transparently moved from @child to @s */
|
* Pass free_empty_child=false, we will free the child (if
|
||||||
|
* necessary) in bdrv_replace_child_commit() (if our
|
||||||
|
* @free_empty_child parameter was true).
|
||||||
|
*/
|
||||||
|
bdrv_replace_child_noperm(childp, new_bs, false);
|
||||||
|
/* old_bs reference is transparently moved from *childp to @s */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2668,9 +2729,24 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
|
|||||||
return permissions[qapi_perm];
|
return permissions[qapi_perm];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_replace_child_noperm(BdrvChild *child,
|
/**
|
||||||
BlockDriverState *new_bs)
|
* Replace (*childp)->bs by @new_bs.
|
||||||
|
*
|
||||||
|
* If @new_bs is NULL, *childp will be set to NULL, too: BDS parents
|
||||||
|
* generally cannot handle a BdrvChild with .bs == NULL, so clearing
|
||||||
|
* BdrvChild.bs should generally immediately be followed by the
|
||||||
|
* BdrvChild pointer being cleared as well.
|
||||||
|
*
|
||||||
|
* If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
|
||||||
|
* freed. @free_empty_child should only be false if the caller will
|
||||||
|
* free the BdrvChild themselves (this may be important in a
|
||||||
|
* transactional context, where it may only be freed on commit).
|
||||||
|
*/
|
||||||
|
static void bdrv_replace_child_noperm(BdrvChild **childp,
|
||||||
|
BlockDriverState *new_bs,
|
||||||
|
bool free_empty_child)
|
||||||
{
|
{
|
||||||
|
BdrvChild *child = *childp;
|
||||||
BlockDriverState *old_bs = child->bs;
|
BlockDriverState *old_bs = child->bs;
|
||||||
int new_bs_quiesce_counter;
|
int new_bs_quiesce_counter;
|
||||||
int drain_saldo;
|
int drain_saldo;
|
||||||
@ -2705,6 +2781,9 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
|
|||||||
}
|
}
|
||||||
|
|
||||||
child->bs = new_bs;
|
child->bs = new_bs;
|
||||||
|
if (!new_bs) {
|
||||||
|
*childp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (new_bs) {
|
if (new_bs) {
|
||||||
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
|
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
|
||||||
@ -2734,21 +2813,25 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
|
|||||||
bdrv_parent_drained_end_single(child);
|
bdrv_parent_drained_end_single(child);
|
||||||
drain_saldo++;
|
drain_saldo++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (free_empty_child && !child->bs) {
|
||||||
|
bdrv_child_free(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_child_free(void *opaque)
|
/**
|
||||||
{
|
* Free the given @child.
|
||||||
BdrvChild *c = opaque;
|
*
|
||||||
|
* The child must be empty (i.e. `child->bs == NULL`) and it must be
|
||||||
g_free(c->name);
|
* unused (i.e. not in a children list).
|
||||||
g_free(c);
|
*/
|
||||||
}
|
static void bdrv_child_free(BdrvChild *child)
|
||||||
|
|
||||||
static void bdrv_remove_empty_child(BdrvChild *child)
|
|
||||||
{
|
{
|
||||||
assert(!child->bs);
|
assert(!child->bs);
|
||||||
QLIST_SAFE_REMOVE(child, next);
|
assert(!child->next.le_prev); /* not in children list */
|
||||||
bdrv_child_free(child);
|
|
||||||
|
g_free(child->name);
|
||||||
|
g_free(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct BdrvAttachChildCommonState {
|
typedef struct BdrvAttachChildCommonState {
|
||||||
@ -2763,27 +2846,35 @@ static void bdrv_attach_child_common_abort(void *opaque)
|
|||||||
BdrvChild *child = *s->child;
|
BdrvChild *child = *s->child;
|
||||||
BlockDriverState *bs = child->bs;
|
BlockDriverState *bs = child->bs;
|
||||||
|
|
||||||
bdrv_replace_child_noperm(child, NULL);
|
/*
|
||||||
|
* Pass free_empty_child=false, because we still need the child
|
||||||
|
* for the AioContext operations on the parent below; those
|
||||||
|
* BdrvChildClass methods all work on a BdrvChild object, so we
|
||||||
|
* need to keep it as an empty shell (after this function, it will
|
||||||
|
* not be attached to any parent, and it will not have a .bs).
|
||||||
|
*/
|
||||||
|
bdrv_replace_child_noperm(s->child, NULL, false);
|
||||||
|
|
||||||
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
|
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
|
||||||
bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
|
bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
|
if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
|
||||||
GSList *ignore = g_slist_prepend(NULL, child);
|
GSList *ignore;
|
||||||
|
|
||||||
|
/* No need to ignore `child`, because it has been detached already */
|
||||||
|
ignore = NULL;
|
||||||
child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
|
child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
g_slist_free(ignore);
|
g_slist_free(ignore);
|
||||||
ignore = g_slist_prepend(NULL, child);
|
|
||||||
child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
|
|
||||||
|
|
||||||
|
ignore = NULL;
|
||||||
|
child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
|
||||||
g_slist_free(ignore);
|
g_slist_free(ignore);
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_unref(bs);
|
bdrv_unref(bs);
|
||||||
bdrv_remove_empty_child(child);
|
bdrv_child_free(child);
|
||||||
*s->child = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static TransactionActionDrv bdrv_attach_child_common_drv = {
|
static TransactionActionDrv bdrv_attach_child_common_drv = {
|
||||||
@ -2855,13 +2946,15 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
|
|||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
bdrv_remove_empty_child(new_child);
|
bdrv_child_free(new_child);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_ref(child_bs);
|
bdrv_ref(child_bs);
|
||||||
bdrv_replace_child_noperm(new_child, child_bs);
|
bdrv_replace_child_noperm(&new_child, child_bs, true);
|
||||||
|
/* child_bs was non-NULL, so new_child must not have been freed */
|
||||||
|
assert(new_child != NULL);
|
||||||
|
|
||||||
*child = new_child;
|
*child = new_child;
|
||||||
|
|
||||||
@ -2913,21 +3006,14 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&parent_bs->children, *child, next);
|
|
||||||
/*
|
|
||||||
* child is removed in bdrv_attach_child_common_abort(), so don't care to
|
|
||||||
* abort this change separately.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bdrv_detach_child(BdrvChild *child)
|
static void bdrv_detach_child(BdrvChild **childp)
|
||||||
{
|
{
|
||||||
BlockDriverState *old_bs = child->bs;
|
BlockDriverState *old_bs = (*childp)->bs;
|
||||||
|
|
||||||
bdrv_replace_child_noperm(child, NULL);
|
bdrv_replace_child_noperm(childp, NULL, true);
|
||||||
bdrv_remove_empty_child(child);
|
|
||||||
|
|
||||||
if (old_bs) {
|
if (old_bs) {
|
||||||
/*
|
/*
|
||||||
@ -3033,7 +3119,7 @@ void bdrv_root_unref_child(BdrvChild *child)
|
|||||||
BlockDriverState *child_bs;
|
BlockDriverState *child_bs;
|
||||||
|
|
||||||
child_bs = child->bs;
|
child_bs = child->bs;
|
||||||
bdrv_detach_child(child);
|
bdrv_detach_child(&child);
|
||||||
bdrv_unref(child_bs);
|
bdrv_unref(child_bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4843,6 +4929,7 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
|
|||||||
|
|
||||||
typedef struct BdrvRemoveFilterOrCowChild {
|
typedef struct BdrvRemoveFilterOrCowChild {
|
||||||
BdrvChild *child;
|
BdrvChild *child;
|
||||||
|
BlockDriverState *bs;
|
||||||
bool is_backing;
|
bool is_backing;
|
||||||
} BdrvRemoveFilterOrCowChild;
|
} BdrvRemoveFilterOrCowChild;
|
||||||
|
|
||||||
@ -4851,7 +4938,6 @@ static void bdrv_remove_filter_or_cow_child_abort(void *opaque)
|
|||||||
BdrvRemoveFilterOrCowChild *s = opaque;
|
BdrvRemoveFilterOrCowChild *s = opaque;
|
||||||
BlockDriverState *parent_bs = s->child->opaque;
|
BlockDriverState *parent_bs = s->child->opaque;
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&parent_bs->children, s->child, next);
|
|
||||||
if (s->is_backing) {
|
if (s->is_backing) {
|
||||||
parent_bs->backing = s->child;
|
parent_bs->backing = s->child;
|
||||||
} else {
|
} else {
|
||||||
@ -4873,10 +4959,19 @@ static void bdrv_remove_filter_or_cow_child_commit(void *opaque)
|
|||||||
bdrv_child_free(s->child);
|
bdrv_child_free(s->child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bdrv_remove_filter_or_cow_child_clean(void *opaque)
|
||||||
|
{
|
||||||
|
BdrvRemoveFilterOrCowChild *s = opaque;
|
||||||
|
|
||||||
|
/* Drop the bs reference after the transaction is done */
|
||||||
|
bdrv_unref(s->bs);
|
||||||
|
g_free(s);
|
||||||
|
}
|
||||||
|
|
||||||
static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
|
static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
|
||||||
.abort = bdrv_remove_filter_or_cow_child_abort,
|
.abort = bdrv_remove_filter_or_cow_child_abort,
|
||||||
.commit = bdrv_remove_filter_or_cow_child_commit,
|
.commit = bdrv_remove_filter_or_cow_child_commit,
|
||||||
.clean = g_free,
|
.clean = bdrv_remove_filter_or_cow_child_clean,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4887,31 +4982,41 @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
|
|||||||
BdrvChild *child,
|
BdrvChild *child,
|
||||||
Transaction *tran)
|
Transaction *tran)
|
||||||
{
|
{
|
||||||
|
BdrvChild **childp;
|
||||||
BdrvRemoveFilterOrCowChild *s;
|
BdrvRemoveFilterOrCowChild *s;
|
||||||
|
|
||||||
assert(child == bs->backing || child == bs->file);
|
|
||||||
|
|
||||||
if (!child) {
|
if (!child) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep a reference to @bs so @childp will stay valid throughout the
|
||||||
|
* transaction (required by bdrv_replace_child_tran())
|
||||||
|
*/
|
||||||
|
bdrv_ref(bs);
|
||||||
|
if (child == bs->backing) {
|
||||||
|
childp = &bs->backing;
|
||||||
|
} else if (child == bs->file) {
|
||||||
|
childp = &bs->file;
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
if (child->bs) {
|
if (child->bs) {
|
||||||
bdrv_replace_child_tran(child, NULL, tran);
|
/*
|
||||||
|
* Pass free_empty_child=false, we will free the child in
|
||||||
|
* bdrv_remove_filter_or_cow_child_commit()
|
||||||
|
*/
|
||||||
|
bdrv_replace_child_tran(childp, NULL, tran, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = g_new(BdrvRemoveFilterOrCowChild, 1);
|
s = g_new(BdrvRemoveFilterOrCowChild, 1);
|
||||||
*s = (BdrvRemoveFilterOrCowChild) {
|
*s = (BdrvRemoveFilterOrCowChild) {
|
||||||
.child = child,
|
.child = child,
|
||||||
.is_backing = (child == bs->backing),
|
.bs = bs,
|
||||||
|
.is_backing = (childp == &bs->backing),
|
||||||
};
|
};
|
||||||
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
|
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
|
||||||
|
|
||||||
QLIST_SAFE_REMOVE(child, next);
|
|
||||||
if (s->is_backing) {
|
|
||||||
bs->backing = NULL;
|
|
||||||
} else {
|
|
||||||
bs->file = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4932,6 +5037,8 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
|
|||||||
{
|
{
|
||||||
BdrvChild *c, *next;
|
BdrvChild *c, *next;
|
||||||
|
|
||||||
|
assert(to != NULL);
|
||||||
|
|
||||||
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
|
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
|
||||||
assert(c->bs == from);
|
assert(c->bs == from);
|
||||||
if (!should_update_child(c, to)) {
|
if (!should_update_child(c, to)) {
|
||||||
@ -4947,7 +5054,12 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
|
|||||||
c->name, from->node_name);
|
c->name, from->node_name);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
bdrv_replace_child_tran(c, to, tran);
|
|
||||||
|
/*
|
||||||
|
* Passing a pointer to the local variable @c is fine here, because
|
||||||
|
* @to is not NULL, and so &c will not be attached to the transaction.
|
||||||
|
*/
|
||||||
|
bdrv_replace_child_tran(&c, to, tran, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -4962,6 +5074,8 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
|
|||||||
*
|
*
|
||||||
* With @detach_subchain=true @to must be in a backing chain of @from. In this
|
* With @detach_subchain=true @to must be in a backing chain of @from. In this
|
||||||
* case backing link of the cow-parent of @to is removed.
|
* case backing link of the cow-parent of @to is removed.
|
||||||
|
*
|
||||||
|
* @to must not be NULL.
|
||||||
*/
|
*/
|
||||||
static int bdrv_replace_node_common(BlockDriverState *from,
|
static int bdrv_replace_node_common(BlockDriverState *from,
|
||||||
BlockDriverState *to,
|
BlockDriverState *to,
|
||||||
@ -4974,6 +5088,8 @@ static int bdrv_replace_node_common(BlockDriverState *from,
|
|||||||
BlockDriverState *to_cow_parent = NULL;
|
BlockDriverState *to_cow_parent = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
assert(to != NULL);
|
||||||
|
|
||||||
if (detach_subchain) {
|
if (detach_subchain) {
|
||||||
assert(bdrv_chain_contains(from, to));
|
assert(bdrv_chain_contains(from, to));
|
||||||
assert(from != to);
|
assert(from != to);
|
||||||
@ -5029,6 +5145,9 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace node @from by @to (where neither may be NULL).
|
||||||
|
*/
|
||||||
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
|
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -5096,7 +5215,9 @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
|
|||||||
bdrv_drained_begin(old_bs);
|
bdrv_drained_begin(old_bs);
|
||||||
bdrv_drained_begin(new_bs);
|
bdrv_drained_begin(new_bs);
|
||||||
|
|
||||||
bdrv_replace_child_tran(child, new_bs, tran);
|
bdrv_replace_child_tran(&child, new_bs, tran, true);
|
||||||
|
/* @new_bs must have been non-NULL, so @child must not have been freed */
|
||||||
|
assert(child != NULL);
|
||||||
|
|
||||||
found = g_hash_table_new(NULL, NULL);
|
found = g_hash_table_new(NULL, NULL);
|
||||||
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
|
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
|
||||||
|
@ -167,6 +167,7 @@ typedef struct BDRVRawState {
|
|||||||
int page_cache_inconsistent; /* errno from fdatasync failure */
|
int page_cache_inconsistent; /* errno from fdatasync failure */
|
||||||
bool has_fallocate;
|
bool has_fallocate;
|
||||||
bool needs_alignment;
|
bool needs_alignment;
|
||||||
|
bool force_alignment;
|
||||||
bool drop_cache;
|
bool drop_cache;
|
||||||
bool check_cache_dropped;
|
bool check_cache_dropped;
|
||||||
struct {
|
struct {
|
||||||
@ -351,6 +352,17 @@ static bool dio_byte_aligned(int fd)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool raw_needs_alignment(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
|
||||||
|
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s->force_alignment;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if read is allowed with given memory buffer and length.
|
/* Check if read is allowed with given memory buffer and length.
|
||||||
*
|
*
|
||||||
* This function is used to check O_DIRECT memory buffer and request alignment.
|
* This function is used to check O_DIRECT memory buffer and request alignment.
|
||||||
@ -728,9 +740,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
|
|
||||||
s->has_discard = true;
|
s->has_discard = true;
|
||||||
s->has_write_zeroes = true;
|
s->has_write_zeroes = true;
|
||||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
|
|
||||||
s->needs_alignment = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fstat(s->fd, &st) < 0) {
|
if (fstat(s->fd, &st) < 0) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
@ -784,9 +793,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
|||||||
* so QEMU makes sure all IO operations on the device are aligned
|
* so QEMU makes sure all IO operations on the device are aligned
|
||||||
* to sector size, or else FreeBSD will reject them with EINVAL.
|
* to sector size, or else FreeBSD will reject them with EINVAL.
|
||||||
*/
|
*/
|
||||||
s->needs_alignment = true;
|
s->force_alignment = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
s->needs_alignment = raw_needs_alignment(bs);
|
||||||
|
|
||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
if (platform_test_xfs_fd(s->fd)) {
|
if (platform_test_xfs_fd(s->fd)) {
|
||||||
@ -1251,7 +1261,9 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
s->needs_alignment = raw_needs_alignment(bs);
|
||||||
raw_probe_alignment(bs, s->fd, errp);
|
raw_probe_alignment(bs, s->fd, errp);
|
||||||
|
|
||||||
bs->bl.min_mem_alignment = s->buf_align;
|
bs->bl.min_mem_alignment = s->buf_align;
|
||||||
bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size);
|
bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size);
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ static int stream_prepare(Job *job)
|
|||||||
{
|
{
|
||||||
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
|
||||||
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
|
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
|
||||||
BlockDriverState *base = bdrv_filter_or_cow_bs(s->above_base);
|
BlockDriverState *base;
|
||||||
BlockDriverState *unfiltered_base = bdrv_skip_filters(base);
|
BlockDriverState *unfiltered_base;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@ -63,6 +63,9 @@ static int stream_prepare(Job *job)
|
|||||||
bdrv_cor_filter_drop(s->cor_filter_bs);
|
bdrv_cor_filter_drop(s->cor_filter_bs);
|
||||||
s->cor_filter_bs = NULL;
|
s->cor_filter_bs = NULL;
|
||||||
|
|
||||||
|
base = bdrv_filter_or_cow_bs(s->above_base);
|
||||||
|
unfiltered_base = bdrv_skip_filters(base);
|
||||||
|
|
||||||
if (bdrv_cow_child(unfiltered_bs)) {
|
if (bdrv_cow_child(unfiltered_bs)) {
|
||||||
const char *base_id = NULL, *base_fmt = NULL;
|
const char *base_id = NULL, *base_fmt = NULL;
|
||||||
if (unfiltered_base) {
|
if (unfiltered_base) {
|
||||||
|
@ -250,6 +250,20 @@ options are removed in favor of using explicit ``blockdev-create`` and
|
|||||||
``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for
|
``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
Incorrectly typed ``device_add`` arguments (since 6.2)
|
||||||
|
''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
Due to shortcomings in the internal implementation of ``device_add``, QEMU
|
||||||
|
incorrectly accepts certain invalid arguments: Any object or list arguments are
|
||||||
|
silently ignored. Other argument types are not checked, but an implicit
|
||||||
|
conversion happens, so that e.g. string values can be assigned to integer
|
||||||
|
device properties or vice versa.
|
||||||
|
|
||||||
|
This is a bug in QEMU that will be fixed in the future so that previously
|
||||||
|
accepted incorrect commands will return an error. Users should make sure that
|
||||||
|
all arguments passed to ``device_add`` are consistent with the documented
|
||||||
|
property types.
|
||||||
|
|
||||||
System accelerators
|
System accelerators
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -49,3 +49,10 @@ S390X_RUNNER_AVAILABLE
|
|||||||
If you've got access to an IBM Z host that can be used as a gitlab-CI
|
If you've got access to an IBM Z host that can be used as a gitlab-CI
|
||||||
runner, you can set this variable to enable the tests that require this
|
runner, you can set this variable to enable the tests that require this
|
||||||
kind of host. The runner should be tagged with "s390x".
|
kind of host. The runner should be tagged with "s390x".
|
||||||
|
|
||||||
|
CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
If you've got access to a CentOS Stream 8 x86_64 host that can be
|
||||||
|
used as a gitlab-CI runner, you can set this variable to enable the
|
||||||
|
tests that require this kind of host. The runner should be tagged with
|
||||||
|
both "centos_stream_8" and "x86_64".
|
||||||
|
@ -45,3 +45,6 @@ modifying QEMU's source code.
|
|||||||
vfio-migration
|
vfio-migration
|
||||||
qapi-code-gen
|
qapi-code-gen
|
||||||
writing-monitor-commands
|
writing-monitor-commands
|
||||||
|
trivial-patches
|
||||||
|
submitting-a-patch
|
||||||
|
submitting-a-pull-request
|
||||||
|
456
docs/devel/submitting-a-patch.rst
Normal file
456
docs/devel/submitting-a-patch.rst
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
Submitting a Patch
|
||||||
|
==================
|
||||||
|
|
||||||
|
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||||
|
functionality). However, we get a lot of patches, and so we have some
|
||||||
|
guidelines about submitting patches. If you follow these, you'll help
|
||||||
|
make our task of code review easier and your patch is likely to be
|
||||||
|
committed faster.
|
||||||
|
|
||||||
|
This page seems very long, so if you are only trying to post a quick
|
||||||
|
one-shot fix, the bare minimum we ask is that:
|
||||||
|
|
||||||
|
- You **must** provide a Signed-off-by: line (this is a hard
|
||||||
|
requirement because it's how you say "I'm legally okay to contribute
|
||||||
|
this and happy for it to go into QEMU", modeled after the `Linux kernel
|
||||||
|
<http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n297>`__
|
||||||
|
policy.) ``git commit -s`` or ``git format-patch -s`` will add one.
|
||||||
|
- All contributions to QEMU must be **sent as patches** to the
|
||||||
|
qemu-devel `mailing list <MailingLists>`__. Patch contributions
|
||||||
|
should not be posted on the bug tracker, posted on forums, or
|
||||||
|
externally hosted and linked to. (We have other mailing lists too,
|
||||||
|
but all patches must go to qemu-devel, possibly with a Cc: to another
|
||||||
|
list.) ``git send-email`` works best for delivering the patch without
|
||||||
|
mangling it (`hints for setting it
|
||||||
|
up <http://lxr.free-electrons.com/source/Documentation/process/email-clients.rst>`__),
|
||||||
|
but attachments can be used as a last resort on a first-time
|
||||||
|
submission.
|
||||||
|
- You must read replies to your message, and be willing to act on them.
|
||||||
|
Note, however, that maintainers are often willing to manually fix up
|
||||||
|
first-time contributions, since there is a learning curve involved in
|
||||||
|
making an ideal patch submission.
|
||||||
|
|
||||||
|
You do not have to subscribe to post (list policy is to reply-to-all to
|
||||||
|
preserve CCs and keep non-subscribers in the loop on the threads they
|
||||||
|
start), although you may find it easier as a subscriber to pick up good
|
||||||
|
ideas from other posts. If you do subscribe, be prepared for a high
|
||||||
|
volume of email, often over one thousand messages in a week. The list is
|
||||||
|
moderated; first-time posts from an email address (whether or not you
|
||||||
|
subscribed) may be subject to some delay while waiting for a moderator
|
||||||
|
to whitelist your address.
|
||||||
|
|
||||||
|
The larger your contribution is, or if you plan on becoming a long-term
|
||||||
|
contributor, then the more important the rest of this page becomes.
|
||||||
|
Reading the table of contents below should already give you an idea of
|
||||||
|
the basic requirements. Use the table of contents as a reference, and
|
||||||
|
read the parts that you have doubts about.
|
||||||
|
|
||||||
|
.. _writing_your_patches:
|
||||||
|
|
||||||
|
Writing your Patches
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. _use_the_qemu_coding_style:
|
||||||
|
|
||||||
|
Use the QEMU coding style
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
You can run run *scripts/checkpatch.pl <patchfile>* before submitting to
|
||||||
|
check that you are in compliance with our coding standards. Be aware
|
||||||
|
that ``checkpatch.pl`` is not infallible, though, especially where C
|
||||||
|
preprocessor macros are involved; use some common sense too. See also:
|
||||||
|
|
||||||
|
- `QEMU Coding Style
|
||||||
|
<https://qemu-project.gitlab.io/qemu/devel/style.html>`__
|
||||||
|
|
||||||
|
- `Automate a checkpatch run on
|
||||||
|
commit <http://blog.vmsplice.net/2011/03/how-to-automatically-run-checkpatchpl.html>`__
|
||||||
|
|
||||||
|
.. _base_patches_against_current_git_master:
|
||||||
|
|
||||||
|
Base patches against current git master
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There's no point submitting a patch which is based on a released version
|
||||||
|
of QEMU because development will have moved on from then and it probably
|
||||||
|
won't even apply to master. We only apply selected bugfixes to release
|
||||||
|
branches and then only as backports once the code has gone into master.
|
||||||
|
|
||||||
|
.. _split_up_long_patches:
|
||||||
|
|
||||||
|
Split up long patches
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Split up longer patches into a patch series of logical code changes.
|
||||||
|
Each change should compile and execute successfully. For instance, don't
|
||||||
|
add a file to the makefile in patch one and then add the file itself in
|
||||||
|
patch two. (This rule is here so that people can later use tools like
|
||||||
|
`git bisect <http://git-scm.com/docs/git-bisect>`__ without hitting
|
||||||
|
points in the commit history where QEMU doesn't work for reasons
|
||||||
|
unrelated to the bug they're chasing.) Put documentation first, not
|
||||||
|
last, so that someone reading the series can do a clean-room evaluation
|
||||||
|
of the documentation, then validate that the code matched the
|
||||||
|
documentation. A commit message that mentions "Also, ..." is often a
|
||||||
|
good candidate for splitting into multiple patches. For more thoughts on
|
||||||
|
properly splitting patches and writing good commit messages, see `this
|
||||||
|
advice from
|
||||||
|
OpenStack <https://wiki.openstack.org/wiki/GitCommitMessages>`__.
|
||||||
|
|
||||||
|
.. _make_code_motion_patches_easy_to_review:
|
||||||
|
|
||||||
|
Make code motion patches easy to review
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If a series requires large blocks of code motion, there are tricks for
|
||||||
|
making the refactoring easier to review. Split up the series so that
|
||||||
|
semantic changes (or even function renames) are done in a separate patch
|
||||||
|
from the raw code motion. Use a one-time setup of
|
||||||
|
``git config diff.renames true; git config diff.algorithm patience``
|
||||||
|
(Refer to `git-config <http://git-scm.com/docs/git-config>`__.) The
|
||||||
|
``diff.renames`` property ensures file rename patches will be given in a
|
||||||
|
more compact representation that focuses only on the differences across
|
||||||
|
the file rename, instead of showing the entire old file as a deletion
|
||||||
|
and the new file as an insertion. Meanwhile, the 'diff.algorithm'
|
||||||
|
property ensures that extracting a non-contiguous subset of one file
|
||||||
|
into a new file, but where all extracted parts occur in the same order
|
||||||
|
both before and after the patch, will reduce churn in trying to treat
|
||||||
|
unrelated ``}`` lines in the original file as separating hunks of
|
||||||
|
changes.
|
||||||
|
|
||||||
|
Ideally, a code motion patch can be reviewed by doing::
|
||||||
|
|
||||||
|
git format-patch --stdout -1 > patch;
|
||||||
|
diff -u <(sed -n 's/^-//p' patch) <(sed -n 's/^\+//p' patch)
|
||||||
|
|
||||||
|
to focus on the few changes that weren't wholesale code motion.
|
||||||
|
|
||||||
|
.. _dont_include_irrelevant_changes:
|
||||||
|
|
||||||
|
Don't include irrelevant changes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
In particular, don't include formatting, coding style or whitespace
|
||||||
|
changes to bits of code that would otherwise not be touched by the
|
||||||
|
patch. (It's OK to fix coding style issues in the immediate area (few
|
||||||
|
lines) of the lines you're changing.) If you think a section of code
|
||||||
|
really does need a reindent or other large-scale style fix, submit this
|
||||||
|
as a separate patch which makes no semantic changes; don't put it in the
|
||||||
|
same patch as your bug fix.
|
||||||
|
|
||||||
|
For smaller patches in less frequently changed areas of QEMU, consider
|
||||||
|
using the `trivial patches process
|
||||||
|
<https://qemu-project.gitlab.io/qemu/devel/style.html>`__.
|
||||||
|
|
||||||
|
.. _write_a_meaningful_commit_message:
|
||||||
|
|
||||||
|
Write a meaningful commit message
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Commit messages should be meaningful and should stand on their own as a
|
||||||
|
historical record of why the changes you applied were necessary or
|
||||||
|
useful.
|
||||||
|
|
||||||
|
QEMU follows the usual standard for git commit messages: the first line
|
||||||
|
(which becomes the email subject line) is "subsystem: single line
|
||||||
|
summary of change". Whether the "single line summary of change" starts
|
||||||
|
with a capital is a matter of taste, but we prefer that the summary does
|
||||||
|
not end in ".". Look at ``git shortlog -30`` for an idea of sample
|
||||||
|
subject lines. Then there is a blank line and a more detailed
|
||||||
|
description of the patch, another blank and your Signed-off-by: line.
|
||||||
|
Please do not use lines that are longer than 76 characters in your
|
||||||
|
commit message (so that the text still shows up nicely with "git show"
|
||||||
|
in a 80-columns terminal window).
|
||||||
|
|
||||||
|
The body of the commit message is a good place to document why your
|
||||||
|
change is important. Don't include comments like "This is a suggestion
|
||||||
|
for fixing this bug" (they can go below the ``---`` line in the email so
|
||||||
|
they don't go into the final commit message). Make sure the body of the
|
||||||
|
commit message can be read in isolation even if the reader's mailer
|
||||||
|
displays the subject line some distance apart (that is, a body that
|
||||||
|
starts with "... so that" as a continuation of the subject line is
|
||||||
|
harder to follow).
|
||||||
|
|
||||||
|
.. _submitting_your_patches:
|
||||||
|
|
||||||
|
Submitting your Patches
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. _cc_the_relevant_maintainer:
|
||||||
|
|
||||||
|
CC the relevant maintainer
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Send patches both to the mailing list and CC the maintainer(s) of the
|
||||||
|
files you are modifying. look in the MAINTAINERS file to find out who
|
||||||
|
that is. Also try using scripts/get_maintainer.pl from the repository
|
||||||
|
for learning the most common committers for the files you touched.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
~/src/qemu/scripts/get_maintainer.pl -f hw/ide/core.c
|
||||||
|
|
||||||
|
In fact, you can automate this, via a one-time setup of ``git config
|
||||||
|
sendemail.cccmd 'scripts/get_maintainer.pl --nogit-fallback'`` (Refer to
|
||||||
|
`git-config <http://git-scm.com/docs/git-config>`__.)
|
||||||
|
|
||||||
|
.. _do_not_send_as_an_attachment:
|
||||||
|
|
||||||
|
Do not send as an attachment
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Send patches inline so they are easy to reply to with review comments.
|
||||||
|
Do not put patches in attachments.
|
||||||
|
|
||||||
|
.. _use_git_format_patch:
|
||||||
|
|
||||||
|
Use ``git format-patch``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Use the right diff format.
|
||||||
|
`git format-patch <http://git-scm.com/docs/git-format-patch>`__ will
|
||||||
|
produce patch emails in the right format (check the documentation to
|
||||||
|
find out how to drive it). You can then edit the cover letter before
|
||||||
|
using ``git send-email`` to mail the files to the mailing list. (We
|
||||||
|
recommend `git send-email <http://git-scm.com/docs/git-send-email>`__
|
||||||
|
because mail clients often mangle patches by wrapping long lines or
|
||||||
|
messing up whitespace. Some distributions do not include send-email in a
|
||||||
|
default install of git; you may need to download additional packages,
|
||||||
|
such as 'git-email' on Fedora-based systems.) Patch series need a cover
|
||||||
|
letter, with shallow threading (all patches in the series are
|
||||||
|
in-reply-to the cover letter, but not to each other); single unrelated
|
||||||
|
patches do not need a cover letter (but if you do send a cover letter,
|
||||||
|
use --numbered so the cover and the patch have distinct subject lines).
|
||||||
|
Patches are easier to find if they start a new top-level thread, rather
|
||||||
|
than being buried in-reply-to another existing thread.
|
||||||
|
|
||||||
|
.. _patch_emails_must_include_a_signed_off_by_line:
|
||||||
|
|
||||||
|
Patch emails must include a ``Signed-off-by:`` line
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For more information see `1.12) Sign your work
|
||||||
|
<http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=f6f94e2ab1b33f0082ac22d71f66385a60d8157f#n296>`__.
|
||||||
|
This is vital or we will not be able to apply your patch! Please use
|
||||||
|
your real name to sign a patch (not an alias or acronym).
|
||||||
|
|
||||||
|
If you wrote the patch, make sure your "From:" and "Signed-off-by:"
|
||||||
|
lines use the same spelling. It's okay if you subscribe or contribute to
|
||||||
|
the list via more than one address, but using multiple addresses in one
|
||||||
|
commit just confuses things. If someone else wrote the patch, git will
|
||||||
|
include a "From:" line in the body of the email (different from your
|
||||||
|
envelope From:) that will give credit to the correct author; but again,
|
||||||
|
that author's Signed-off-by: line is mandatory, with the same spelling.
|
||||||
|
|
||||||
|
.. _include_a_meaningful_cover_letter:
|
||||||
|
|
||||||
|
Include a meaningful cover letter
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This usually applies only to a series that includes multiple patches;
|
||||||
|
the cover letter explains the overall goal of such a series.
|
||||||
|
|
||||||
|
When reviewers don't know your goal at the start of their review, they
|
||||||
|
may object to early changes that don't make sense until the end of the
|
||||||
|
series, because they do not have enough context yet at that point of
|
||||||
|
their review. A series where the goal is unclear also risks a higher
|
||||||
|
number of review-fix cycles because the reviewers haven't bought into
|
||||||
|
the idea yet. If the cover letter can explain these points to the
|
||||||
|
reviewer, the process will be smoother patches will get merged faster.
|
||||||
|
Make sure your cover letter includes a diffstat of changes made over the
|
||||||
|
entire series; potential reviewers know what files they are interested
|
||||||
|
in, and they need an easy way determine if your series touches them.
|
||||||
|
|
||||||
|
.. _use_the_rfc_tag_if_needed:
|
||||||
|
|
||||||
|
Use the RFC tag if needed
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For example, "[PATCH RFC v2]". ``git format-patch --subject-prefix=RFC``
|
||||||
|
can help.
|
||||||
|
|
||||||
|
"RFC" means "Request For Comments" and is a statement that you don't
|
||||||
|
intend for your patchset to be applied to master, but would like some
|
||||||
|
review on it anyway. Reasons for doing this include:
|
||||||
|
|
||||||
|
- the patch depends on some pending kernel changes which haven't yet
|
||||||
|
been accepted, so the QEMU patch series is blocked until that
|
||||||
|
dependency has been dealt with, but is worth reviewing anyway
|
||||||
|
- the patch set is not finished yet (perhaps it doesn't cover all use
|
||||||
|
cases or work with all targets) but you want early review of a major
|
||||||
|
API change or design structure before continuing
|
||||||
|
|
||||||
|
In general, since it's asking other people to do review work on a
|
||||||
|
patchset that the submitter themselves is saying shouldn't be applied,
|
||||||
|
it's best to:
|
||||||
|
|
||||||
|
- use it sparingly
|
||||||
|
- in the cover letter, be clear about why a patch is an RFC, what areas
|
||||||
|
of the patchset you're looking for review on, and why reviewers
|
||||||
|
should care
|
||||||
|
|
||||||
|
.. _participating_in_code_review:
|
||||||
|
|
||||||
|
Participating in Code Review
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
All patches submitted to the QEMU project go through a code review
|
||||||
|
process before they are accepted. Some areas of code that are well
|
||||||
|
maintained may review patches quickly, lesser-loved areas of code may
|
||||||
|
have a longer delay.
|
||||||
|
|
||||||
|
.. _stay_around_to_fix_problems_raised_in_code_review:
|
||||||
|
|
||||||
|
Stay around to fix problems raised in code review
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Not many patches get into QEMU straight away -- it is quite common that
|
||||||
|
developers will identify bugs, or suggest a cleaner approach, or even
|
||||||
|
just point out code style issues or commit message typos. You'll need to
|
||||||
|
respond to these, and then send a second version of your patches with
|
||||||
|
the issues fixed. This takes a little time and effort on your part, but
|
||||||
|
if you don't do it then your changes will never get into QEMU. It's also
|
||||||
|
just polite -- it is quite disheartening for a developer to spend time
|
||||||
|
reviewing your code and suggesting improvements, only to find that
|
||||||
|
you're not going to do anything further and it was all wasted effort.
|
||||||
|
|
||||||
|
When replying to comments on your patches **reply to all and not just
|
||||||
|
the sender** -- keeping discussion on the mailing list means everybody
|
||||||
|
can follow it.
|
||||||
|
|
||||||
|
.. _pay_attention_to_review_comments:
|
||||||
|
|
||||||
|
Pay attention to review comments
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Someone took their time to review your work, and it pays to respect that
|
||||||
|
effort; repeatedly submitting a series without addressing all comments
|
||||||
|
from the previous round tends to alienate reviewers and stall your
|
||||||
|
patch. Reviewers aren't always perfect, so it is okay if you want to
|
||||||
|
argue that your code was correct in the first place instead of blindly
|
||||||
|
doing everything the reviewer asked. On the other hand, if someone
|
||||||
|
pointed out a potential issue during review, then even if your code
|
||||||
|
turns out to be correct, it's probably a sign that you should improve
|
||||||
|
your commit message and/or comments in the code explaining why the code
|
||||||
|
is correct.
|
||||||
|
|
||||||
|
If you fix issues that are raised during review **resend the entire
|
||||||
|
patch series** not just the one patch that was changed. This allows
|
||||||
|
maintainers to easily apply the fixed series without having to manually
|
||||||
|
identify which patches are relevant. Send the new version as a complete
|
||||||
|
fresh email or series of emails -- don't try to make it a followup to
|
||||||
|
version 1. (This helps automatic patch email handling tools distinguish
|
||||||
|
between v1 and v2 emails.)
|
||||||
|
|
||||||
|
.. _when_resending_patches_add_a_version_tag:
|
||||||
|
|
||||||
|
When resending patches add a version tag
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
All patches beyond the first version should include a version tag -- for
|
||||||
|
example, "[PATCH v2]". This means people can easily identify whether
|
||||||
|
they're looking at the most recent version. (The first version of a
|
||||||
|
patch need not say "v1", just [PATCH] is sufficient.) For patch series,
|
||||||
|
the version applies to the whole series -- even if you only change one
|
||||||
|
patch, you resend the entire series and mark it as "v2". Don't try to
|
||||||
|
track versions of different patches in the series separately. `git
|
||||||
|
format-patch <http://git-scm.com/docs/git-format-patch>`__ and `git
|
||||||
|
send-email <http://git-scm.com/docs/git-send-email>`__ both understand
|
||||||
|
the ``-v2`` option to make this easier. Send each new revision as a new
|
||||||
|
top-level thread, rather than burying it in-reply-to an earlier
|
||||||
|
revision, as many reviewers are not looking inside deep threads for new
|
||||||
|
patches.
|
||||||
|
|
||||||
|
.. _include_version_history_in_patchset_revisions:
|
||||||
|
|
||||||
|
Include version history in patchset revisions
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For later versions of patches, include a summary of changes from
|
||||||
|
previous versions, but not in the commit message itself. In an email
|
||||||
|
formatted as a git patch, the commit message is the part above the "---"
|
||||||
|
line, and this will go into the git changelog when the patch is
|
||||||
|
committed. This part should be a self-contained description of what this
|
||||||
|
version of the patch does, written to make sense to anybody who comes
|
||||||
|
back to look at this commit in git in six months' time. The part below
|
||||||
|
the "---" line and above the patch proper (git format-patch puts the
|
||||||
|
diffstat here) is a good place to put remarks for people reading the
|
||||||
|
patch email, and this is where the "changes since previous version"
|
||||||
|
summary belongs. The
|
||||||
|
`git-publish <https://github.com/stefanha/git-publish>`__ script can
|
||||||
|
help with tracking a good summary across versions. Also, the
|
||||||
|
`git-backport-diff <https://github.com/codyprime/git-scripts>`__ script
|
||||||
|
can help focus reviewers on what changed between revisions.
|
||||||
|
|
||||||
|
.. _tips_and_tricks:
|
||||||
|
|
||||||
|
Tips and Tricks
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. _proper_use_of_reviewed_by_tags_can_aid_review:
|
||||||
|
|
||||||
|
Proper use of Reviewed-by: tags can aid review
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When reviewing a large series, a reviewer can reply to some of the
|
||||||
|
patches with a Reviewed-by tag, stating that they are happy with that
|
||||||
|
patch in isolation (sometimes conditional on minor cleanup, like fixing
|
||||||
|
whitespace, that doesn't affect code content). You should then update
|
||||||
|
those commit messages by hand to include the Reviewed-by tag, so that in
|
||||||
|
the next revision, reviewers can spot which patches were already clean
|
||||||
|
from the previous round. Conversely, if you significantly modify a patch
|
||||||
|
that was previously reviewed, remove the reviewed-by tag out of the
|
||||||
|
commit message, as well as listing the changes from the previous
|
||||||
|
version, to make it easier to focus a reviewer's attention to your
|
||||||
|
changes.
|
||||||
|
|
||||||
|
.. _if_your_patch_seems_to_have_been_ignored:
|
||||||
|
|
||||||
|
If your patch seems to have been ignored
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If your patchset has received no replies you should "ping" it after a
|
||||||
|
week or two, by sending an email as a reply-to-all to the patch mail,
|
||||||
|
including the word "ping" and ideally also a link to the page for the
|
||||||
|
patch on
|
||||||
|
`patchwork <http://patchwork.ozlabs.org/project/qemu-devel/list/>`__ or
|
||||||
|
GMANE. It's worth double-checking for reasons why your patch might have
|
||||||
|
been ignored (forgot to CC the maintainer? annoyed people by failing to
|
||||||
|
respond to review comments on an earlier version?), but often for
|
||||||
|
less-maintained areas of QEMU patches do just slip through the cracks.
|
||||||
|
If your ping is also ignored, ping again after another week or so. As
|
||||||
|
the submitter, you are the person with the most motivation to get your
|
||||||
|
patch applied, so you have to be persistent.
|
||||||
|
|
||||||
|
.. _is_my_patch_in:
|
||||||
|
|
||||||
|
Is my patch in?
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Once your patch has had enough review on list, the maintainer for that
|
||||||
|
area of code will send notification to the list that they are including
|
||||||
|
your patch in a particular staging branch. Periodically, the maintainer
|
||||||
|
then sends a `pull request
|
||||||
|
<https://qemu-project.gitlab.io/qemu/devel/submitting-a-pull-request.html>`__
|
||||||
|
for aggregating topic branches into mainline qemu. Generally, you do not
|
||||||
|
need to send a pull request unless you have contributed enough patches
|
||||||
|
to become a maintainer over a particular section of code. Maintainers
|
||||||
|
may further modify your commit, by resolving simple merge conflicts or
|
||||||
|
fixing minor typos pointed out during review, but will always add a
|
||||||
|
Signed-off-by line in addition to yours, indicating that it went through
|
||||||
|
their tree. Occasionally, the maintainer's pull request may hit more
|
||||||
|
difficult merge conflicts, where you may be requested to help rebase and
|
||||||
|
resolve the problems. It may take a couple of weeks between when your
|
||||||
|
patch first had a positive review to when it finally lands in qemu.git;
|
||||||
|
release cycle freezes may extend that time even longer.
|
||||||
|
|
||||||
|
.. _return_the_favor:
|
||||||
|
|
||||||
|
Return the favor
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Peer review only works if everyone chips in a bit of review time. If
|
||||||
|
everyone submitted more patches than they reviewed, we would have a
|
||||||
|
patch backlog. A good goal is to try to review at least as many patches
|
||||||
|
from others as what you submit. Don't worry if you don't know the code
|
||||||
|
base as well as a maintainer; it's perfectly fine to admit when your
|
||||||
|
review is weak because you are unfamiliar with the code.
|
76
docs/devel/submitting-a-pull-request.rst
Normal file
76
docs/devel/submitting-a-pull-request.rst
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
Submit a Pull Request
|
||||||
|
=====================
|
||||||
|
|
||||||
|
QEMU welcomes contributions of code, but we generally expect these to be
|
||||||
|
sent as simple patch emails to the mailing list (see our page on
|
||||||
|
`submitting a patch
|
||||||
|
<https://qemu-project.gitlab.io/qemu/devel/submitting-a-patch.html>`__
|
||||||
|
for more details). Generally only existing submaintainers of a tree
|
||||||
|
will need to submit pull requests, although occasionally for a large
|
||||||
|
patch series we might ask a submitter to send a pull request. This page
|
||||||
|
documents our recommendations on pull requests for those people.
|
||||||
|
|
||||||
|
A good rule of thumb is not to send a pull request unless somebody asks
|
||||||
|
you to.
|
||||||
|
|
||||||
|
**Resend the patches with the pull request** as emails which are
|
||||||
|
threaded as follow-ups to the pull request itself. The simplest way to
|
||||||
|
do this is to use ``git format-patch --cover-letter`` to create the
|
||||||
|
emails, and then edit the cover letter to include the pull request
|
||||||
|
details that ``git request-pull`` outputs.
|
||||||
|
|
||||||
|
**Use PULL as the subject line tag** in both the cover letter and the
|
||||||
|
retransmitted patch mails (for example, by using
|
||||||
|
``--subject-prefix=PULL`` in your ``git format-patch`` command). This
|
||||||
|
helps people to filter in or out the resulting emails (especially useful
|
||||||
|
if they are only CC'd on one email out of the set).
|
||||||
|
|
||||||
|
**Each patch must have your own Signed-off-by: line** as well as that of
|
||||||
|
the original author if the patch was not written by you. This is because
|
||||||
|
with a pull request you're now indicating that the patch has passed via
|
||||||
|
you rather than directly from the original author.
|
||||||
|
|
||||||
|
**Don't forget to add Reviewed-by: and Acked-by: lines**. When other
|
||||||
|
people have reviewed the patches you're putting in the pull request,
|
||||||
|
make sure you've copied their signoffs across. (If you use the `patches
|
||||||
|
tool <https://github.com/stefanha/patches>`__ to add patches from email
|
||||||
|
directly to your git repo it will include the tags automatically; if
|
||||||
|
you're updating patches manually or in some other way you'll need to
|
||||||
|
edit the commit messages by hand.)
|
||||||
|
|
||||||
|
**Don't send pull requests for code that hasn't passed review**. A pull
|
||||||
|
request says these patches are ready to go into QEMU now, so they must
|
||||||
|
have passed the standard code review processes. In particular if you've
|
||||||
|
corrected issues in one round of code review, you need to send your
|
||||||
|
fixed patch series as normal to the list; you can't put it in a pull
|
||||||
|
request until it's gone through. (Extremely trivial fixes may be OK to
|
||||||
|
just fix in passing, but if in doubt err on the side of not.)
|
||||||
|
|
||||||
|
**Test before sending**. This is an obvious thing to say, but make sure
|
||||||
|
everything builds (including that it compiles at each step of the patch
|
||||||
|
series) and that "make check" passes before sending out the pull
|
||||||
|
request. As a submaintainer you're one of QEMU's lines of defense
|
||||||
|
against bad code, so double check the details.
|
||||||
|
|
||||||
|
**All pull requests must be signed**. If your key is not already signed
|
||||||
|
by members of the QEMU community, you should make arrangements to attend
|
||||||
|
a `KeySigningParty <https://wiki.qemu.org/KeySigningParty>`__ (for
|
||||||
|
example at KVM Forum) or make alternative arrangements to have your key
|
||||||
|
signed by an attendee. Key signing requires meeting another community
|
||||||
|
member \*in person\* so please make appropriate arrangements. By
|
||||||
|
"signed" here we mean that the pullreq email should quote a tag which is
|
||||||
|
a GPG-signed tag (as created with 'gpg tag -s ...').
|
||||||
|
|
||||||
|
**Pull requests not for master should say "not for master" and have
|
||||||
|
"PULL SUBSYSTEM whatever" in the subject tag**. If your pull request is
|
||||||
|
targeting a stable branch or some submaintainer tree, please include the
|
||||||
|
string "not for master" in the cover letter email, and make sure the
|
||||||
|
subject tag is "PULL SUBSYSTEM s390/block/whatever" rather than just
|
||||||
|
"PULL". This allows it to be automatically filtered out of the set of
|
||||||
|
pull requests that should be applied to master.
|
||||||
|
|
||||||
|
You might be interested in the `make-pullreq
|
||||||
|
<https://git.linaro.org/people/peter.maydell/misc-scripts.git/tree/make-pullreq>`__
|
||||||
|
script which automates some of this process for you and includes a few
|
||||||
|
sanity checks. Note that you must edit it to configure it suitably for
|
||||||
|
your local situation!
|
50
docs/devel/trivial-patches.rst
Normal file
50
docs/devel/trivial-patches.rst
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
Trivial Patches
|
||||||
|
===============
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
Trivial patches that change just a few lines of code sometimes languish
|
||||||
|
on the mailing list even though they require only a small amount of
|
||||||
|
review. This is often the case for patches that do not fall under an
|
||||||
|
actively maintained subsystem and therefore fall through the cracks.
|
||||||
|
|
||||||
|
The trivial patches team take on the task of reviewing and building pull
|
||||||
|
requests for patches that:
|
||||||
|
|
||||||
|
- Do not fall under an actively maintained subsystem.
|
||||||
|
- Are single patches or short series (max 2-4 patches).
|
||||||
|
- Only touch a few lines of code.
|
||||||
|
|
||||||
|
**You should hint that your patch is a candidate by CCing
|
||||||
|
qemu-trivial@nongnu.org.**
|
||||||
|
|
||||||
|
Repositories
|
||||||
|
------------
|
||||||
|
|
||||||
|
Since the trivial patch team rotates maintainership there is only one
|
||||||
|
active repository at a time:
|
||||||
|
|
||||||
|
- git://github.com/vivier/qemu.git trivial-patches - `browse <https://github.com/vivier/qemu/tree/trivial-patches>`__
|
||||||
|
|
||||||
|
Workflow
|
||||||
|
--------
|
||||||
|
|
||||||
|
The trivial patches team rotates the duty of collecting trivial patches
|
||||||
|
amongst its members. A team member's job is to:
|
||||||
|
|
||||||
|
1. Identify trivial patches on the development mailing list.
|
||||||
|
2. Review trivial patches, merge them into a git tree, and reply to state
|
||||||
|
that the patch is queued.
|
||||||
|
3. Send pull requests to the development mailing list once a week.
|
||||||
|
|
||||||
|
A single team member can be on duty as long as they like. The suggested
|
||||||
|
time is 1 week before handing off to the next member.
|
||||||
|
|
||||||
|
Team
|
||||||
|
----
|
||||||
|
|
||||||
|
If you would like to join the trivial patches team, contact Laurent
|
||||||
|
Vivier. The current team includes:
|
||||||
|
|
||||||
|
- `Laurent Vivier <mailto:laurent@vivier.eu>`__
|
@ -110,28 +110,32 @@ multipath I/O.
|
|||||||
This will create an NVM subsystem with two controllers. Having controllers
|
This will create an NVM subsystem with two controllers. Having controllers
|
||||||
linked to an ``nvme-subsys`` device allows additional ``nvme-ns`` parameters:
|
linked to an ``nvme-subsys`` device allows additional ``nvme-ns`` parameters:
|
||||||
|
|
||||||
``shared`` (default: ``off``)
|
``shared`` (default: ``on`` since 6.2)
|
||||||
Specifies that the namespace will be attached to all controllers in the
|
Specifies that the namespace will be attached to all controllers in the
|
||||||
subsystem. If set to ``off`` (the default), the namespace will remain a
|
subsystem. If set to ``off``, the namespace will remain a private namespace
|
||||||
private namespace and may only be attached to a single controller at a time.
|
and may only be attached to a single controller at a time. Shared namespaces
|
||||||
|
are always automatically attached to all controllers (also when controllers
|
||||||
|
are hotplugged).
|
||||||
|
|
||||||
``detached`` (default: ``off``)
|
``detached`` (default: ``off``)
|
||||||
If set to ``on``, the namespace will be be available in the subsystem, but
|
If set to ``on``, the namespace will be be available in the subsystem, but
|
||||||
not attached to any controllers initially.
|
not attached to any controllers initially. A shared namespace with this set
|
||||||
|
to ``on`` will never be automatically attached to controllers.
|
||||||
|
|
||||||
Thus, adding
|
Thus, adding
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
-drive file=nvm-1.img,if=none,id=nvm-1
|
-drive file=nvm-1.img,if=none,id=nvm-1
|
||||||
-device nvme-ns,drive=nvm-1,nsid=1,shared=on
|
-device nvme-ns,drive=nvm-1,nsid=1
|
||||||
-drive file=nvm-2.img,if=none,id=nvm-2
|
-drive file=nvm-2.img,if=none,id=nvm-2
|
||||||
-device nvme-ns,drive=nvm-2,nsid=3,detached=on
|
-device nvme-ns,drive=nvm-2,nsid=3,shared=off,detached=on
|
||||||
|
|
||||||
will cause NSID 1 will be a shared namespace (due to ``shared=on``) that is
|
will cause NSID 1 will be a shared namespace that is initially attached to both
|
||||||
initially attached to both controllers. NSID 3 will be a private namespace
|
controllers. NSID 3 will be a private namespace due to ``shared=off`` and only
|
||||||
(i.e. only attachable to a single controller at a time) and will not be
|
attachable to a single controller at a time. Additionally it will not be
|
||||||
attached to any controller initially (due to ``detached=on``).
|
attached to any controller initially (due to ``detached=on``) or to hotplugged
|
||||||
|
controllers.
|
||||||
|
|
||||||
Optional Features
|
Optional Features
|
||||||
=================
|
=================
|
||||||
|
@ -419,6 +419,20 @@ static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
|
|||||||
s->pm.use_acpi_hotplug_bridge = value;
|
s->pm.use_acpi_hotplug_bridge = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
|
return s->pm.keep_pci_slot_hpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ich9_pm_set_keep_pci_slot_hpc(Object *obj, bool value, Error **errp)
|
||||||
|
{
|
||||||
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
|
s->pm.keep_pci_slot_hpc = value;
|
||||||
|
}
|
||||||
|
|
||||||
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
||||||
{
|
{
|
||||||
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
||||||
@ -428,6 +442,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
|||||||
pm->disable_s4 = 0;
|
pm->disable_s4 = 0;
|
||||||
pm->s4_val = 2;
|
pm->s4_val = 2;
|
||||||
pm->use_acpi_hotplug_bridge = true;
|
pm->use_acpi_hotplug_bridge = true;
|
||||||
|
pm->keep_pci_slot_hpc = true;
|
||||||
|
|
||||||
object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
|
object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
|
||||||
&pm->pm_io_base, OBJ_PROP_FLAG_READ);
|
&pm->pm_io_base, OBJ_PROP_FLAG_READ);
|
||||||
@ -454,6 +469,9 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
|||||||
object_property_add_bool(obj, ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
|
object_property_add_bool(obj, ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
|
||||||
ich9_pm_get_acpi_pci_hotplug,
|
ich9_pm_get_acpi_pci_hotplug,
|
||||||
ich9_pm_set_acpi_pci_hotplug);
|
ich9_pm_set_acpi_pci_hotplug);
|
||||||
|
object_property_add_bool(obj, "x-keep-pci-slot-hpc",
|
||||||
|
ich9_pm_get_keep_pci_slot_hpc,
|
||||||
|
ich9_pm_set_keep_pci_slot_hpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
GlobalProperty hw_compat_6_1[] = {
|
GlobalProperty hw_compat_6_1[] = {
|
||||||
{ "vhost-user-vsock-device", "seqpacket", "off" },
|
{ "vhost-user-vsock-device", "seqpacket", "off" },
|
||||||
|
{ "nvme-ns", "shared", "off" },
|
||||||
};
|
};
|
||||||
const size_t hw_compat_6_1_len = G_N_ELEMENTS(hw_compat_6_1);
|
const size_t hw_compat_6_1_len = G_N_ELEMENTS(hw_compat_6_1);
|
||||||
|
|
||||||
|
@ -1337,7 +1337,7 @@ static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr)
|
|||||||
aml_append(table, scope);
|
aml_append(table, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Aml *build_q35_osc_method(void)
|
static Aml *build_q35_osc_method(bool enable_native_pcie_hotplug)
|
||||||
{
|
{
|
||||||
Aml *if_ctx;
|
Aml *if_ctx;
|
||||||
Aml *if_ctx2;
|
Aml *if_ctx2;
|
||||||
@ -1359,8 +1359,10 @@ static Aml *build_q35_osc_method(void)
|
|||||||
/*
|
/*
|
||||||
* Always allow native PME, AER (no dependencies)
|
* Always allow native PME, AER (no dependencies)
|
||||||
* Allow SHPC (PCI bridges can have SHPC controller)
|
* Allow SHPC (PCI bridges can have SHPC controller)
|
||||||
|
* Disable PCIe Native Hot-plug if ACPI PCI Hot-plug is enabled.
|
||||||
*/
|
*/
|
||||||
aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
|
aml_append(if_ctx, aml_and(a_ctrl,
|
||||||
|
aml_int(0x1E | (enable_native_pcie_hotplug ? 0x1 : 0x0)), a_ctrl));
|
||||||
|
|
||||||
if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
|
if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
|
||||||
/* Unknown revision */
|
/* Unknown revision */
|
||||||
@ -1449,7 +1451,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||||||
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
|
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
|
||||||
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
|
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
|
||||||
aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid)));
|
aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid)));
|
||||||
aml_append(dev, build_q35_osc_method());
|
aml_append(dev, build_q35_osc_method(!pm->pcihp_bridge_en));
|
||||||
aml_append(sb_scope, dev);
|
aml_append(sb_scope, dev);
|
||||||
if (mcfg_valid) {
|
if (mcfg_valid) {
|
||||||
aml_append(sb_scope, build_q35_dram_controller(&mcfg));
|
aml_append(sb_scope, build_q35_dram_controller(&mcfg));
|
||||||
@ -1565,7 +1567,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||||||
if (pci_bus_is_express(bus)) {
|
if (pci_bus_is_express(bus)) {
|
||||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
|
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
|
||||||
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
|
aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
|
||||||
aml_append(dev, build_q35_osc_method());
|
|
||||||
|
/* Expander bridges do not have ACPI PCI Hot-plug enabled */
|
||||||
|
aml_append(dev, build_q35_osc_method(true));
|
||||||
} else {
|
} else {
|
||||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
|
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ GlobalProperty pc_compat_6_1[] = {
|
|||||||
{ TYPE_X86_CPU, "hv-version-id-build", "0x1bbc" },
|
{ TYPE_X86_CPU, "hv-version-id-build", "0x1bbc" },
|
||||||
{ TYPE_X86_CPU, "hv-version-id-major", "0x0006" },
|
{ TYPE_X86_CPU, "hv-version-id-major", "0x0006" },
|
||||||
{ TYPE_X86_CPU, "hv-version-id-minor", "0x0001" },
|
{ TYPE_X86_CPU, "hv-version-id-minor", "0x0001" },
|
||||||
|
{ "ICH9-LPC", "x-keep-pci-slot-hpc", "false" },
|
||||||
};
|
};
|
||||||
const size_t pc_compat_6_1_len = G_N_ELEMENTS(pc_compat_6_1);
|
const size_t pc_compat_6_1_len = G_N_ELEMENTS(pc_compat_6_1);
|
||||||
|
|
||||||
@ -107,6 +108,7 @@ GlobalProperty pc_compat_6_0[] = {
|
|||||||
{ "qemu64" "-" TYPE_X86_CPU, "stepping", "3" },
|
{ "qemu64" "-" TYPE_X86_CPU, "stepping", "3" },
|
||||||
{ TYPE_X86_CPU, "x-vendor-cpuid-only", "off" },
|
{ TYPE_X86_CPU, "x-vendor-cpuid-only", "off" },
|
||||||
{ "ICH9-LPC", ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, "off" },
|
{ "ICH9-LPC", ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, "off" },
|
||||||
|
{ "ICH9-LPC", "x-keep-pci-slot-hpc", "true" },
|
||||||
};
|
};
|
||||||
const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0);
|
const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0);
|
||||||
|
|
||||||
|
@ -137,6 +137,7 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
DriveInfo *hd[MAX_SATA_PORTS];
|
DriveInfo *hd[MAX_SATA_PORTS];
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
bool acpi_pcihp;
|
bool acpi_pcihp;
|
||||||
|
bool keep_pci_slot_hpc;
|
||||||
|
|
||||||
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
|
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
|
||||||
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
|
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
|
||||||
@ -242,8 +243,12 @@ static void pc_q35_init(MachineState *machine)
|
|||||||
ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
|
ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (acpi_pcihp) {
|
keep_pci_slot_hpc = object_property_get_bool(OBJECT(lpc),
|
||||||
object_register_sugar_prop(TYPE_PCIE_SLOT, "native-hotplug",
|
"x-keep-pci-slot-hpc",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!keep_pci_slot_hpc && acpi_pcihp) {
|
||||||
|
object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug",
|
||||||
"false", true);
|
"false", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,17 +387,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->nb_redist_regions != 1) {
|
gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops);
|
||||||
error_setg(errp, "VGICv3 redist region number(%d) not equal to 1",
|
|
||||||
s->nb_redist_regions);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gicv3_init_cpuif(s);
|
gicv3_init_cpuif(s);
|
||||||
}
|
}
|
||||||
|
@ -250,21 +250,11 @@ static const VMStateDescription vmstate_gicv3 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
||||||
const MemoryRegionOps *ops, Error **errp)
|
const MemoryRegionOps *ops)
|
||||||
{
|
{
|
||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||||
int rdist_capacity = 0;
|
|
||||||
int i;
|
int i;
|
||||||
|
int cpuidx;
|
||||||
for (i = 0; i < s->nb_redist_regions; i++) {
|
|
||||||
rdist_capacity += s->redist_region_count[i];
|
|
||||||
}
|
|
||||||
if (rdist_capacity < s->num_cpu) {
|
|
||||||
error_setg(errp, "Capacity of the redist regions(%d) "
|
|
||||||
"is less than number of vcpus(%d)",
|
|
||||||
rdist_capacity, s->num_cpu);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
|
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
|
||||||
* GPIO array layout is thus:
|
* GPIO array layout is thus:
|
||||||
@ -293,14 +283,20 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
|||||||
"gicv3_dist", 0x10000);
|
"gicv3_dist", 0x10000);
|
||||||
sysbus_init_mmio(sbd, &s->iomem_dist);
|
sysbus_init_mmio(sbd, &s->iomem_dist);
|
||||||
|
|
||||||
s->iomem_redist = g_new0(MemoryRegion, s->nb_redist_regions);
|
s->redist_regions = g_new0(GICv3RedistRegion, s->nb_redist_regions);
|
||||||
|
cpuidx = 0;
|
||||||
for (i = 0; i < s->nb_redist_regions; i++) {
|
for (i = 0; i < s->nb_redist_regions; i++) {
|
||||||
char *name = g_strdup_printf("gicv3_redist_region[%d]", i);
|
char *name = g_strdup_printf("gicv3_redist_region[%d]", i);
|
||||||
|
GICv3RedistRegion *region = &s->redist_regions[i];
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem_redist[i], OBJECT(s),
|
region->gic = s;
|
||||||
ops ? &ops[1] : NULL, s, name,
|
region->cpuidx = cpuidx;
|
||||||
|
cpuidx += s->redist_region_count[i];
|
||||||
|
|
||||||
|
memory_region_init_io(®ion->iomem, OBJECT(s),
|
||||||
|
ops ? &ops[1] : NULL, region, name,
|
||||||
s->redist_region_count[i] * GICV3_REDIST_SIZE);
|
s->redist_region_count[i] * GICV3_REDIST_SIZE);
|
||||||
sysbus_init_mmio(sbd, &s->iomem_redist[i]);
|
sysbus_init_mmio(sbd, ®ion->iomem);
|
||||||
g_free(name);
|
g_free(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,7 +304,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
|||||||
static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
GICv3State *s = ARM_GICV3_COMMON(dev);
|
GICv3State *s = ARM_GICV3_COMMON(dev);
|
||||||
int i;
|
int i, rdist_capacity, cpuidx;
|
||||||
|
|
||||||
/* revision property is actually reserved and currently used only in order
|
/* revision property is actually reserved and currently used only in order
|
||||||
* to keep the interface compatible with GICv2 code, avoiding extra
|
* to keep the interface compatible with GICv2 code, avoiding extra
|
||||||
@ -350,12 +346,22 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rdist_capacity = 0;
|
||||||
|
for (i = 0; i < s->nb_redist_regions; i++) {
|
||||||
|
rdist_capacity += s->redist_region_count[i];
|
||||||
|
}
|
||||||
|
if (rdist_capacity < s->num_cpu) {
|
||||||
|
error_setg(errp, "Capacity of the redist regions(%d) "
|
||||||
|
"is less than number of vcpus(%d)",
|
||||||
|
rdist_capacity, s->num_cpu);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
|
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
|
||||||
|
|
||||||
for (i = 0; i < s->num_cpu; i++) {
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
CPUState *cpu = qemu_get_cpu(i);
|
CPUState *cpu = qemu_get_cpu(i);
|
||||||
uint64_t cpu_affid;
|
uint64_t cpu_affid;
|
||||||
int last;
|
|
||||||
|
|
||||||
s->cpu[i].cpu = cpu;
|
s->cpu[i].cpu = cpu;
|
||||||
s->cpu[i].gic = s;
|
s->cpu[i].gic = s;
|
||||||
@ -375,7 +381,6 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
|||||||
* PLPIS == 0 (physical LPIs not supported)
|
* PLPIS == 0 (physical LPIs not supported)
|
||||||
*/
|
*/
|
||||||
cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL);
|
cpu_affid = object_property_get_uint(OBJECT(cpu), "mp-affinity", NULL);
|
||||||
last = (i == s->num_cpu - 1);
|
|
||||||
|
|
||||||
/* The CPU mp-affinity property is in MPIDR register format; squash
|
/* The CPU mp-affinity property is in MPIDR register format; squash
|
||||||
* the affinity bytes into 32 bits as the GICR_TYPER has them.
|
* the affinity bytes into 32 bits as the GICR_TYPER has them.
|
||||||
@ -384,13 +389,22 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
|||||||
(cpu_affid & 0xFFFFFF);
|
(cpu_affid & 0xFFFFFF);
|
||||||
s->cpu[i].gicr_typer = (cpu_affid << 32) |
|
s->cpu[i].gicr_typer = (cpu_affid << 32) |
|
||||||
(1 << 24) |
|
(1 << 24) |
|
||||||
(i << 8) |
|
(i << 8);
|
||||||
(last << 4);
|
|
||||||
|
|
||||||
if (s->lpi_enable) {
|
if (s->lpi_enable) {
|
||||||
s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
|
s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now go through and set GICR_TYPER.Last for the final
|
||||||
|
* redistributor in each region.
|
||||||
|
*/
|
||||||
|
cpuidx = 0;
|
||||||
|
for (i = 0; i < s->nb_redist_regions; i++) {
|
||||||
|
cpuidx += s->redist_region_count[i];
|
||||||
|
s->cpu[cpuidx - 1].gicr_typer |= GICR_TYPER_LAST;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm_gicv3_finalize(Object *obj)
|
static void arm_gicv3_finalize(Object *obj)
|
||||||
|
@ -787,11 +787,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL, &local_err);
|
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
|
||||||
if (local_err) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < s->num_cpu; i++) {
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
|
ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
|
||||||
@ -829,7 +825,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||||||
KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd, 0);
|
KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd, 0);
|
||||||
|
|
||||||
if (!multiple_redist_region_allowed) {
|
if (!multiple_redist_region_allowed) {
|
||||||
kvm_arm_register_device(&s->iomem_redist[0], -1,
|
kvm_arm_register_device(&s->redist_regions[0].iomem, -1,
|
||||||
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd, 0);
|
KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -842,7 +838,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||||||
uint64_t addr_ormask =
|
uint64_t addr_ormask =
|
||||||
i | ((uint64_t)s->redist_region_count[i] << 52);
|
i | ((uint64_t)s->redist_region_count[i] << 52);
|
||||||
|
|
||||||
kvm_arm_register_device(&s->iomem_redist[i], -1,
|
kvm_arm_register_device(&s->redist_regions[i].iomem, -1,
|
||||||
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION,
|
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION,
|
||||||
s->dev_fd, addr_ormask);
|
s->dev_fd, addr_ormask);
|
||||||
|
@ -425,22 +425,24 @@ static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset,
|
|||||||
MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
|
MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
|
||||||
unsigned size, MemTxAttrs attrs)
|
unsigned size, MemTxAttrs attrs)
|
||||||
{
|
{
|
||||||
GICv3State *s = opaque;
|
GICv3RedistRegion *region = opaque;
|
||||||
|
GICv3State *s = region->gic;
|
||||||
GICv3CPUState *cs;
|
GICv3CPUState *cs;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
int cpuidx;
|
int cpuidx;
|
||||||
|
|
||||||
assert((offset & (size - 1)) == 0);
|
assert((offset & (size - 1)) == 0);
|
||||||
|
|
||||||
/* This region covers all the redistributor pages; there are
|
/*
|
||||||
* (for GICv3) two 64K pages per CPU. At the moment they are
|
* There are (for GICv3) two 64K redistributor pages per CPU.
|
||||||
* all contiguous (ie in this one region), though we might later
|
* In some cases the redistributor pages for all CPUs are not
|
||||||
* want to allow splitting of redistributor pages into several
|
* contiguous (eg on the virt board they are split into two
|
||||||
* blocks so we can support more CPUs.
|
* parts if there are too many CPUs to all fit in the same place
|
||||||
|
* in the memory map); if so then the GIC has multiple MemoryRegions
|
||||||
|
* for the redistributors.
|
||||||
*/
|
*/
|
||||||
cpuidx = offset / 0x20000;
|
cpuidx = region->cpuidx + offset / GICV3_REDIST_SIZE;
|
||||||
offset %= 0x20000;
|
offset %= GICV3_REDIST_SIZE;
|
||||||
assert(cpuidx < s->num_cpu);
|
|
||||||
|
|
||||||
cs = &s->cpu[cpuidx];
|
cs = &s->cpu[cpuidx];
|
||||||
|
|
||||||
@ -482,22 +484,24 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
|
|||||||
MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
|
MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
|
||||||
unsigned size, MemTxAttrs attrs)
|
unsigned size, MemTxAttrs attrs)
|
||||||
{
|
{
|
||||||
GICv3State *s = opaque;
|
GICv3RedistRegion *region = opaque;
|
||||||
|
GICv3State *s = region->gic;
|
||||||
GICv3CPUState *cs;
|
GICv3CPUState *cs;
|
||||||
MemTxResult r;
|
MemTxResult r;
|
||||||
int cpuidx;
|
int cpuidx;
|
||||||
|
|
||||||
assert((offset & (size - 1)) == 0);
|
assert((offset & (size - 1)) == 0);
|
||||||
|
|
||||||
/* This region covers all the redistributor pages; there are
|
/*
|
||||||
* (for GICv3) two 64K pages per CPU. At the moment they are
|
* There are (for GICv3) two 64K redistributor pages per CPU.
|
||||||
* all contiguous (ie in this one region), though we might later
|
* In some cases the redistributor pages for all CPUs are not
|
||||||
* want to allow splitting of redistributor pages into several
|
* contiguous (eg on the virt board they are split into two
|
||||||
* blocks so we can support more CPUs.
|
* parts if there are too many CPUs to all fit in the same place
|
||||||
|
* in the memory map); if so then the GIC has multiple MemoryRegions
|
||||||
|
* for the redistributors.
|
||||||
*/
|
*/
|
||||||
cpuidx = offset / 0x20000;
|
cpuidx = region->cpuidx + offset / GICV3_REDIST_SIZE;
|
||||||
offset %= 0x20000;
|
offset %= GICV3_REDIST_SIZE;
|
||||||
assert(cpuidx < s->num_cpu);
|
|
||||||
|
|
||||||
cs = &s->cpu[cpuidx];
|
cs = &s->cpu[cpuidx];
|
||||||
|
|
||||||
|
@ -181,7 +181,21 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
|
|||||||
PCDIMMDevice *dimm = PC_DIMM(dev);
|
PCDIMMDevice *dimm = PC_DIMM(dev);
|
||||||
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
|
||||||
MachineState *ms = MACHINE(qdev_get_machine());
|
MachineState *ms = MACHINE(qdev_get_machine());
|
||||||
int nb_numa_nodes = ms->numa_state->num_nodes;
|
|
||||||
|
if (ms->numa_state) {
|
||||||
|
int nb_numa_nodes = ms->numa_state->num_nodes;
|
||||||
|
|
||||||
|
if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) ||
|
||||||
|
(!nb_numa_nodes && dimm->node)) {
|
||||||
|
error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
|
||||||
|
PRIu32 "' which exceeds the number of numa nodes: %d",
|
||||||
|
dimm->node, nb_numa_nodes ? nb_numa_nodes : 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (dimm->node > 0) {
|
||||||
|
error_setg(errp, "machine doesn't support NUMA");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dimm->hostmem) {
|
if (!dimm->hostmem) {
|
||||||
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
|
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
|
||||||
@ -191,13 +205,6 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
|
|||||||
object_get_canonical_path_component(OBJECT(dimm->hostmem)));
|
object_get_canonical_path_component(OBJECT(dimm->hostmem)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) ||
|
|
||||||
(!nb_numa_nodes && dimm->node)) {
|
|
||||||
error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
|
|
||||||
PRIu32 "' which exceeds the number of numa nodes: %d",
|
|
||||||
dimm->node, nb_numa_nodes ? nb_numa_nodes : 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ddc->realize) {
|
if (ddc->realize) {
|
||||||
ddc->realize(dimm, errp);
|
ddc->realize(dimm, errp);
|
||||||
|
@ -232,10 +232,10 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index,
|
static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index,
|
||||||
int last_index)
|
int vq_index_end)
|
||||||
{
|
{
|
||||||
net->dev.vq_index = vq_index;
|
net->dev.vq_index = vq_index;
|
||||||
net->dev.last_index = last_index;
|
net->dev.vq_index_end = vq_index_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vhost_net_start_one(struct vhost_net *net,
|
static int vhost_net_start_one(struct vhost_net *net,
|
||||||
@ -326,11 +326,11 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
|||||||
VirtIONet *n = VIRTIO_NET(dev);
|
VirtIONet *n = VIRTIO_NET(dev);
|
||||||
int nvhosts = data_queue_pairs + cvq;
|
int nvhosts = data_queue_pairs + cvq;
|
||||||
struct vhost_net *net;
|
struct vhost_net *net;
|
||||||
int r, e, i, last_index = data_queue_pairs * 2;
|
int r, e, i, index_end = data_queue_pairs * 2;
|
||||||
NetClientState *peer;
|
NetClientState *peer;
|
||||||
|
|
||||||
if (!cvq) {
|
if (cvq) {
|
||||||
last_index -= 1;
|
index_end += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!k->set_guest_notifiers) {
|
if (!k->set_guest_notifiers) {
|
||||||
@ -347,7 +347,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
net = get_vhost_net(peer);
|
net = get_vhost_net(peer);
|
||||||
vhost_net_set_vq_index(net, i * 2, last_index);
|
vhost_net_set_vq_index(net, i * 2, index_end);
|
||||||
|
|
||||||
/* Suppress the masking guest notifiers on vhost user
|
/* Suppress the masking guest notifiers on vhost user
|
||||||
* because vhost user doesn't interrupt masking/unmasking
|
* because vhost user doesn't interrupt masking/unmasking
|
||||||
|
@ -1441,6 +1441,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
vmxnet3_setup_rx_filtering(s);
|
vmxnet3_setup_rx_filtering(s);
|
||||||
/* Cache fields from shared memory */
|
/* Cache fields from shared memory */
|
||||||
s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu);
|
s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu);
|
||||||
|
assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU);
|
||||||
VMW_CFPRN("MTU is %u", s->mtu);
|
VMW_CFPRN("MTU is %u", s->mtu);
|
||||||
|
|
||||||
s->max_rx_frags =
|
s->max_rx_frags =
|
||||||
@ -1486,6 +1487,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
/* Read rings memory locations for TX queues */
|
/* Read rings memory locations for TX queues */
|
||||||
pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA);
|
pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA);
|
||||||
size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize);
|
size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize);
|
||||||
|
if (size > VMXNET3_TX_RING_MAX_SIZE) {
|
||||||
|
size = VMXNET3_TX_RING_MAX_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size,
|
vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size,
|
||||||
sizeof(struct Vmxnet3_TxDesc), false);
|
sizeof(struct Vmxnet3_TxDesc), false);
|
||||||
@ -1496,6 +1500,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
/* TXC ring */
|
/* TXC ring */
|
||||||
pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA);
|
pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA);
|
||||||
size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize);
|
size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize);
|
||||||
|
if (size > VMXNET3_TC_RING_MAX_SIZE) {
|
||||||
|
size = VMXNET3_TC_RING_MAX_SIZE;
|
||||||
|
}
|
||||||
vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size,
|
vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size,
|
||||||
sizeof(struct Vmxnet3_TxCompDesc), true);
|
sizeof(struct Vmxnet3_TxCompDesc), true);
|
||||||
VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring);
|
VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring);
|
||||||
@ -1537,6 +1544,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
/* RX rings */
|
/* RX rings */
|
||||||
pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]);
|
pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]);
|
||||||
size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]);
|
size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]);
|
||||||
|
if (size > VMXNET3_RX_RING_MAX_SIZE) {
|
||||||
|
size = VMXNET3_RX_RING_MAX_SIZE;
|
||||||
|
}
|
||||||
vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size,
|
vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size,
|
||||||
sizeof(struct Vmxnet3_RxDesc), false);
|
sizeof(struct Vmxnet3_RxDesc), false);
|
||||||
VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d",
|
VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d",
|
||||||
@ -1546,6 +1556,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
|||||||
/* RXC ring */
|
/* RXC ring */
|
||||||
pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA);
|
pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA);
|
||||||
size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize);
|
size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize);
|
||||||
|
if (size > VMXNET3_RC_RING_MAX_SIZE) {
|
||||||
|
size = VMXNET3_RC_RING_MAX_SIZE;
|
||||||
|
}
|
||||||
vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size,
|
vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size,
|
||||||
sizeof(struct Vmxnet3_RxCompDesc), true);
|
sizeof(struct Vmxnet3_RxCompDesc), true);
|
||||||
VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size);
|
VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size);
|
||||||
|
@ -4168,6 +4168,11 @@ static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
uint32_t nsid;
|
uint32_t nsid;
|
||||||
|
|
||||||
|
if (off >= sizeof(nslist)) {
|
||||||
|
trace_pci_nvme_err_invalid_log_page_offset(off, sizeof(nslist));
|
||||||
|
return NVME_INVALID_FIELD | NVME_DNR;
|
||||||
|
}
|
||||||
|
|
||||||
memset(nslist, 0x0, sizeof(nslist));
|
memset(nslist, 0x0, sizeof(nslist));
|
||||||
trans_len = MIN(sizeof(nslist) - off, buf_len);
|
trans_len = MIN(sizeof(nslist) - off, buf_len);
|
||||||
|
|
||||||
|
@ -465,12 +465,6 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
|
|||||||
"linked to an nvme-subsys device");
|
"linked to an nvme-subsys device");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->params.shared) {
|
|
||||||
error_setg(errp, "shared requires that the nvme device is "
|
|
||||||
"linked to an nvme-subsys device");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If this namespace belongs to a subsystem (through a link on the
|
* If this namespace belongs to a subsystem (through a link on the
|
||||||
@ -532,7 +526,7 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
|
|||||||
static Property nvme_ns_props[] = {
|
static Property nvme_ns_props[] = {
|
||||||
DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
|
DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
|
||||||
DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false),
|
DEFINE_PROP_BOOL("detached", NvmeNamespace, params.detached, false),
|
||||||
DEFINE_PROP_BOOL("shared", NvmeNamespace, params.shared, false),
|
DEFINE_PROP_BOOL("shared", NvmeNamespace, params.shared, true),
|
||||||
DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
|
DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
|
||||||
DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid),
|
DEFINE_PROP_UUID("uuid", NvmeNamespace, params.uuid),
|
||||||
DEFINE_PROP_UINT64("eui64", NvmeNamespace, params.eui64, 0),
|
DEFINE_PROP_UINT64("eui64", NvmeNamespace, params.eui64, 0),
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
|
int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
|
||||||
{
|
{
|
||||||
NvmeSubsystem *subsys = n->subsys;
|
NvmeSubsystem *subsys = n->subsys;
|
||||||
int cntlid;
|
int cntlid, nsid;
|
||||||
|
|
||||||
for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) {
|
for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) {
|
||||||
if (!subsys->ctrls[cntlid]) {
|
if (!subsys->ctrls[cntlid]) {
|
||||||
@ -29,12 +29,20 @@ int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
|
|||||||
|
|
||||||
subsys->ctrls[cntlid] = n;
|
subsys->ctrls[cntlid] = n;
|
||||||
|
|
||||||
|
for (nsid = 1; nsid < ARRAY_SIZE(subsys->namespaces); nsid++) {
|
||||||
|
NvmeNamespace *ns = subsys->namespaces[nsid];
|
||||||
|
if (ns && ns->params.shared && !ns->params.detached) {
|
||||||
|
nvme_attach_ns(n, ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cntlid;
|
return cntlid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n)
|
void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n)
|
||||||
{
|
{
|
||||||
subsys->ctrls[n->cntlid] = NULL;
|
subsys->ctrls[n->cntlid] = NULL;
|
||||||
|
n->cntlid = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvme_subsys_setup(NvmeSubsystem *subsys)
|
static void nvme_subsys_setup(NvmeSubsystem *subsys)
|
||||||
|
25
hw/pci/pci.c
25
hw/pci/pci.c
@ -1380,6 +1380,9 @@ static void pci_update_mappings(PCIDevice *d)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
new_addr = pci_bar_address(d, i, r->type, r->size);
|
new_addr = pci_bar_address(d, i, r->type, r->size);
|
||||||
|
if (!d->has_power) {
|
||||||
|
new_addr = PCI_BAR_UNMAPPED;
|
||||||
|
}
|
||||||
|
|
||||||
/* This bar isn't changed */
|
/* This bar isn't changed */
|
||||||
if (new_addr == r->addr)
|
if (new_addr == r->addr)
|
||||||
@ -1464,8 +1467,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
|
|||||||
if (range_covers_byte(addr, l, PCI_COMMAND)) {
|
if (range_covers_byte(addr, l, PCI_COMMAND)) {
|
||||||
pci_update_irq_disabled(d, was_irq_disabled);
|
pci_update_irq_disabled(d, was_irq_disabled);
|
||||||
memory_region_set_enabled(&d->bus_master_enable_region,
|
memory_region_set_enabled(&d->bus_master_enable_region,
|
||||||
pci_get_word(d->config + PCI_COMMAND)
|
(pci_get_word(d->config + PCI_COMMAND)
|
||||||
& PCI_COMMAND_MASTER);
|
& PCI_COMMAND_MASTER) && d->has_power);
|
||||||
}
|
}
|
||||||
|
|
||||||
msi_write_config(d, addr, val_in, l);
|
msi_write_config(d, addr, val_in, l);
|
||||||
@ -2182,6 +2185,8 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
|
|||||||
pci_qdev_unrealize(DEVICE(pci_dev));
|
pci_qdev_unrealize(DEVICE(pci_dev));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pci_set_power(pci_dev, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
PCIDevice *pci_new_multifunction(int devfn, bool multifunction,
|
PCIDevice *pci_new_multifunction(int devfn, bool multifunction,
|
||||||
@ -2853,6 +2858,22 @@ MSIMessage pci_get_msi_message(PCIDevice *dev, int vector)
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pci_set_power(PCIDevice *d, bool state)
|
||||||
|
{
|
||||||
|
if (d->has_power == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->has_power = state;
|
||||||
|
pci_update_mappings(d);
|
||||||
|
memory_region_set_enabled(&d->bus_master_enable_region,
|
||||||
|
(pci_get_word(d->config + PCI_COMMAND)
|
||||||
|
& PCI_COMMAND_MASTER) && d->has_power);
|
||||||
|
if (!d->has_power) {
|
||||||
|
pci_device_reset(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const TypeInfo pci_device_type_info = {
|
static const TypeInfo pci_device_type_info = {
|
||||||
.name = TYPE_PCI_DEVICE,
|
.name = TYPE_PCI_DEVICE,
|
||||||
.parent = TYPE_DEVICE,
|
.parent = TYPE_DEVICE,
|
||||||
|
@ -74,7 +74,8 @@ void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
|
|||||||
/* non-zero functions are only exposed when function 0 is present,
|
/* non-zero functions are only exposed when function 0 is present,
|
||||||
* allowing direct removal of unexposed functions.
|
* allowing direct removal of unexposed functions.
|
||||||
*/
|
*/
|
||||||
if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) {
|
if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
|
||||||
|
!pci_dev->has_power) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +98,8 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
|
|||||||
/* non-zero functions are only exposed when function 0 is present,
|
/* non-zero functions are only exposed when function 0 is present,
|
||||||
* allowing direct removal of unexposed functions.
|
* allowing direct removal of unexposed functions.
|
||||||
*/
|
*/
|
||||||
if (pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) {
|
if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
|
||||||
|
!pci_dev->has_power) {
|
||||||
return ~0x0;
|
return ~0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +366,29 @@ static void hotplug_event_clear(PCIDevice *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pcie_set_power_device(PCIBus *bus, PCIDevice *dev, void *opaque)
|
||||||
|
{
|
||||||
|
bool *power = opaque;
|
||||||
|
|
||||||
|
pci_set_power(dev, *power);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pcie_cap_update_power(PCIDevice *hotplug_dev)
|
||||||
|
{
|
||||||
|
uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
|
||||||
|
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(hotplug_dev));
|
||||||
|
uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP);
|
||||||
|
uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
|
||||||
|
bool power = true;
|
||||||
|
|
||||||
|
if (sltcap & PCI_EXP_SLTCAP_PCP) {
|
||||||
|
power = (sltctl & PCI_EXP_SLTCTL_PCC) == PCI_EXP_SLTCTL_PWR_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
|
||||||
|
pcie_set_power_device, &power);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A PCI Express Hot-Plug Event has occurred, so update slot status register
|
* A PCI Express Hot-Plug Event has occurred, so update slot status register
|
||||||
* and notify OS of the event if necessary.
|
* and notify OS of the event if necessary.
|
||||||
@ -434,6 +457,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
|
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
|
||||||
PCI_EXP_LNKSTA_DLLLA);
|
PCI_EXP_LNKSTA_DLLLA);
|
||||||
}
|
}
|
||||||
|
pcie_cap_update_power(hotplug_pdev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,6 +475,7 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||||||
}
|
}
|
||||||
pcie_cap_slot_event(hotplug_pdev,
|
pcie_cap_slot_event(hotplug_pdev,
|
||||||
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
|
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
|
||||||
|
pcie_cap_update_power(hotplug_pdev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,6 +497,25 @@ static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
|
|||||||
object_unparent(OBJECT(dev));
|
object_unparent(OBJECT(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pcie_cap_slot_do_unplug(PCIDevice *dev)
|
||||||
|
{
|
||||||
|
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
|
||||||
|
uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
|
||||||
|
uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
|
||||||
|
|
||||||
|
pci_for_each_device_under_bus(sec_bus, pcie_unplug_device, NULL);
|
||||||
|
|
||||||
|
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||||
|
PCI_EXP_SLTSTA_PDS);
|
||||||
|
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA ||
|
||||||
|
(lnkcap & PCI_EXP_LNKCAP_DLLLARC)) {
|
||||||
|
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
|
||||||
|
PCI_EXP_LNKSTA_DLLLA);
|
||||||
|
}
|
||||||
|
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||||
|
PCI_EXP_SLTSTA_PDC);
|
||||||
|
}
|
||||||
|
|
||||||
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
@ -481,6 +525,7 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||||||
PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
|
PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
|
||||||
uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
|
uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
|
||||||
uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
|
uint32_t sltcap = pci_get_word(exp_cap + PCI_EXP_SLTCAP);
|
||||||
|
uint16_t sltctl = pci_get_word(exp_cap + PCI_EXP_SLTCTL);
|
||||||
|
|
||||||
/* Check if hot-unplug is disabled on the slot */
|
/* Check if hot-unplug is disabled on the slot */
|
||||||
if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
|
if ((sltcap & PCI_EXP_SLTCAP_HPC) == 0) {
|
||||||
@ -496,7 +541,15 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((sltctl & PCI_EXP_SLTCTL_PIC) == PCI_EXP_SLTCTL_PWR_IND_BLINK) {
|
||||||
|
error_setg(errp, "Hot-unplug failed: "
|
||||||
|
"guest is busy (power indicator blinking)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dev->pending_deleted_event = true;
|
dev->pending_deleted_event = true;
|
||||||
|
dev->pending_deleted_expires_ms =
|
||||||
|
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 5000; /* 5 secs */
|
||||||
|
|
||||||
/* In case user cancel the operation of multi-function hot-add,
|
/* In case user cancel the operation of multi-function hot-add,
|
||||||
* remove the function that is unexposed to guest individually,
|
* remove the function that is unexposed to guest individually,
|
||||||
@ -509,6 +562,16 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((sltctl & PCI_EXP_SLTCTL_PIC) == PCI_EXP_SLTCTL_PWR_IND_OFF) &&
|
||||||
|
((sltctl & PCI_EXP_SLTCTL_PCC) == PCI_EXP_SLTCTL_PWR_OFF)) {
|
||||||
|
/* slot is powered off -> unplug without round-trip to the guest */
|
||||||
|
pcie_cap_slot_do_unplug(hotplug_pdev);
|
||||||
|
hotplug_event_notify(hotplug_pdev);
|
||||||
|
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||||
|
PCI_EXP_SLTSTA_ABP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pcie_cap_slot_push_attention_button(hotplug_pdev);
|
pcie_cap_slot_push_attention_button(hotplug_pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,6 +688,7 @@ void pcie_cap_slot_reset(PCIDevice *dev)
|
|||||||
PCI_EXP_SLTSTA_PDC |
|
PCI_EXP_SLTSTA_PDC |
|
||||||
PCI_EXP_SLTSTA_ABP);
|
PCI_EXP_SLTSTA_ABP);
|
||||||
|
|
||||||
|
pcie_cap_update_power(dev);
|
||||||
hotplug_event_update_event_status(dev);
|
hotplug_event_update_event_status(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,7 +707,6 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
|
|||||||
uint32_t pos = dev->exp.exp_cap;
|
uint32_t pos = dev->exp.exp_cap;
|
||||||
uint8_t *exp_cap = dev->config + pos;
|
uint8_t *exp_cap = dev->config + pos;
|
||||||
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
|
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
|
||||||
uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
|
|
||||||
|
|
||||||
if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
|
if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
|
||||||
/*
|
/*
|
||||||
@ -693,18 +756,9 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
|
|||||||
(val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF &&
|
(val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF &&
|
||||||
(!(old_slt_ctl & PCI_EXP_SLTCTL_PCC) ||
|
(!(old_slt_ctl & PCI_EXP_SLTCTL_PCC) ||
|
||||||
(old_slt_ctl & PCI_EXP_SLTCTL_PIC_OFF) != PCI_EXP_SLTCTL_PIC_OFF)) {
|
(old_slt_ctl & PCI_EXP_SLTCTL_PIC_OFF) != PCI_EXP_SLTCTL_PIC_OFF)) {
|
||||||
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
|
pcie_cap_slot_do_unplug(dev);
|
||||||
pci_for_each_device_under_bus(sec_bus, pcie_unplug_device, NULL);
|
|
||||||
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
|
||||||
PCI_EXP_SLTSTA_PDS);
|
|
||||||
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA ||
|
|
||||||
(lnkcap & PCI_EXP_LNKCAP_DLLLARC)) {
|
|
||||||
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
|
|
||||||
PCI_EXP_LNKSTA_DLLLA);
|
|
||||||
}
|
|
||||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
|
||||||
PCI_EXP_SLTSTA_PDC);
|
|
||||||
}
|
}
|
||||||
|
pcie_cap_update_power(dev);
|
||||||
|
|
||||||
hotplug_event_notify(dev);
|
hotplug_event_notify(dev);
|
||||||
|
|
||||||
@ -731,6 +785,7 @@ int pcie_cap_slot_post_load(void *opaque, int version_id)
|
|||||||
{
|
{
|
||||||
PCIDevice *dev = opaque;
|
PCIDevice *dev = opaque;
|
||||||
hotplug_event_update_event_status(dev);
|
hotplug_event_update_event_status(dev);
|
||||||
|
pcie_cap_update_power(dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ static Property pcie_slot_props[] = {
|
|||||||
DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
|
DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
|
||||||
DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
|
DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
|
||||||
DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
|
DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
|
||||||
DEFINE_PROP_BOOL("native-hotplug", PCIESlot, native_hotplug, true),
|
DEFINE_PROP_BOOL("x-native-hotplug", PCIESlot, native_hotplug, true),
|
||||||
DEFINE_PROP_END_OF_LIST()
|
DEFINE_PROP_END_OF_LIST()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
softmmu_ss.add(when: 'CONFIG_DS1338', if_true: files('ds1338.c'))
|
softmmu_ss.add(when: 'CONFIG_DS1338', if_true: files('ds1338.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_M41T80', if_true: files('m41t80.c'))
|
softmmu_ss.add(when: 'CONFIG_M41T80', if_true: files('m41t80.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_M48T59', if_true: files('m48t59.c'))
|
softmmu_ss.add(when: 'CONFIG_M48T59', if_true: files('m48t59.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
|
specific_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_TWL92230', if_true: files('twl92230.c'))
|
softmmu_ss.add(when: 'CONFIG_TWL92230', if_true: files('twl92230.c'))
|
||||||
softmmu_ss.add(when: ['CONFIG_ISA_BUS', 'CONFIG_M48T59'], if_true: files('m48t59-isa.c'))
|
softmmu_ss.add(when: ['CONFIG_ISA_BUS', 'CONFIG_M48T59'], if_true: files('m48t59-isa.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-rtc.c'))
|
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-rtc.c'))
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include "qapi/qapi-events-misc-target.h"
|
||||||
|
|
||||||
#define RTC_DR 0x00 /* Data read register */
|
#define RTC_DR 0x00 /* Data read register */
|
||||||
#define RTC_MR 0x04 /* Match register */
|
#define RTC_MR 0x04 /* Match register */
|
||||||
@ -136,10 +137,17 @@ static void pl031_write(void * opaque, hwaddr offset,
|
|||||||
trace_pl031_write(offset, value);
|
trace_pl031_write(offset, value);
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case RTC_LR:
|
case RTC_LR: {
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
s->tick_offset += value - pl031_get_count(s);
|
s->tick_offset += value - pl031_get_count(s);
|
||||||
|
|
||||||
|
qemu_get_timedate(&tm, s->tick_offset);
|
||||||
|
qapi_event_send_rtc_change(qemu_timedate_diff(&tm));
|
||||||
|
|
||||||
pl031_set_alarm(s);
|
pl031_set_alarm(s);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RTC_MR:
|
case RTC_MR:
|
||||||
s->mr = value;
|
s->mr = value;
|
||||||
pl031_set_alarm(s);
|
pl031_set_alarm(s);
|
||||||
|
@ -551,6 +551,7 @@ static int vfio_host_win_del(VFIOContainer *container, hwaddr min_iova,
|
|||||||
QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) {
|
QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) {
|
||||||
if (hostwin->min_iova == min_iova && hostwin->max_iova == max_iova) {
|
if (hostwin->min_iova == min_iova && hostwin->max_iova == max_iova) {
|
||||||
QLIST_REMOVE(hostwin, hostwin_next);
|
QLIST_REMOVE(hostwin, hostwin_next);
|
||||||
|
g_free(hostwin);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2239,6 +2240,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
|
|||||||
if (QLIST_EMPTY(&container->group_list)) {
|
if (QLIST_EMPTY(&container->group_list)) {
|
||||||
VFIOAddressSpace *space = container->space;
|
VFIOAddressSpace *space = container->space;
|
||||||
VFIOGuestIOMMU *giommu, *tmp;
|
VFIOGuestIOMMU *giommu, *tmp;
|
||||||
|
VFIOHostDMAWindow *hostwin, *next;
|
||||||
|
|
||||||
QLIST_REMOVE(container, next);
|
QLIST_REMOVE(container, next);
|
||||||
|
|
||||||
@ -2249,6 +2251,12 @@ static void vfio_disconnect_container(VFIOGroup *group)
|
|||||||
g_free(giommu);
|
g_free(giommu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QLIST_FOREACH_SAFE(hostwin, &container->hostwin_list, hostwin_next,
|
||||||
|
next) {
|
||||||
|
QLIST_REMOVE(hostwin, hostwin_next);
|
||||||
|
g_free(hostwin);
|
||||||
|
}
|
||||||
|
|
||||||
trace_vfio_disconnect_container(container->fd);
|
trace_vfio_disconnect_container(container->fd);
|
||||||
close(container->fd);
|
close(container->fd);
|
||||||
g_free(container);
|
g_free(container);
|
||||||
|
@ -645,7 +645,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
|
|||||||
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
|
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->vq_index + dev->nvqs != dev->last_index) {
|
if (dev->vq_index + dev->nvqs != dev->vq_index_end) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,13 +247,10 @@ static void vring_packed_event_read(VirtIODevice *vdev,
|
|||||||
hwaddr off_off = offsetof(VRingPackedDescEvent, off_wrap);
|
hwaddr off_off = offsetof(VRingPackedDescEvent, off_wrap);
|
||||||
hwaddr off_flags = offsetof(VRingPackedDescEvent, flags);
|
hwaddr off_flags = offsetof(VRingPackedDescEvent, flags);
|
||||||
|
|
||||||
address_space_read_cached(cache, off_flags, &e->flags,
|
e->flags = virtio_lduw_phys_cached(vdev, cache, off_flags);
|
||||||
sizeof(e->flags));
|
|
||||||
/* Make sure flags is seen before off_wrap */
|
/* Make sure flags is seen before off_wrap */
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
address_space_read_cached(cache, off_off, &e->off_wrap,
|
e->off_wrap = virtio_lduw_phys_cached(vdev, cache, off_off);
|
||||||
sizeof(e->off_wrap));
|
|
||||||
virtio_tswap16s(vdev, &e->off_wrap);
|
|
||||||
virtio_tswap16s(vdev, &e->flags);
|
virtio_tswap16s(vdev, &e->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,8 +260,7 @@ static void vring_packed_off_wrap_write(VirtIODevice *vdev,
|
|||||||
{
|
{
|
||||||
hwaddr off = offsetof(VRingPackedDescEvent, off_wrap);
|
hwaddr off = offsetof(VRingPackedDescEvent, off_wrap);
|
||||||
|
|
||||||
virtio_tswap16s(vdev, &off_wrap);
|
virtio_stw_phys_cached(vdev, cache, off, off_wrap);
|
||||||
address_space_write_cached(cache, off, &off_wrap, sizeof(off_wrap));
|
|
||||||
address_space_cache_invalidate(cache, off, sizeof(off_wrap));
|
address_space_cache_invalidate(cache, off, sizeof(off_wrap));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,8 +269,7 @@ static void vring_packed_flags_write(VirtIODevice *vdev,
|
|||||||
{
|
{
|
||||||
hwaddr off = offsetof(VRingPackedDescEvent, flags);
|
hwaddr off = offsetof(VRingPackedDescEvent, flags);
|
||||||
|
|
||||||
virtio_tswap16s(vdev, &flags);
|
virtio_stw_phys_cached(vdev, cache, off, flags);
|
||||||
address_space_write_cached(cache, off, &flags, sizeof(flags));
|
|
||||||
address_space_cache_invalidate(cache, off, sizeof(flags));
|
address_space_cache_invalidate(cache, off, sizeof(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,11 +502,9 @@ static void vring_packed_desc_read_flags(VirtIODevice *vdev,
|
|||||||
MemoryRegionCache *cache,
|
MemoryRegionCache *cache,
|
||||||
int i)
|
int i)
|
||||||
{
|
{
|
||||||
address_space_read_cached(cache,
|
hwaddr off = i * sizeof(VRingPackedDesc) + offsetof(VRingPackedDesc, flags);
|
||||||
i * sizeof(VRingPackedDesc) +
|
|
||||||
offsetof(VRingPackedDesc, flags),
|
*flags = virtio_lduw_phys_cached(vdev, cache, off);
|
||||||
flags, sizeof(*flags));
|
|
||||||
virtio_tswap16s(vdev, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vring_packed_desc_read(VirtIODevice *vdev,
|
static void vring_packed_desc_read(VirtIODevice *vdev,
|
||||||
@ -564,8 +557,7 @@ static void vring_packed_desc_write_flags(VirtIODevice *vdev,
|
|||||||
{
|
{
|
||||||
hwaddr off = i * sizeof(VRingPackedDesc) + offsetof(VRingPackedDesc, flags);
|
hwaddr off = i * sizeof(VRingPackedDesc) + offsetof(VRingPackedDesc, flags);
|
||||||
|
|
||||||
virtio_tswap16s(vdev, &desc->flags);
|
virtio_stw_phys_cached(vdev, cache, off, desc->flags);
|
||||||
address_space_write_cached(cache, off, &desc->flags, sizeof(desc->flags));
|
|
||||||
address_space_cache_invalidate(cache, off, sizeof(desc->flags));
|
address_space_cache_invalidate(cache, off, sizeof(desc->flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ typedef struct ICH9LPCPMRegs {
|
|||||||
AcpiCpuHotplug gpe_cpu;
|
AcpiCpuHotplug gpe_cpu;
|
||||||
CPUHotplugState cpuhp_state;
|
CPUHotplugState cpuhp_state;
|
||||||
|
|
||||||
|
bool keep_pci_slot_hpc;
|
||||||
bool use_acpi_hotplug_bridge;
|
bool use_acpi_hotplug_bridge;
|
||||||
AcpiPciHpState acpi_pci_hotplug;
|
AcpiPciHpState acpi_pci_hotplug;
|
||||||
MemHotplugState acpi_memory_hotplug;
|
MemHotplugState acpi_memory_hotplug;
|
||||||
|
@ -215,13 +215,23 @@ struct GICv3CPUState {
|
|||||||
bool seenbetter;
|
bool seenbetter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The redistributor pages might be split into more than one region
|
||||||
|
* on some machine types if there are many CPUs.
|
||||||
|
*/
|
||||||
|
typedef struct GICv3RedistRegion {
|
||||||
|
GICv3State *gic;
|
||||||
|
MemoryRegion iomem;
|
||||||
|
uint32_t cpuidx; /* index of first CPU this region covers */
|
||||||
|
} GICv3RedistRegion;
|
||||||
|
|
||||||
struct GICv3State {
|
struct GICv3State {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
MemoryRegion iomem_dist; /* Distributor */
|
MemoryRegion iomem_dist; /* Distributor */
|
||||||
MemoryRegion *iomem_redist; /* Redistributor Regions */
|
GICv3RedistRegion *redist_regions; /* Redistributor Regions */
|
||||||
uint32_t *redist_region_count; /* redistributor count within each region */
|
uint32_t *redist_region_count; /* redistributor count within each region */
|
||||||
uint32_t nb_redist_regions; /* number of redist regions */
|
uint32_t nb_redist_regions; /* number of redist regions */
|
||||||
|
|
||||||
@ -306,6 +316,6 @@ struct ARMGICv3CommonClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
||||||
const MemoryRegionOps *ops, Error **errp);
|
const MemoryRegionOps *ops);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -268,6 +268,7 @@ typedef struct PCIReqIDCache PCIReqIDCache;
|
|||||||
struct PCIDevice {
|
struct PCIDevice {
|
||||||
DeviceState qdev;
|
DeviceState qdev;
|
||||||
bool partially_hotplugged;
|
bool partially_hotplugged;
|
||||||
|
bool has_power;
|
||||||
|
|
||||||
/* PCI config space */
|
/* PCI config space */
|
||||||
uint8_t *config;
|
uint8_t *config;
|
||||||
@ -908,5 +909,6 @@ extern const VMStateDescription vmstate_pci_device;
|
|||||||
}
|
}
|
||||||
|
|
||||||
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector);
|
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector);
|
||||||
|
void pci_set_power(PCIDevice *pci_dev, bool state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -181,6 +181,7 @@ struct DeviceState {
|
|||||||
char *canonical_path;
|
char *canonical_path;
|
||||||
bool realized;
|
bool realized;
|
||||||
bool pending_deleted_event;
|
bool pending_deleted_event;
|
||||||
|
int64_t pending_deleted_expires_ms;
|
||||||
QDict *opts;
|
QDict *opts;
|
||||||
int hotplugged;
|
int hotplugged;
|
||||||
bool allow_unplug_during_migration;
|
bool allow_unplug_during_migration;
|
||||||
|
@ -74,8 +74,8 @@ struct vhost_dev {
|
|||||||
unsigned int nvqs;
|
unsigned int nvqs;
|
||||||
/* the first virtqueue which would be used by this vhost dev */
|
/* the first virtqueue which would be used by this vhost dev */
|
||||||
int vq_index;
|
int vq_index;
|
||||||
/* the last vq index for the virtio device (not vhost) */
|
/* one past the last vq index for the virtio device (not vhost) */
|
||||||
int last_index;
|
int vq_index_end;
|
||||||
/* if non-zero, minimum required value for max_queues */
|
/* if non-zero, minimum required value for max_queues */
|
||||||
int num_queues;
|
int num_queues;
|
||||||
uint64_t features;
|
uint64_t features;
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
* tran_create(), call your "prepare" functions on it, and finally call
|
* tran_create(), call your "prepare" functions on it, and finally call
|
||||||
* tran_abort() or tran_commit() to finalize the transaction by corresponding
|
* tran_abort() or tran_commit() to finalize the transaction by corresponding
|
||||||
* finalization actions in reverse order.
|
* finalization actions in reverse order.
|
||||||
|
*
|
||||||
|
* The clean() functions registered by the drivers in a transaction are called
|
||||||
|
* last, after all abort() or commit() functions have been called.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef QEMU_TRANSACTIONS_H
|
#ifndef QEMU_TRANSACTIONS_H
|
||||||
|
24
meson.build
24
meson.build
@ -59,6 +59,12 @@ supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64',
|
|||||||
'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64']
|
'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64']
|
||||||
|
|
||||||
cpu = host_machine.cpu_family()
|
cpu = host_machine.cpu_family()
|
||||||
|
|
||||||
|
# Unify riscv* to a single family.
|
||||||
|
if cpu in ['riscv32', 'riscv64']
|
||||||
|
cpu = 'riscv'
|
||||||
|
endif
|
||||||
|
|
||||||
targetos = host_machine.system()
|
targetos = host_machine.system()
|
||||||
|
|
||||||
if cpu in ['x86', 'x86_64']
|
if cpu in ['x86', 'x86_64']
|
||||||
@ -566,13 +572,7 @@ endif
|
|||||||
spice_headers = spice.partial_dependency(compile_args: true, includes: true)
|
spice_headers = spice.partial_dependency(compile_args: true, includes: true)
|
||||||
|
|
||||||
rt = cc.find_library('rt', required: false)
|
rt = cc.find_library('rt', required: false)
|
||||||
libdl = not_found
|
|
||||||
if 'CONFIG_PLUGIN' in config_host
|
|
||||||
libdl = cc.find_library('dl', required: false)
|
|
||||||
if not cc.has_function('dlopen', dependencies: libdl)
|
|
||||||
error('dlopen not found')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
libiscsi = not_found
|
libiscsi = not_found
|
||||||
if not get_option('libiscsi').auto() or have_block
|
if not get_option('libiscsi').auto() or have_block
|
||||||
libiscsi = dependency('libiscsi', version: '>=1.9.0',
|
libiscsi = dependency('libiscsi', version: '>=1.9.0',
|
||||||
@ -1201,6 +1201,11 @@ keyutils = dependency('libkeyutils', required: false,
|
|||||||
|
|
||||||
has_gettid = cc.has_function('gettid')
|
has_gettid = cc.has_function('gettid')
|
||||||
|
|
||||||
|
# libselinux
|
||||||
|
selinux = dependency('libselinux',
|
||||||
|
required: get_option('selinux'),
|
||||||
|
method: 'pkg-config', kwargs: static_kwargs)
|
||||||
|
|
||||||
# Malloc tests
|
# Malloc tests
|
||||||
|
|
||||||
malloc = []
|
malloc = []
|
||||||
@ -1479,6 +1484,7 @@ config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
|
|||||||
config_host_data.set('CONFIG_SPICE', spice.found())
|
config_host_data.set('CONFIG_SPICE', spice.found())
|
||||||
config_host_data.set('CONFIG_X11', x11.found())
|
config_host_data.set('CONFIG_X11', x11.found())
|
||||||
config_host_data.set('CONFIG_CFI', get_option('cfi'))
|
config_host_data.set('CONFIG_CFI', get_option('cfi'))
|
||||||
|
config_host_data.set('CONFIG_SELINUX', selinux.found())
|
||||||
config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
|
config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
|
||||||
config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
|
config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
|
||||||
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
|
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
|
||||||
@ -3088,7 +3094,8 @@ if have_tools
|
|||||||
qemu_io = executable('qemu-io', files('qemu-io.c'),
|
qemu_io = executable('qemu-io', files('qemu-io.c'),
|
||||||
dependencies: [block, qemuutil], install: true)
|
dependencies: [block, qemuutil], install: true)
|
||||||
qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
|
qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
|
||||||
dependencies: [blockdev, qemuutil, gnutls], install: true)
|
dependencies: [blockdev, qemuutil, gnutls, selinux],
|
||||||
|
install: true)
|
||||||
|
|
||||||
subdir('storage-daemon')
|
subdir('storage-daemon')
|
||||||
subdir('contrib/rdmacm-mux')
|
subdir('contrib/rdmacm-mux')
|
||||||
@ -3464,6 +3471,7 @@ summary_info += {'libdaxctl support': libdaxctl}
|
|||||||
summary_info += {'libudev': libudev}
|
summary_info += {'libudev': libudev}
|
||||||
# Dummy dependency, keep .found()
|
# Dummy dependency, keep .found()
|
||||||
summary_info += {'FUSE lseek': fuse_lseek.found()}
|
summary_info += {'FUSE lseek': fuse_lseek.found()}
|
||||||
|
summary_info += {'selinux': selinux}
|
||||||
summary(summary_info, bool_yn: true, section: 'Dependencies')
|
summary(summary_info, bool_yn: true, section: 'Dependencies')
|
||||||
|
|
||||||
if not supported_cpus.contains(cpu)
|
if not supported_cpus.contains(cpu)
|
||||||
|
@ -201,3 +201,6 @@ option('slirp', type: 'combo', value: 'auto',
|
|||||||
option('fdt', type: 'combo', value: 'auto',
|
option('fdt', type: 'combo', value: 'auto',
|
||||||
choices: ['disabled', 'enabled', 'auto', 'system', 'internal'],
|
choices: ['disabled', 'enabled', 'auto', 'system', 'internal'],
|
||||||
description: 'Whether and how to find the libfdt library')
|
description: 'Whether and how to find the libfdt library')
|
||||||
|
|
||||||
|
option('selinux', type: 'feature', value: 'auto',
|
||||||
|
description: 'SELinux support in qemu-nbd')
|
||||||
|
13
nbd/server.c
13
nbd/server.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016-2020 Red Hat, Inc.
|
* Copyright (C) 2016-2021 Red Hat, Inc.
|
||||||
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
|
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
|
||||||
*
|
*
|
||||||
* Network Block Device Server Side
|
* Network Block Device Server Side
|
||||||
@ -879,7 +879,9 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
|
|||||||
if (!*query) {
|
if (!*query) {
|
||||||
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
|
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
|
||||||
meta->allocation_depth = meta->exp->allocation_depth;
|
meta->allocation_depth = meta->exp->allocation_depth;
|
||||||
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
|
if (meta->exp->nr_export_bitmaps) {
|
||||||
|
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
trace_nbd_negotiate_meta_query_parse("empty");
|
trace_nbd_negotiate_meta_query_parse("empty");
|
||||||
return true;
|
return true;
|
||||||
@ -894,7 +896,8 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
|
|||||||
if (nbd_strshift(&query, "dirty-bitmap:")) {
|
if (nbd_strshift(&query, "dirty-bitmap:")) {
|
||||||
trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
|
trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
|
||||||
if (!*query) {
|
if (!*query) {
|
||||||
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
|
if (client->opt == NBD_OPT_LIST_META_CONTEXT &&
|
||||||
|
meta->exp->nr_export_bitmaps) {
|
||||||
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
|
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
|
||||||
}
|
}
|
||||||
trace_nbd_negotiate_meta_query_parse("empty");
|
trace_nbd_negotiate_meta_query_parse("empty");
|
||||||
@ -1024,7 +1027,9 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
|
|||||||
/* enable all known contexts */
|
/* enable all known contexts */
|
||||||
meta->base_allocation = true;
|
meta->base_allocation = true;
|
||||||
meta->allocation_depth = meta->exp->allocation_depth;
|
meta->allocation_depth = meta->exp->allocation_depth;
|
||||||
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
|
if (meta->exp->nr_export_bitmaps) {
|
||||||
|
memset(meta->bitmaps, 1, meta->exp->nr_export_bitmaps);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < nb_queries; ++i) {
|
for (i = 0; i < nb_queries; ++i) {
|
||||||
ret = nbd_negotiate_meta_query(client, meta, errp);
|
ret = nbd_negotiate_meta_query(client, meta, errp);
|
||||||
|
@ -209,7 +209,8 @@ static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
|
|||||||
|
|
||||||
pkt->tcp_seq = ntohl(tcphd->th_seq);
|
pkt->tcp_seq = ntohl(tcphd->th_seq);
|
||||||
pkt->tcp_ack = ntohl(tcphd->th_ack);
|
pkt->tcp_ack = ntohl(tcphd->th_ack);
|
||||||
*max_ack = *max_ack > pkt->tcp_ack ? *max_ack : pkt->tcp_ack;
|
/* Need to consider ACK will bigger than uint32_t MAX */
|
||||||
|
*max_ack = pkt->tcp_ack - *max_ack > 0 ? pkt->tcp_ack : *max_ack;
|
||||||
pkt->header_size = pkt->transport_header - (uint8_t *)pkt->data
|
pkt->header_size = pkt->transport_header - (uint8_t *)pkt->data
|
||||||
+ (tcphd->th_off << 2);
|
+ (tcphd->th_off << 2);
|
||||||
pkt->payload_size = pkt->size - pkt->header_size;
|
pkt->payload_size = pkt->size - pkt->header_size;
|
||||||
@ -413,7 +414,8 @@ static void colo_compare_tcp(CompareState *s, Connection *conn)
|
|||||||
* can ensure that the packet's payload is acknowledged by
|
* can ensure that the packet's payload is acknowledged by
|
||||||
* primary and secondary.
|
* primary and secondary.
|
||||||
*/
|
*/
|
||||||
uint32_t min_ack = conn->pack > conn->sack ? conn->sack : conn->pack;
|
uint32_t min_ack = conn->pack - conn->sack > 0 ?
|
||||||
|
conn->sack : conn->pack;
|
||||||
|
|
||||||
pri:
|
pri:
|
||||||
if (g_queue_is_empty(&conn->primary_list)) {
|
if (g_queue_is_empty(&conn->primary_list)) {
|
||||||
@ -805,7 +807,7 @@ static int compare_chr_send(CompareState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!size) {
|
if (!size) {
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = g_slice_new(SendEntry);
|
entry = g_slice_new(SendEntry);
|
||||||
|
@ -214,7 +214,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
|
|||||||
static int vhost_vdpa_get_max_queue_pairs(int fd, int *has_cvq, Error **errp)
|
static int vhost_vdpa_get_max_queue_pairs(int fd, int *has_cvq, Error **errp)
|
||||||
{
|
{
|
||||||
unsigned long config_size = offsetof(struct vhost_vdpa_config, buf);
|
unsigned long config_size = offsetof(struct vhost_vdpa_config, buf);
|
||||||
struct vhost_vdpa_config *config;
|
g_autofree struct vhost_vdpa_config *config = NULL;
|
||||||
__virtio16 *max_queue_pairs;
|
__virtio16 *max_queue_pairs;
|
||||||
uint64_t features;
|
uint64_t features;
|
||||||
int ret;
|
int ret;
|
||||||
@ -260,8 +260,12 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
|
|||||||
|
|
||||||
assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
|
assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
|
||||||
opts = &netdev->u.vhost_vdpa;
|
opts = &netdev->u.vhost_vdpa;
|
||||||
|
if (!opts->vhostdev) {
|
||||||
|
error_setg(errp, "vdpa character device not specified with vhostdev");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
vdpa_device_fd = qemu_open_old(opts->vhostdev, O_RDWR);
|
vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp);
|
||||||
if (vdpa_device_fd == -1) {
|
if (vdpa_device_fd == -1) {
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,11 @@ class ConnectError(AQMPError):
|
|||||||
self.exc: Exception = exc
|
self.exc: Exception = exc
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.error_message}: {self.exc!s}"
|
cause = str(self.exc)
|
||||||
|
if not cause:
|
||||||
|
# If there's no error string, use the exception name.
|
||||||
|
cause = exception_summary(self.exc)
|
||||||
|
return f"{self.error_message}: {cause}"
|
||||||
|
|
||||||
|
|
||||||
class StateError(AQMPError):
|
class StateError(AQMPError):
|
||||||
@ -623,13 +627,21 @@ class AsyncProtocol(Generic[T]):
|
|||||||
def _done(task: Optional['asyncio.Future[Any]']) -> bool:
|
def _done(task: Optional['asyncio.Future[Any]']) -> bool:
|
||||||
return task is not None and task.done()
|
return task is not None and task.done()
|
||||||
|
|
||||||
# NB: We can't rely on _bh_tasks being done() here, it may not
|
# Are we already in an error pathway? If either of the tasks are
|
||||||
# yet have had a chance to run and gather itself.
|
# already done, or if we have no tasks but a reader/writer; we
|
||||||
|
# must be.
|
||||||
|
#
|
||||||
|
# NB: We can't use _bh_tasks to check for premature task
|
||||||
|
# completion, because it may not yet have had a chance to run
|
||||||
|
# and gather itself.
|
||||||
tasks = tuple(filter(None, (self._writer_task, self._reader_task)))
|
tasks = tuple(filter(None, (self._writer_task, self._reader_task)))
|
||||||
error_pathway = _done(self._reader_task) or _done(self._writer_task)
|
error_pathway = _done(self._reader_task) or _done(self._writer_task)
|
||||||
|
if not tasks:
|
||||||
|
error_pathway |= bool(self._reader) or bool(self._writer)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try to flush the writer, if possible:
|
# Try to flush the writer, if possible.
|
||||||
|
# This *may* cause an error and force us over into the error path.
|
||||||
if not error_pathway:
|
if not error_pathway:
|
||||||
await self._bh_flush_writer()
|
await self._bh_flush_writer()
|
||||||
except BaseException as err:
|
except BaseException as err:
|
||||||
@ -639,7 +651,7 @@ class AsyncProtocol(Generic[T]):
|
|||||||
self.logger.debug("%s:\n%s\n", emsg, pretty_traceback())
|
self.logger.debug("%s:\n%s\n", emsg, pretty_traceback())
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
# Cancel any still-running tasks:
|
# Cancel any still-running tasks (Won't raise):
|
||||||
if self._writer_task is not None and not self._writer_task.done():
|
if self._writer_task is not None and not self._writer_task.done():
|
||||||
self.logger.debug("Cancelling writer task.")
|
self.logger.debug("Cancelling writer task.")
|
||||||
self._writer_task.cancel()
|
self._writer_task.cancel()
|
||||||
@ -652,7 +664,7 @@ class AsyncProtocol(Generic[T]):
|
|||||||
self.logger.debug("Waiting for tasks to complete ...")
|
self.logger.debug("Waiting for tasks to complete ...")
|
||||||
await asyncio.wait(tasks)
|
await asyncio.wait(tasks)
|
||||||
|
|
||||||
# Lastly, close the stream itself. (May raise):
|
# Lastly, close the stream itself. (*May raise*!):
|
||||||
await self._bh_close_stream(error_pathway)
|
await self._bh_close_stream(error_pathway)
|
||||||
self.logger.debug("Disconnected.")
|
self.logger.debug("Disconnected.")
|
||||||
|
|
||||||
|
@ -769,6 +769,10 @@
|
|||||||
# @reduced-phys-bits: number of bits in physical addresses that become
|
# @reduced-phys-bits: number of bits in physical addresses that become
|
||||||
# unavailable when SEV is enabled
|
# unavailable when SEV is enabled
|
||||||
#
|
#
|
||||||
|
# @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
|
||||||
|
# designated guest firmware page for measured boot
|
||||||
|
# with -kernel (default: false) (since 6.2)
|
||||||
|
#
|
||||||
# Since: 2.12
|
# Since: 2.12
|
||||||
##
|
##
|
||||||
{ 'struct': 'SevGuestProperties',
|
{ 'struct': 'SevGuestProperties',
|
||||||
@ -778,7 +782,8 @@
|
|||||||
'*policy': 'uint32',
|
'*policy': 'uint32',
|
||||||
'*handle': 'uint32',
|
'*handle': 'uint32',
|
||||||
'*cbitpos': 'uint32',
|
'*cbitpos': 'uint32',
|
||||||
'reduced-phys-bits': 'uint32' } }
|
'reduced-phys-bits': 'uint32',
|
||||||
|
'*kernel-hashes': 'bool' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @ObjectType:
|
# @ObjectType:
|
||||||
|
46
qemu-nbd.c
46
qemu-nbd.c
@ -47,6 +47,10 @@
|
|||||||
#include "trace/control.h"
|
#include "trace/control.h"
|
||||||
#include "qemu-version.h"
|
#include "qemu-version.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_SELINUX
|
||||||
|
#include <selinux/selinux.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#define HAVE_NBD_DEVICE 1
|
#define HAVE_NBD_DEVICE 1
|
||||||
#else
|
#else
|
||||||
@ -64,6 +68,7 @@
|
|||||||
#define QEMU_NBD_OPT_FORK 263
|
#define QEMU_NBD_OPT_FORK 263
|
||||||
#define QEMU_NBD_OPT_TLSAUTHZ 264
|
#define QEMU_NBD_OPT_TLSAUTHZ 264
|
||||||
#define QEMU_NBD_OPT_PID_FILE 265
|
#define QEMU_NBD_OPT_PID_FILE 265
|
||||||
|
#define QEMU_NBD_OPT_SELINUX_LABEL 266
|
||||||
|
|
||||||
#define MBR_SIZE 512
|
#define MBR_SIZE 512
|
||||||
|
|
||||||
@ -116,6 +121,9 @@ static void usage(const char *name)
|
|||||||
" --fork fork off the server process and exit the parent\n"
|
" --fork fork off the server process and exit the parent\n"
|
||||||
" once the server is running\n"
|
" once the server is running\n"
|
||||||
" --pid-file=PATH store the server's process ID in the given file\n"
|
" --pid-file=PATH store the server's process ID in the given file\n"
|
||||||
|
#ifdef CONFIG_SELINUX
|
||||||
|
" --selinux-label=LABEL set SELinux process label on listening socket\n"
|
||||||
|
#endif
|
||||||
#if HAVE_NBD_DEVICE
|
#if HAVE_NBD_DEVICE
|
||||||
"\n"
|
"\n"
|
||||||
"Kernel NBD client support:\n"
|
"Kernel NBD client support:\n"
|
||||||
@ -454,6 +462,7 @@ static const char *socket_activation_validate_opts(const char *device,
|
|||||||
const char *sockpath,
|
const char *sockpath,
|
||||||
const char *address,
|
const char *address,
|
||||||
const char *port,
|
const char *port,
|
||||||
|
const char *selinux,
|
||||||
bool list)
|
bool list)
|
||||||
{
|
{
|
||||||
if (device != NULL) {
|
if (device != NULL) {
|
||||||
@ -472,6 +481,10 @@ static const char *socket_activation_validate_opts(const char *device,
|
|||||||
return "TCP port number can't be set when using socket activation";
|
return "TCP port number can't be set when using socket activation";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selinux != NULL) {
|
||||||
|
return "SELinux label can't be set when using socket activation";
|
||||||
|
}
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
return "List mode is incompatible with socket activation";
|
return "List mode is incompatible with socket activation";
|
||||||
}
|
}
|
||||||
@ -534,6 +547,8 @@ int main(int argc, char **argv)
|
|||||||
{ "trace", required_argument, NULL, 'T' },
|
{ "trace", required_argument, NULL, 'T' },
|
||||||
{ "fork", no_argument, NULL, QEMU_NBD_OPT_FORK },
|
{ "fork", no_argument, NULL, QEMU_NBD_OPT_FORK },
|
||||||
{ "pid-file", required_argument, NULL, QEMU_NBD_OPT_PID_FILE },
|
{ "pid-file", required_argument, NULL, QEMU_NBD_OPT_PID_FILE },
|
||||||
|
{ "selinux-label", required_argument, NULL,
|
||||||
|
QEMU_NBD_OPT_SELINUX_LABEL },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
int ch;
|
int ch;
|
||||||
@ -560,6 +575,7 @@ int main(int argc, char **argv)
|
|||||||
int old_stderr = -1;
|
int old_stderr = -1;
|
||||||
unsigned socket_activation;
|
unsigned socket_activation;
|
||||||
const char *pid_file_name = NULL;
|
const char *pid_file_name = NULL;
|
||||||
|
const char *selinux_label = NULL;
|
||||||
BlockExportOptions *export_opts;
|
BlockExportOptions *export_opts;
|
||||||
|
|
||||||
#ifdef CONFIG_POSIX
|
#ifdef CONFIG_POSIX
|
||||||
@ -749,6 +765,9 @@ int main(int argc, char **argv)
|
|||||||
case QEMU_NBD_OPT_PID_FILE:
|
case QEMU_NBD_OPT_PID_FILE:
|
||||||
pid_file_name = optarg;
|
pid_file_name = optarg;
|
||||||
break;
|
break;
|
||||||
|
case QEMU_NBD_OPT_SELINUX_LABEL:
|
||||||
|
selinux_label = optarg;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,6 +807,7 @@ int main(int argc, char **argv)
|
|||||||
/* Using socket activation - check user didn't use -p etc. */
|
/* Using socket activation - check user didn't use -p etc. */
|
||||||
const char *err_msg = socket_activation_validate_opts(device, sockpath,
|
const char *err_msg = socket_activation_validate_opts(device, sockpath,
|
||||||
bindto, port,
|
bindto, port,
|
||||||
|
selinux_label,
|
||||||
list);
|
list);
|
||||||
if (err_msg != NULL) {
|
if (err_msg != NULL) {
|
||||||
error_report("%s", err_msg);
|
error_report("%s", err_msg);
|
||||||
@ -827,6 +847,18 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selinux_label) {
|
||||||
|
#ifdef CONFIG_SELINUX
|
||||||
|
if (sockpath == NULL && device == NULL) {
|
||||||
|
error_report("--selinux-label is not permitted without --socket");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
error_report("SELinux support not enabled in this binary");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
||||||
return qemu_nbd_client_list(saddr, tlscreds, bindto);
|
return qemu_nbd_client_list(saddr, tlscreds, bindto);
|
||||||
@ -940,6 +972,13 @@ int main(int argc, char **argv)
|
|||||||
} else {
|
} else {
|
||||||
backlog = MIN(shared, SOMAXCONN);
|
backlog = MIN(shared, SOMAXCONN);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_SELINUX
|
||||||
|
if (selinux_label && setsockcreatecon_raw(selinux_label) == -1) {
|
||||||
|
error_report("Cannot set SELinux socket create context to %s: %s",
|
||||||
|
selinux_label, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
||||||
if (qio_net_listener_open_sync(server, saddr, backlog,
|
if (qio_net_listener_open_sync(server, saddr, backlog,
|
||||||
&local_err) < 0) {
|
&local_err) < 0) {
|
||||||
@ -947,6 +986,13 @@ int main(int argc, char **argv)
|
|||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_SELINUX
|
||||||
|
if (selinux_label && setsockcreatecon_raw(NULL) == -1) {
|
||||||
|
error_report("Cannot clear SELinux socket create context: %s",
|
||||||
|
strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
size_t i;
|
size_t i;
|
||||||
/* See comment in check_socket_activation above. */
|
/* See comment in check_socket_activation above. */
|
||||||
|
@ -5189,7 +5189,7 @@ SRST
|
|||||||
-object secret,id=sec0,keyid=secmaster0,format=base64,\\
|
-object secret,id=sec0,keyid=secmaster0,format=base64,\\
|
||||||
data=$SECRET,iv=$(<iv.b64)
|
data=$SECRET,iv=$(<iv.b64)
|
||||||
|
|
||||||
``-object sev-guest,id=id,cbitpos=cbitpos,reduced-phys-bits=val,[sev-device=string,policy=policy,handle=handle,dh-cert-file=file,session-file=file]``
|
``-object sev-guest,id=id,cbitpos=cbitpos,reduced-phys-bits=val,[sev-device=string,policy=policy,handle=handle,dh-cert-file=file,session-file=file,kernel-hashes=on|off]``
|
||||||
Create a Secure Encrypted Virtualization (SEV) guest object,
|
Create a Secure Encrypted Virtualization (SEV) guest object,
|
||||||
which can be used to provide the guest memory encryption support
|
which can be used to provide the guest memory encryption support
|
||||||
on AMD processors.
|
on AMD processors.
|
||||||
@ -5229,6 +5229,10 @@ SRST
|
|||||||
session with the guest owner to negotiate keys used for
|
session with the guest owner to negotiate keys used for
|
||||||
attestation. The file must be encoded in base64.
|
attestation. The file must be encoded in base64.
|
||||||
|
|
||||||
|
The ``kernel-hashes`` adds the hashes of given kernel/initrd/
|
||||||
|
cmdline to a designated guest firmware page for measured Linux
|
||||||
|
boot with -kernel. The default is off. (Since 6.2)
|
||||||
|
|
||||||
e.g to launch a SEV guest
|
e.g to launch a SEV guest
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
51
scripts/ci/org.centos/stream/8/build-environment.yml
Normal file
51
scripts/ci/org.centos/stream/8/build-environment.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
- name: Installation of extra packages to build QEMU
|
||||||
|
hosts: all
|
||||||
|
tasks:
|
||||||
|
- name: Extra check for CentOS Stream 8
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/redhat-release
|
||||||
|
line: CentOS Stream release 8
|
||||||
|
state: present
|
||||||
|
check_mode: yes
|
||||||
|
register: centos_stream_8
|
||||||
|
|
||||||
|
- name: Enable PowerTools repo on CentOS Stream 8
|
||||||
|
ini_file:
|
||||||
|
path: /etc/yum.repos.d/CentOS-Stream-PowerTools.repo
|
||||||
|
section: powertools
|
||||||
|
option: enabled
|
||||||
|
value: "1"
|
||||||
|
when:
|
||||||
|
- ansible_facts['distribution'] == 'CentOS'
|
||||||
|
- ansible_facts['distribution_major_version'] == '8'
|
||||||
|
- centos_stream_8
|
||||||
|
|
||||||
|
- name: Install basic packages to build QEMU on CentOS Stream 8
|
||||||
|
dnf:
|
||||||
|
name:
|
||||||
|
- device-mapper-multipath-devel
|
||||||
|
- glusterfs-api-devel
|
||||||
|
- gnutls-devel
|
||||||
|
- libcap-ng-devel
|
||||||
|
- libcurl-devel
|
||||||
|
- libfdt-devel
|
||||||
|
- libiscsi-devel
|
||||||
|
- libpmem-devel
|
||||||
|
- librados-devel
|
||||||
|
- librbd-devel
|
||||||
|
- libseccomp-devel
|
||||||
|
- libssh-devel
|
||||||
|
- libxkbcommon-devel
|
||||||
|
- ninja-build
|
||||||
|
- numactl-devel
|
||||||
|
- python3-sphinx
|
||||||
|
- redhat-rpm-config
|
||||||
|
- snappy-devel
|
||||||
|
- spice-server-devel
|
||||||
|
- systemd-devel
|
||||||
|
state: present
|
||||||
|
when:
|
||||||
|
- ansible_facts['distribution'] == 'CentOS'
|
||||||
|
- ansible_facts['distribution_major_version'] == '8'
|
||||||
|
- centos_stream_8
|
208
scripts/ci/org.centos/stream/8/x86_64/configure
vendored
Executable file
208
scripts/ci/org.centos/stream/8/x86_64/configure
vendored
Executable file
@ -0,0 +1,208 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
#
|
||||||
|
# Configuration for QEMU based on CentOS Stream 8 x86_64 builds
|
||||||
|
#
|
||||||
|
# The "configure" command line is based on:
|
||||||
|
#
|
||||||
|
# https://git.centos.org/rpms/qemu-kvm/blob/c8s-stream-rhel/f/SPECS/qemu-kvm.spec
|
||||||
|
#
|
||||||
|
# But, because the SPEC file contains a number of conditionals and
|
||||||
|
# variable and expansions only available at RPM build time, this version
|
||||||
|
# was initially generated from an actual RPM build on an x86_64 platform.
|
||||||
|
#
|
||||||
|
# From that initial version, options that are required or are a
|
||||||
|
# consequence of non-upstream patches have been adapted. One example
|
||||||
|
# is "--without-default-devices" which is *not* present here, given
|
||||||
|
# that patches adding downstream specific devices are not available.
|
||||||
|
#
|
||||||
|
../configure \
|
||||||
|
--prefix="/usr" \
|
||||||
|
--libdir="/usr/lib64" \
|
||||||
|
--datadir="/usr/share" \
|
||||||
|
--sysconfdir="/etc" \
|
||||||
|
--interp-prefix=/usr/qemu-%M \
|
||||||
|
--localstatedir="/var" \
|
||||||
|
--docdir="/usr/share/doc" \
|
||||||
|
--libexecdir="/usr/libexec" \
|
||||||
|
--extra-ldflags="-Wl,--build-id -Wl,-z,relro -Wl,-z,now" \
|
||||||
|
--extra-cflags="-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection" \
|
||||||
|
--with-suffix="qemu-kvm" \
|
||||||
|
--firmwarepath=/usr/share/qemu-firmware \
|
||||||
|
--with-git=meson \
|
||||||
|
--with-git-submodules=update \
|
||||||
|
--target-list="x86_64-softmmu" \
|
||||||
|
--block-drv-rw-whitelist="qcow2,raw,file,host_device,nbd,iscsi,rbd,blkdebug,luks,null-co,nvme,copy-on-read,throttle,gluster" \
|
||||||
|
--audio-drv-list="" \
|
||||||
|
--block-drv-ro-whitelist="vmdk,vhdx,vpc,https,ssh" \
|
||||||
|
--with-coroutine=ucontext \
|
||||||
|
--with-git=git \
|
||||||
|
--tls-priority=@QEMU,SYSTEM \
|
||||||
|
--disable-attr \
|
||||||
|
--disable-auth-pam \
|
||||||
|
--disable-avx2 \
|
||||||
|
--disable-avx512f \
|
||||||
|
--disable-bochs \
|
||||||
|
--disable-bpf \
|
||||||
|
--disable-brlapi \
|
||||||
|
--disable-bsd-user \
|
||||||
|
--disable-bzip2 \
|
||||||
|
--disable-cap-ng \
|
||||||
|
--disable-capstone \
|
||||||
|
--disable-cfi \
|
||||||
|
--disable-cfi-debug \
|
||||||
|
--disable-cloop \
|
||||||
|
--disable-cocoa \
|
||||||
|
--disable-coroutine-pool \
|
||||||
|
--disable-crypto-afalg \
|
||||||
|
--disable-curl \
|
||||||
|
--disable-curses \
|
||||||
|
--disable-debug-info \
|
||||||
|
--disable-debug-mutex \
|
||||||
|
--disable-debug-tcg \
|
||||||
|
--disable-dmg \
|
||||||
|
--disable-docs \
|
||||||
|
--disable-fuse \
|
||||||
|
--disable-fuse-lseek \
|
||||||
|
--disable-gcrypt \
|
||||||
|
--disable-gio \
|
||||||
|
--disable-glusterfs \
|
||||||
|
--disable-gnutls \
|
||||||
|
--disable-gtk \
|
||||||
|
--disable-guest-agent \
|
||||||
|
--disable-guest-agent-msi \
|
||||||
|
--disable-hax \
|
||||||
|
--disable-hvf \
|
||||||
|
--disable-iconv \
|
||||||
|
--disable-kvm \
|
||||||
|
--disable-libdaxctl \
|
||||||
|
--disable-libiscsi \
|
||||||
|
--disable-libnfs \
|
||||||
|
--disable-libpmem \
|
||||||
|
--disable-libssh \
|
||||||
|
--disable-libudev \
|
||||||
|
--disable-libusb \
|
||||||
|
--disable-libxml2 \
|
||||||
|
--disable-linux-aio \
|
||||||
|
--disable-linux-io-uring \
|
||||||
|
--disable-linux-user \
|
||||||
|
--disable-live-block-migration \
|
||||||
|
--disable-lto \
|
||||||
|
--disable-lzfse \
|
||||||
|
--disable-lzo \
|
||||||
|
--disable-malloc-trim \
|
||||||
|
--disable-membarrier \
|
||||||
|
--disable-modules \
|
||||||
|
--disable-module-upgrades \
|
||||||
|
--disable-mpath \
|
||||||
|
--disable-multiprocess \
|
||||||
|
--disable-netmap \
|
||||||
|
--disable-nettle \
|
||||||
|
--disable-numa \
|
||||||
|
--disable-nvmm \
|
||||||
|
--disable-opengl \
|
||||||
|
--disable-parallels \
|
||||||
|
--disable-pie \
|
||||||
|
--disable-pvrdma \
|
||||||
|
--disable-qcow1 \
|
||||||
|
--disable-qed \
|
||||||
|
--disable-qom-cast-debug \
|
||||||
|
--disable-rbd \
|
||||||
|
--disable-rdma \
|
||||||
|
--disable-replication \
|
||||||
|
--disable-rng-none \
|
||||||
|
--disable-safe-stack \
|
||||||
|
--disable-sanitizers \
|
||||||
|
--disable-sdl \
|
||||||
|
--disable-sdl-image \
|
||||||
|
--disable-seccomp \
|
||||||
|
--disable-slirp-smbd \
|
||||||
|
--disable-smartcard \
|
||||||
|
--disable-snappy \
|
||||||
|
--disable-sparse \
|
||||||
|
--disable-spice \
|
||||||
|
--disable-strip \
|
||||||
|
--disable-system \
|
||||||
|
--disable-tcg \
|
||||||
|
--disable-tools \
|
||||||
|
--disable-tpm \
|
||||||
|
--disable-u2f \
|
||||||
|
--disable-usb-redir \
|
||||||
|
--disable-user \
|
||||||
|
--disable-vde \
|
||||||
|
--disable-vdi \
|
||||||
|
--disable-vhost-crypto \
|
||||||
|
--disable-vhost-kernel \
|
||||||
|
--disable-vhost-net \
|
||||||
|
--disable-vhost-scsi \
|
||||||
|
--disable-vhost-user \
|
||||||
|
--disable-vhost-user-blk-server \
|
||||||
|
--disable-vhost-vdpa \
|
||||||
|
--disable-vhost-vsock \
|
||||||
|
--disable-virglrenderer \
|
||||||
|
--disable-virtfs \
|
||||||
|
--disable-virtiofsd \
|
||||||
|
--disable-vnc \
|
||||||
|
--disable-vnc-jpeg \
|
||||||
|
--disable-vnc-png \
|
||||||
|
--disable-vnc-sasl \
|
||||||
|
--disable-vte \
|
||||||
|
--disable-vvfat \
|
||||||
|
--disable-werror \
|
||||||
|
--disable-whpx \
|
||||||
|
--disable-xen \
|
||||||
|
--disable-xen-pci-passthrough \
|
||||||
|
--disable-xfsctl \
|
||||||
|
--disable-xkbcommon \
|
||||||
|
--disable-zstd \
|
||||||
|
--enable-attr \
|
||||||
|
--enable-avx2 \
|
||||||
|
--enable-cap-ng \
|
||||||
|
--enable-capstone \
|
||||||
|
--enable-coroutine-pool \
|
||||||
|
--enable-curl \
|
||||||
|
--enable-debug-info \
|
||||||
|
--enable-docs \
|
||||||
|
--enable-fdt \
|
||||||
|
--enable-gcrypt \
|
||||||
|
--enable-glusterfs \
|
||||||
|
--enable-gnutls \
|
||||||
|
--enable-guest-agent \
|
||||||
|
--enable-iconv \
|
||||||
|
--enable-kvm \
|
||||||
|
--enable-libiscsi \
|
||||||
|
--enable-libpmem \
|
||||||
|
--enable-libssh \
|
||||||
|
--enable-libusb \
|
||||||
|
--enable-libudev \
|
||||||
|
--enable-linux-aio \
|
||||||
|
--enable-lzo \
|
||||||
|
--enable-malloc-trim \
|
||||||
|
--enable-modules \
|
||||||
|
--enable-mpath \
|
||||||
|
--enable-numa \
|
||||||
|
--enable-opengl \
|
||||||
|
--enable-pie \
|
||||||
|
--enable-rbd \
|
||||||
|
--enable-rdma \
|
||||||
|
--enable-seccomp \
|
||||||
|
--enable-snappy \
|
||||||
|
--enable-smartcard \
|
||||||
|
--enable-spice \
|
||||||
|
--enable-system \
|
||||||
|
--enable-tcg \
|
||||||
|
--enable-tools \
|
||||||
|
--enable-tpm \
|
||||||
|
--enable-trace-backend=dtrace \
|
||||||
|
--enable-usb-redir \
|
||||||
|
--enable-virtiofsd \
|
||||||
|
--enable-vhost-kernel \
|
||||||
|
--enable-vhost-net \
|
||||||
|
--enable-vhost-user \
|
||||||
|
--enable-vhost-user-blk-server \
|
||||||
|
--enable-vhost-vdpa \
|
||||||
|
--enable-vhost-vsock \
|
||||||
|
--enable-vnc \
|
||||||
|
--enable-vnc-png \
|
||||||
|
--enable-vnc-sasl \
|
||||||
|
--enable-werror \
|
||||||
|
--enable-xkbcommon
|
70
scripts/ci/org.centos/stream/8/x86_64/test-avocado
Executable file
70
scripts/ci/org.centos/stream/8/x86_64/test-avocado
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
#
|
||||||
|
# Runs a previously vetted list of tests, either marked explicitly for
|
||||||
|
# KVM and x86_64, or tests that are generic enough to be valid for all
|
||||||
|
# targets. Such a test list can be generated with:
|
||||||
|
#
|
||||||
|
# ./tests/venv/bin/avocado list --filter-by-tags-include-empty \
|
||||||
|
# --filter-by-tags-include-empty-key -t accel:kvm,arch:x86_64 \
|
||||||
|
# tests/avocado/
|
||||||
|
#
|
||||||
|
# This is almost the complete list of avocado based tests available at
|
||||||
|
# the time this was compile, with the following exceptions:
|
||||||
|
#
|
||||||
|
# * Require machine type "x-remote":
|
||||||
|
# - tests/avocado/multiprocess.py:Multiprocess.test_multiprocess_x86_64
|
||||||
|
#
|
||||||
|
# * Needs superuser privileges:
|
||||||
|
# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_pre_virtiofsd_set_up
|
||||||
|
# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_pre_launch_set_up
|
||||||
|
# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_post_launch_set_up
|
||||||
|
# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_post_mount_set_up
|
||||||
|
# - tests/avocado/virtiofs_submounts.py:VirtiofsSubmountsTest.test_two_runs
|
||||||
|
#
|
||||||
|
# * Requires display type "egl-headless":
|
||||||
|
# - tests/avocado/virtio-gpu.py:VirtioGPUx86.test_virtio_vga_virgl
|
||||||
|
# - tests/avocado/virtio-gpu.py:VirtioGPUx86.test_vhost_user_vga_virgl
|
||||||
|
#
|
||||||
|
# * Test is marked (unconditionally) to be skipped:
|
||||||
|
# - tests/avocado/virtio_check_params.py:VirtioMaxSegSettingsCheck.test_machine_types
|
||||||
|
#
|
||||||
|
make get-vm-images
|
||||||
|
./tests/venv/bin/avocado run \
|
||||||
|
--job-results-dir=tests/results/ \
|
||||||
|
tests/avocado/boot_linux.py:BootLinuxX8664.test_pc_i440fx_kvm \
|
||||||
|
tests/avocado/boot_linux.py:BootLinuxX8664.test_pc_q35_kvm \
|
||||||
|
tests/avocado/boot_linux_console.py:BootLinuxConsole.test_x86_64_pc \
|
||||||
|
tests/avocado/cpu_queries.py:QueryCPUModelExpansion.test \
|
||||||
|
tests/avocado/empty_cpu_model.py:EmptyCPUModel.test \
|
||||||
|
tests/avocado/hotplug_cpu.py:HotPlugCPU.test \
|
||||||
|
tests/avocado/info_usernet.py:InfoUsernet.test_hostfwd \
|
||||||
|
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu \
|
||||||
|
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_pt \
|
||||||
|
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_strict \
|
||||||
|
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_strict_cm \
|
||||||
|
tests/avocado/linux_initrd.py:LinuxInitrd.test_with_2gib_file_should_exit_error_msg_with_linux_v3_6 \
|
||||||
|
tests/avocado/linux_initrd.py:LinuxInitrd.test_with_2gib_file_should_work_with_linux_v4_16 \
|
||||||
|
tests/avocado/migration.py:Migration.test_migration_with_exec \
|
||||||
|
tests/avocado/migration.py:Migration.test_migration_with_tcp_localhost \
|
||||||
|
tests/avocado/migration.py:Migration.test_migration_with_unix \
|
||||||
|
tests/avocado/pc_cpu_hotplug_props.py:OmittedCPUProps.test_no_die_id \
|
||||||
|
tests/avocado/replay_kernel.py:ReplayKernelNormal.test_x86_64_pc \
|
||||||
|
tests/avocado/reverse_debugging.py:ReverseDebugging_X86_64.test_x86_64_pc \
|
||||||
|
tests/avocado/version.py:Version.test_qmp_human_info_version \
|
||||||
|
tests/avocado/virtio_version.py:VirtioVersionCheck.test_conventional_devs \
|
||||||
|
tests/avocado/virtio_version.py:VirtioVersionCheck.test_modern_only_devs \
|
||||||
|
tests/avocado/vnc.py:Vnc.test_change_password \
|
||||||
|
tests/avocado/vnc.py:Vnc.test_change_password_requires_a_password \
|
||||||
|
tests/avocado/vnc.py:Vnc.test_no_vnc \
|
||||||
|
tests/avocado/vnc.py:Vnc.test_no_vnc_change_password \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_4_0 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_4_1 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_set_4_0 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_unset_4_1 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_v1_4_0 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_v1_set_4_0 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_v2_4_0 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:CascadelakeArchCapabilities.test_v2_unset_4_1 \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:X86CPUModelAliases.test_4_0_alias_compatibility \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:X86CPUModelAliases.test_4_1_alias \
|
||||||
|
tests/avocado/x86_cpu_model_versions.py:X86CPUModelAliases.test_none_alias
|
17
scripts/ci/org.centos/stream/README
Normal file
17
scripts/ci/org.centos/stream/README
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
This directory contains scripts for generating a build of QEMU that
|
||||||
|
closely matches the CentOS Stream[1] builds of the qemu-kvm package.
|
||||||
|
|
||||||
|
To have the environment ready to configure, build QEMU and run tests,
|
||||||
|
please start with a CentOS Stream machine and:
|
||||||
|
|
||||||
|
* apply the generic "build-environment.yml" playbook located at
|
||||||
|
scripts/ci/setup
|
||||||
|
|
||||||
|
* apply the "build-environment.yml" in the directory following the
|
||||||
|
CentOS Stream version (such as "8").
|
||||||
|
|
||||||
|
This currently only covers CentOS Stream 8 environments and
|
||||||
|
packages[2].
|
||||||
|
|
||||||
|
[1] https://www.centos.org/centos-stream/
|
||||||
|
[2] https://git.centos.org/rpms/qemu-kvm/commits/c8s-stream-rhel
|
@ -114,3 +114,41 @@
|
|||||||
when:
|
when:
|
||||||
- ansible_facts['distribution'] == 'Ubuntu'
|
- ansible_facts['distribution'] == 'Ubuntu'
|
||||||
- ansible_facts['distribution_version'] == '20.04'
|
- ansible_facts['distribution_version'] == '20.04'
|
||||||
|
|
||||||
|
- name: Install basic packages to build QEMU on EL8
|
||||||
|
dnf:
|
||||||
|
# This list of packages start with tests/docker/dockerfiles/centos8.docker
|
||||||
|
# but only include files that are common to all distro variants and present
|
||||||
|
# in the standard repos (no add-ons)
|
||||||
|
name:
|
||||||
|
- bzip2
|
||||||
|
- bzip2-devel
|
||||||
|
- dbus-daemon
|
||||||
|
- diffutils
|
||||||
|
- gcc
|
||||||
|
- gcc-c++
|
||||||
|
- genisoimage
|
||||||
|
- gettext
|
||||||
|
- git
|
||||||
|
- glib2-devel
|
||||||
|
- libaio-devel
|
||||||
|
- libepoxy-devel
|
||||||
|
- libgcrypt-devel
|
||||||
|
- lzo-devel
|
||||||
|
- make
|
||||||
|
- mesa-libEGL-devel
|
||||||
|
- nettle-devel
|
||||||
|
- nmap-ncat
|
||||||
|
- perl-Test-Harness
|
||||||
|
- pixman-devel
|
||||||
|
- python36
|
||||||
|
- rdma-core-devel
|
||||||
|
- spice-glib-devel
|
||||||
|
- spice-server
|
||||||
|
- systemtap-sdt-devel
|
||||||
|
- tar
|
||||||
|
- zlib-devel
|
||||||
|
state: present
|
||||||
|
when:
|
||||||
|
- ansible_facts['distribution_file_variety'] == 'RedHat'
|
||||||
|
- ansible_facts['distribution_version'] == '8'
|
||||||
|
@ -36,6 +36,7 @@ from itertools import chain
|
|||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
|
||||||
from qemu.machine import QEMUMachine
|
from qemu.machine import QEMUMachine
|
||||||
|
from qemu.aqmp import ConnectError
|
||||||
|
|
||||||
logger = logging.getLogger('device-crash-test')
|
logger = logging.getLogger('device-crash-test')
|
||||||
dbg = logger.debug
|
dbg = logger.debug
|
||||||
@ -175,7 +176,6 @@ ERROR_RULE_LIST = [
|
|||||||
{'log':r"Multiple VT220 operator consoles are not supported"},
|
{'log':r"Multiple VT220 operator consoles are not supported"},
|
||||||
{'log':r"core 0 already populated"},
|
{'log':r"core 0 already populated"},
|
||||||
{'log':r"could not find stage1 bootloader"},
|
{'log':r"could not find stage1 bootloader"},
|
||||||
{'log':r"No '.*' bus found for device"},
|
|
||||||
|
|
||||||
# other exitcode=1 failures not listed above will just generate INFO messages:
|
# other exitcode=1 failures not listed above will just generate INFO messages:
|
||||||
{'exitcode':1, 'loglevel':logging.INFO},
|
{'exitcode':1, 'loglevel':logging.INFO},
|
||||||
@ -317,9 +317,7 @@ class QemuBinaryInfo(object):
|
|||||||
try:
|
try:
|
||||||
vm.launch()
|
vm.launch()
|
||||||
mi['runnable'] = True
|
mi['runnable'] = True
|
||||||
except KeyboardInterrupt:
|
except Exception:
|
||||||
raise
|
|
||||||
except:
|
|
||||||
dbg("exception trying to run binary=%s machine=%s", self.binary, machine, exc_info=sys.exc_info())
|
dbg("exception trying to run binary=%s machine=%s", self.binary, machine, exc_info=sys.exc_info())
|
||||||
dbg("log: %r", vm.get_log())
|
dbg("log: %r", vm.get_log())
|
||||||
mi['runnable'] = False
|
mi['runnable'] = False
|
||||||
@ -357,12 +355,12 @@ def checkOneCase(args, testcase):
|
|||||||
dbg("will launch QEMU: %s", cmdline)
|
dbg("will launch QEMU: %s", cmdline)
|
||||||
vm = QEMUMachine(binary=binary, args=args)
|
vm = QEMUMachine(binary=binary, args=args)
|
||||||
|
|
||||||
|
exc = None
|
||||||
exc_traceback = None
|
exc_traceback = None
|
||||||
try:
|
try:
|
||||||
vm.launch()
|
vm.launch()
|
||||||
except KeyboardInterrupt:
|
except Exception as this_exc:
|
||||||
raise
|
exc = this_exc
|
||||||
except:
|
|
||||||
exc_traceback = traceback.format_exc()
|
exc_traceback = traceback.format_exc()
|
||||||
dbg("Exception while running test case")
|
dbg("Exception while running test case")
|
||||||
finally:
|
finally:
|
||||||
@ -370,8 +368,9 @@ def checkOneCase(args, testcase):
|
|||||||
ec = vm.exitcode()
|
ec = vm.exitcode()
|
||||||
log = vm.get_log()
|
log = vm.get_log()
|
||||||
|
|
||||||
if exc_traceback is not None or ec != 0:
|
if exc is not None or ec != 0:
|
||||||
return {'exc_traceback':exc_traceback,
|
return {'exc': exc,
|
||||||
|
'exc_traceback':exc_traceback,
|
||||||
'exitcode':ec,
|
'exitcode':ec,
|
||||||
'log':log,
|
'log':log,
|
||||||
'testcase':testcase,
|
'testcase':testcase,
|
||||||
@ -459,6 +458,17 @@ def logFailure(f, level):
|
|||||||
for l in f['log'].strip().split('\n'):
|
for l in f['log'].strip().split('\n'):
|
||||||
logger.log(level, "log: %s", l)
|
logger.log(level, "log: %s", l)
|
||||||
logger.log(level, "exit code: %r", f['exitcode'])
|
logger.log(level, "exit code: %r", f['exitcode'])
|
||||||
|
|
||||||
|
# If the Exception is merely a QMP connect error,
|
||||||
|
# reduce the logging level for its traceback to
|
||||||
|
# improve visual clarity.
|
||||||
|
if isinstance(f.get('exc'), ConnectError):
|
||||||
|
logger.log(level, "%s.%s: %s",
|
||||||
|
type(f['exc']).__module__,
|
||||||
|
type(f['exc']).__qualname__,
|
||||||
|
str(f['exc']))
|
||||||
|
level = logging.DEBUG
|
||||||
|
|
||||||
if f['exc_traceback']:
|
if f['exc_traceback']:
|
||||||
logger.log(level, "exception:")
|
logger.log(level, "exception:")
|
||||||
for l in f['exc_traceback'].split('\n'):
|
for l in f['exc_traceback'].split('\n'):
|
||||||
@ -503,6 +513,12 @@ def main():
|
|||||||
lvl = logging.WARN
|
lvl = logging.WARN
|
||||||
logging.basicConfig(stream=sys.stdout, level=lvl, format='%(levelname)s: %(message)s')
|
logging.basicConfig(stream=sys.stdout, level=lvl, format='%(levelname)s: %(message)s')
|
||||||
|
|
||||||
|
if not args.debug:
|
||||||
|
# Async QMP, when in use, is chatty about connection failures.
|
||||||
|
# This script knowingly generates a ton of connection errors.
|
||||||
|
# Silence this logger.
|
||||||
|
logging.getLogger('qemu.aqmp.qmp_client').setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
fatal_failures = []
|
fatal_failures = []
|
||||||
wl_stats = {}
|
wl_stats = {}
|
||||||
skipped = 0
|
skipped = 0
|
||||||
|
@ -72,6 +72,7 @@ meson_options_help() {
|
|||||||
printf "%s\n" ' sdl SDL user interface'
|
printf "%s\n" ' sdl SDL user interface'
|
||||||
printf "%s\n" ' sdl-image SDL Image support for icons'
|
printf "%s\n" ' sdl-image SDL Image support for icons'
|
||||||
printf "%s\n" ' seccomp seccomp support'
|
printf "%s\n" ' seccomp seccomp support'
|
||||||
|
printf "%s\n" ' selinux SELinux support in qemu-nbd'
|
||||||
printf "%s\n" ' smartcard CA smartcard emulation support'
|
printf "%s\n" ' smartcard CA smartcard emulation support'
|
||||||
printf "%s\n" ' snappy snappy compression support'
|
printf "%s\n" ' snappy snappy compression support'
|
||||||
printf "%s\n" ' sparse sparse checker'
|
printf "%s\n" ' sparse sparse checker'
|
||||||
@ -215,6 +216,8 @@ _meson_option_parse() {
|
|||||||
--disable-sdl-image) printf "%s" -Dsdl_image=disabled ;;
|
--disable-sdl-image) printf "%s" -Dsdl_image=disabled ;;
|
||||||
--enable-seccomp) printf "%s" -Dseccomp=enabled ;;
|
--enable-seccomp) printf "%s" -Dseccomp=enabled ;;
|
||||||
--disable-seccomp) printf "%s" -Dseccomp=disabled ;;
|
--disable-seccomp) printf "%s" -Dseccomp=disabled ;;
|
||||||
|
--enable-selinux) printf "%s" -Dselinux=enabled ;;
|
||||||
|
--disable-selinux) printf "%s" -Dselinux=disabled ;;
|
||||||
--enable-slirp) printf "%s" -Dslirp=enabled ;;
|
--enable-slirp) printf "%s" -Dslirp=enabled ;;
|
||||||
--disable-slirp) printf "%s" -Dslirp=disabled ;;
|
--disable-slirp) printf "%s" -Dslirp=disabled ;;
|
||||||
--enable-slirp=*) quote_sh "-Dslirp=$2" ;;
|
--enable-slirp=*) quote_sh "-Dslirp=$2" ;;
|
||||||
|
@ -593,8 +593,8 @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
|
|||||||
if (prop) {
|
if (prop) {
|
||||||
dev->id = id;
|
dev->id = id;
|
||||||
} else {
|
} else {
|
||||||
g_free(id);
|
|
||||||
error_setg(errp, "Duplicate device ID '%s'", id);
|
error_setg(errp, "Duplicate device ID '%s'", id);
|
||||||
|
g_free(id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -937,7 +937,9 @@ void qmp_device_del(const char *id, Error **errp)
|
|||||||
{
|
{
|
||||||
DeviceState *dev = find_device_state(id, errp);
|
DeviceState *dev = find_device_state(id, errp);
|
||||||
if (dev != NULL) {
|
if (dev != NULL) {
|
||||||
if (dev->pending_deleted_event) {
|
if (dev->pending_deleted_event &&
|
||||||
|
(dev->pending_deleted_expires_ms == 0 ||
|
||||||
|
dev->pending_deleted_expires_ms > qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL))) {
|
||||||
error_setg(errp, "Device %s is already in the "
|
error_setg(errp, "Device %s is already in the "
|
||||||
"process of unplug", id);
|
"process of unplug", id);
|
||||||
return;
|
return;
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "exec/confidential-guest-support.h"
|
#include "exec/confidential-guest-support.h"
|
||||||
#include "hw/i386/pc.h"
|
#include "hw/i386/pc.h"
|
||||||
|
#include "exec/address-spaces.h"
|
||||||
|
|
||||||
#define TYPE_SEV_GUEST "sev-guest"
|
#define TYPE_SEV_GUEST "sev-guest"
|
||||||
OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
|
OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
|
||||||
@ -62,6 +63,7 @@ struct SevGuestState {
|
|||||||
char *session_file;
|
char *session_file;
|
||||||
uint32_t cbitpos;
|
uint32_t cbitpos;
|
||||||
uint32_t reduced_phys_bits;
|
uint32_t reduced_phys_bits;
|
||||||
|
bool kernel_hashes;
|
||||||
|
|
||||||
/* runtime state */
|
/* runtime state */
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
@ -109,9 +111,19 @@ typedef struct QEMU_PACKED SevHashTable {
|
|||||||
SevHashTableEntry cmdline;
|
SevHashTableEntry cmdline;
|
||||||
SevHashTableEntry initrd;
|
SevHashTableEntry initrd;
|
||||||
SevHashTableEntry kernel;
|
SevHashTableEntry kernel;
|
||||||
uint8_t padding[];
|
|
||||||
} SevHashTable;
|
} SevHashTable;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data encrypted by sev_encrypt_flash() must be padded to a multiple of
|
||||||
|
* 16 bytes.
|
||||||
|
*/
|
||||||
|
typedef struct QEMU_PACKED PaddedSevHashTable {
|
||||||
|
SevHashTable ht;
|
||||||
|
uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
|
||||||
|
} PaddedSevHashTable;
|
||||||
|
|
||||||
|
QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
|
||||||
|
|
||||||
static SevGuestState *sev_guest;
|
static SevGuestState *sev_guest;
|
||||||
static Error *sev_mig_blocker;
|
static Error *sev_mig_blocker;
|
||||||
|
|
||||||
@ -327,6 +339,20 @@ sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
|
|||||||
sev->sev_device = g_strdup(value);
|
sev->sev_device = g_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
SevGuestState *sev = SEV_GUEST(obj);
|
||||||
|
|
||||||
|
return sev->kernel_hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
|
||||||
|
{
|
||||||
|
SevGuestState *sev = SEV_GUEST(obj);
|
||||||
|
|
||||||
|
sev->kernel_hashes = value;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sev_guest_class_init(ObjectClass *oc, void *data)
|
sev_guest_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
@ -345,6 +371,11 @@ sev_guest_class_init(ObjectClass *oc, void *data)
|
|||||||
sev_guest_set_session_file);
|
sev_guest_set_session_file);
|
||||||
object_class_property_set_description(oc, "session-file",
|
object_class_property_set_description(oc, "session-file",
|
||||||
"guest owners session parameters (encoded with base64)");
|
"guest owners session parameters (encoded with base64)");
|
||||||
|
object_class_property_add_bool(oc, "kernel-hashes",
|
||||||
|
sev_guest_get_kernel_hashes,
|
||||||
|
sev_guest_set_kernel_hashes);
|
||||||
|
object_class_property_set_description(oc, "kernel-hashes",
|
||||||
|
"add kernel hashes to guest firmware for measured Linux boot");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1196,18 +1227,35 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
|
|||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
SevHashTableDescriptor *area;
|
SevHashTableDescriptor *area;
|
||||||
SevHashTable *ht;
|
SevHashTable *ht;
|
||||||
|
PaddedSevHashTable *padded_ht;
|
||||||
uint8_t cmdline_hash[HASH_SIZE];
|
uint8_t cmdline_hash[HASH_SIZE];
|
||||||
uint8_t initrd_hash[HASH_SIZE];
|
uint8_t initrd_hash[HASH_SIZE];
|
||||||
uint8_t kernel_hash[HASH_SIZE];
|
uint8_t kernel_hash[HASH_SIZE];
|
||||||
uint8_t *hashp;
|
uint8_t *hashp;
|
||||||
size_t hash_len = HASH_SIZE;
|
size_t hash_len = HASH_SIZE;
|
||||||
int aligned_len;
|
hwaddr mapped_len = sizeof(*padded_ht);
|
||||||
|
MemTxAttrs attrs = { 0 };
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only add the kernel hashes if the sev-guest configuration explicitly
|
||||||
|
* stated kernel-hashes=on.
|
||||||
|
*/
|
||||||
|
if (!sev_guest->kernel_hashes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
|
if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
|
||||||
error_setg(errp, "SEV: kernel specified but OVMF has no hash table guid");
|
error_setg(errp, "SEV: kernel specified but guest firmware "
|
||||||
|
"has no hashes table GUID");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
area = (SevHashTableDescriptor *)data;
|
area = (SevHashTableDescriptor *)data;
|
||||||
|
if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
|
||||||
|
error_setg(errp, "SEV: guest firmware hashes table area is invalid "
|
||||||
|
"(base=0x%x size=0x%x)", area->base, area->size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate hash of kernel command-line with the terminating null byte. If
|
* Calculate hash of kernel command-line with the terminating null byte. If
|
||||||
@ -1248,7 +1296,13 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
|
|||||||
* Populate the hashes table in the guest's memory at the OVMF-designated
|
* Populate the hashes table in the guest's memory at the OVMF-designated
|
||||||
* area for the SEV hashes table
|
* area for the SEV hashes table
|
||||||
*/
|
*/
|
||||||
ht = qemu_map_ram_ptr(NULL, area->base);
|
padded_ht = address_space_map(&address_space_memory, area->base,
|
||||||
|
&mapped_len, true, attrs);
|
||||||
|
if (!padded_ht || mapped_len != sizeof(*padded_ht)) {
|
||||||
|
error_setg(errp, "SEV: cannot map hashes table guest memory area");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ht = &padded_ht->ht;
|
||||||
|
|
||||||
ht->guid = sev_hash_table_header_guid;
|
ht->guid = sev_hash_table_header_guid;
|
||||||
ht->len = sizeof(*ht);
|
ht->len = sizeof(*ht);
|
||||||
@ -1265,18 +1319,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
|
|||||||
ht->kernel.len = sizeof(ht->kernel);
|
ht->kernel.len = sizeof(ht->kernel);
|
||||||
memcpy(ht->kernel.hash, kernel_hash, sizeof(ht->kernel.hash));
|
memcpy(ht->kernel.hash, kernel_hash, sizeof(ht->kernel.hash));
|
||||||
|
|
||||||
/* When calling sev_encrypt_flash, the length has to be 16 byte aligned */
|
/* zero the excess data so the measurement can be reliably calculated */
|
||||||
aligned_len = ROUND_UP(ht->len, 16);
|
memset(padded_ht->padding, 0, sizeof(padded_ht->padding));
|
||||||
if (aligned_len != ht->len) {
|
|
||||||
/* zero the excess data so the measurement can be reliably calculated */
|
if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht), errp) < 0) {
|
||||||
memset(ht->padding, 0, aligned_len - ht->len);
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sev_encrypt_flash((uint8_t *)ht, aligned_len, errp) < 0) {
|
address_space_unmap(&address_space_memory, padded_ht,
|
||||||
return false;
|
mapped_len, true, mapped_len);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -76,56 +76,6 @@ static bool hyper_needed(void *opaque)
|
|||||||
return riscv_has_ext(env, RVH);
|
return riscv_has_ext(env, RVH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool vector_needed(void *opaque)
|
|
||||||
{
|
|
||||||
RISCVCPU *cpu = opaque;
|
|
||||||
CPURISCVState *env = &cpu->env;
|
|
||||||
|
|
||||||
return riscv_has_ext(env, RVV);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool pointermasking_needed(void *opaque)
|
|
||||||
{
|
|
||||||
RISCVCPU *cpu = opaque;
|
|
||||||
CPURISCVState *env = &cpu->env;
|
|
||||||
|
|
||||||
return riscv_has_ext(env, RVJ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_vector = {
|
|
||||||
.name = "cpu/vector",
|
|
||||||
.version_id = 1,
|
|
||||||
.minimum_version_id = 1,
|
|
||||||
.needed = vector_needed,
|
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64),
|
|
||||||
VMSTATE_UINTTL(env.vxrm, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.vxsat, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.vl, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.vstart, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.vtype, RISCVCPU),
|
|
||||||
VMSTATE_END_OF_LIST()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pointermasking = {
|
|
||||||
.name = "cpu/pointer_masking",
|
|
||||||
.version_id = 1,
|
|
||||||
.minimum_version_id = 1,
|
|
||||||
.needed = pointermasking_needed,
|
|
||||||
.fields = (VMStateField[]) {
|
|
||||||
VMSTATE_UINTTL(env.mmte, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.mpmmask, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.mpmbase, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.spmmask, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.spmbase, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.upmmask, RISCVCPU),
|
|
||||||
VMSTATE_UINTTL(env.upmbase, RISCVCPU),
|
|
||||||
|
|
||||||
VMSTATE_END_OF_LIST()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const VMStateDescription vmstate_hyper = {
|
static const VMStateDescription vmstate_hyper = {
|
||||||
.name = "cpu/hyper",
|
.name = "cpu/hyper",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@ -164,6 +114,56 @@ static const VMStateDescription vmstate_hyper = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool vector_needed(void *opaque)
|
||||||
|
{
|
||||||
|
RISCVCPU *cpu = opaque;
|
||||||
|
CPURISCVState *env = &cpu->env;
|
||||||
|
|
||||||
|
return riscv_has_ext(env, RVV);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_vector = {
|
||||||
|
.name = "cpu/vector",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.needed = vector_needed,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64),
|
||||||
|
VMSTATE_UINTTL(env.vxrm, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.vxsat, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.vl, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.vstart, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.vtype, RISCVCPU),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool pointermasking_needed(void *opaque)
|
||||||
|
{
|
||||||
|
RISCVCPU *cpu = opaque;
|
||||||
|
CPURISCVState *env = &cpu->env;
|
||||||
|
|
||||||
|
return riscv_has_ext(env, RVJ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_pointermasking = {
|
||||||
|
.name = "cpu/pointer_masking",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.needed = pointermasking_needed,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINTTL(env.mmte, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.mpmmask, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.mpmbase, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.spmmask, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.spmbase, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.upmmask, RISCVCPU),
|
||||||
|
VMSTATE_UINTTL(env.upmbase, RISCVCPU),
|
||||||
|
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_riscv_cpu = {
|
const VMStateDescription vmstate_riscv_cpu = {
|
||||||
.name = "cpu",
|
.name = "cpu",
|
||||||
.version_id = 3,
|
.version_id = 3,
|
||||||
|
@ -674,11 +674,6 @@ QEMU_BUILD_BUG_ON(sizeof(SysIB) != 4096);
|
|||||||
#define SIGP_STAT_INVALID_ORDER 0x00000002UL
|
#define SIGP_STAT_INVALID_ORDER 0x00000002UL
|
||||||
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
|
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
|
||||||
|
|
||||||
/* SIGP SET ARCHITECTURE modes */
|
|
||||||
#define SIGP_MODE_ESA_S390 0
|
|
||||||
#define SIGP_MODE_Z_ARCH_TRANS_ALL_PSW 1
|
|
||||||
#define SIGP_MODE_Z_ARCH_TRANS_CUR_PSW 2
|
|
||||||
|
|
||||||
/* SIGP order code mask corresponding to bit positions 56-63 */
|
/* SIGP order code mask corresponding to bit positions 56-63 */
|
||||||
#define SIGP_ORDER_MASK 0x000000ff
|
#define SIGP_ORDER_MASK 0x000000ff
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -150,6 +150,9 @@ docker-image-debian-sparc64-cross: docker-image-debian10
|
|||||||
# The native build should never use the registry
|
# The native build should never use the registry
|
||||||
docker-image-debian-native: DOCKER_REGISTRY=
|
docker-image-debian-native: DOCKER_REGISTRY=
|
||||||
|
|
||||||
|
# base images should not add a local user
|
||||||
|
docker-image-debian10: NOUSER=1
|
||||||
|
docker-image-debian11: NOUSER=1
|
||||||
|
|
||||||
#
|
#
|
||||||
# The build rule for hexagon-cross is special in so far for most of
|
# The build rule for hexagon-cross is special in so far for most of
|
||||||
|
@ -51,6 +51,7 @@ ENV PACKAGES \
|
|||||||
libpng-devel \
|
libpng-devel \
|
||||||
librbd-devel \
|
librbd-devel \
|
||||||
libseccomp-devel \
|
libseccomp-devel \
|
||||||
|
libselinux-devel \
|
||||||
libslirp-devel \
|
libslirp-devel \
|
||||||
libssh-devel \
|
libssh-devel \
|
||||||
libtasn1-devel \
|
libtasn1-devel \
|
||||||
|
@ -8,6 +8,7 @@ ENV PACKAGES \
|
|||||||
gcc \
|
gcc \
|
||||||
git \
|
git \
|
||||||
libffi-devel.i686 \
|
libffi-devel.i686 \
|
||||||
|
libselinux-devel.i686 \
|
||||||
libtasn1-devel.i686 \
|
libtasn1-devel.i686 \
|
||||||
libzstd-devel.i686 \
|
libzstd-devel.i686 \
|
||||||
make \
|
make \
|
||||||
|
@ -53,6 +53,7 @@ ENV PACKAGES \
|
|||||||
libpng-devel \
|
libpng-devel \
|
||||||
librbd-devel \
|
librbd-devel \
|
||||||
libseccomp-devel \
|
libseccomp-devel \
|
||||||
|
libselinux-devel \
|
||||||
libslirp-devel \
|
libslirp-devel \
|
||||||
libssh-devel \
|
libssh-devel \
|
||||||
libtasn1-devel \
|
libtasn1-devel \
|
||||||
|
@ -55,6 +55,7 @@ ENV PACKAGES \
|
|||||||
libpulse-devel \
|
libpulse-devel \
|
||||||
librbd-devel \
|
librbd-devel \
|
||||||
libseccomp-devel \
|
libseccomp-devel \
|
||||||
|
libselinux-devel \
|
||||||
libspice-server-devel \
|
libspice-server-devel \
|
||||||
libssh-devel \
|
libssh-devel \
|
||||||
libtasn1-devel \
|
libtasn1-devel \
|
||||||
|
@ -60,6 +60,7 @@ ENV PACKAGES \
|
|||||||
libsdl2-dev \
|
libsdl2-dev \
|
||||||
libsdl2-image-dev \
|
libsdl2-image-dev \
|
||||||
libseccomp-dev \
|
libseccomp-dev \
|
||||||
|
libselinux-dev \
|
||||||
libsnappy-dev \
|
libsnappy-dev \
|
||||||
libspice-protocol-dev \
|
libspice-protocol-dev \
|
||||||
libspice-server-dev \
|
libspice-server-dev \
|
||||||
|
@ -60,6 +60,7 @@ ENV PACKAGES \
|
|||||||
libsdl2-dev \
|
libsdl2-dev \
|
||||||
libsdl2-image-dev \
|
libsdl2-image-dev \
|
||||||
libseccomp-dev \
|
libseccomp-dev \
|
||||||
|
libselinux-dev \
|
||||||
libslirp-dev \
|
libslirp-dev \
|
||||||
libsnappy-dev \
|
libsnappy-dev \
|
||||||
libspice-protocol-dev \
|
libspice-protocol-dev \
|
||||||
|
@ -251,7 +251,16 @@ class TestParallelOps(iotests.QMPTestCase):
|
|||||||
speed=1024)
|
speed=1024)
|
||||||
self.assert_qmp(result, 'return', {})
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
for job in pending_jobs:
|
# Do this in reverse: After unthrottling them, some jobs may finish
|
||||||
|
# before we have unthrottled all of them. This will drain their
|
||||||
|
# subgraph, and this will make jobs above them advance (despite those
|
||||||
|
# jobs on top being throttled). In the worst case, all jobs below the
|
||||||
|
# top one are finished before we can unthrottle it, and this makes it
|
||||||
|
# advance so far that it completes before we can unthrottle it - which
|
||||||
|
# results in an error.
|
||||||
|
# Starting from the top (i.e. in reverse) does not have this problem:
|
||||||
|
# When a job finishes, the ones below it are not advanced.
|
||||||
|
for job in reversed(pending_jobs):
|
||||||
result = self.vm.qmp('block-job-set-speed', device=job, speed=0)
|
result = self.vm.qmp('block-job-set-speed', device=job, speed=0)
|
||||||
self.assert_qmp(result, 'return', {})
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
|
@ -350,6 +350,35 @@ info block backing-file"
|
|||||||
|
|
||||||
echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache"
|
echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "--- Alignment after changing O_DIRECT ---"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Directly test the protocol level: Can unaligned requests succeed even if
|
||||||
|
# O_DIRECT was only enabled through a reopen and vice versa?
|
||||||
|
|
||||||
|
# Ensure image size is a multiple of the sector size (required for O_DIRECT)
|
||||||
|
$QEMU_IMG create -f file "$TEST_IMG" 1M | _filter_img_create
|
||||||
|
|
||||||
|
# And write some data (not strictly necessary, but it feels better to actually
|
||||||
|
# have something to be read)
|
||||||
|
$QEMU_IO -f file -c 'write 0 4096' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
$QEMU_IO --cache=writeback -f file $TEST_IMG <<EOF | _filter_qemu_io
|
||||||
|
read 42 42
|
||||||
|
reopen -o cache.direct=on
|
||||||
|
read 42 42
|
||||||
|
reopen -o cache.direct=off
|
||||||
|
read 42 42
|
||||||
|
EOF
|
||||||
|
$QEMU_IO --cache=none -f file $TEST_IMG <<EOF | _filter_qemu_io
|
||||||
|
read 42 42
|
||||||
|
reopen -o cache.direct=off
|
||||||
|
read 42 42
|
||||||
|
reopen -o cache.direct=on
|
||||||
|
read 42 42
|
||||||
|
EOF
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo "*** done"
|
echo "*** done"
|
||||||
rm -f $seq.full
|
rm -f $seq.full
|
||||||
|
@ -747,4 +747,22 @@ cache.no-flush=on on backing-file
|
|||||||
Cache mode: writeback
|
Cache mode: writeback
|
||||||
Cache mode: writeback, direct
|
Cache mode: writeback, direct
|
||||||
Cache mode: writeback, ignore flushes
|
Cache mode: writeback, ignore flushes
|
||||||
|
|
||||||
|
--- Alignment after changing O_DIRECT ---
|
||||||
|
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=file size=1048576
|
||||||
|
wrote 4096/4096 bytes at offset 0
|
||||||
|
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 42/42 bytes at offset 42
|
||||||
|
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 42/42 bytes at offset 42
|
||||||
|
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 42/42 bytes at offset 42
|
||||||
|
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 42/42 bytes at offset 42
|
||||||
|
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 42/42 bytes at offset 42
|
||||||
|
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 42/42 bytes at offset 42
|
||||||
|
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
*** done
|
*** done
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */
|
#define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */
|
||||||
#define MAX_CPUS 512 /* set the max CPUs supported by the machine as 512 */
|
#define MAX_CPUS 512 /* set the max CPUs supported by the machine as 512 */
|
||||||
|
|
||||||
|
#define SMP_MACHINE_NAME "TEST-SMP"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to define the generic 3-level CPU topology hierarchy
|
* Used to define the generic 3-level CPU topology hierarchy
|
||||||
* -sockets/cores/threads
|
* -sockets/cores/threads
|
||||||
@ -75,14 +77,6 @@ typedef struct SMPTestData {
|
|||||||
const char *expect_error;
|
const char *expect_error;
|
||||||
} SMPTestData;
|
} SMPTestData;
|
||||||
|
|
||||||
/* Type info of the tested machine */
|
|
||||||
static const TypeInfo smp_machine_info = {
|
|
||||||
.name = TYPE_MACHINE,
|
|
||||||
.parent = TYPE_OBJECT,
|
|
||||||
.class_size = sizeof(MachineClass),
|
|
||||||
.instance_size = sizeof(MachineState),
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List all the possible valid sub-collections of the generic 5
|
* List all the possible valid sub-collections of the generic 5
|
||||||
* topology parameters (i.e. cpus/maxcpus/sockets/cores/threads),
|
* topology parameters (i.e. cpus/maxcpus/sockets/cores/threads),
|
||||||
@ -315,13 +309,13 @@ static struct SMPTestData data_generic_invalid[] = {
|
|||||||
* should tweak the supported min CPUs to 2 for testing */
|
* should tweak the supported min CPUs to 2 for testing */
|
||||||
.config = SMP_CONFIG_GENERIC(T, 1, F, 0, F, 0, F, 0, F, 0),
|
.config = SMP_CONFIG_GENERIC(T, 1, F, 0, F, 0, F, 0, F, 0),
|
||||||
.expect_error = "Invalid SMP CPUs 1. The min CPUs supported "
|
.expect_error = "Invalid SMP CPUs 1. The min CPUs supported "
|
||||||
"by machine '(null)' is 2",
|
"by machine '" SMP_MACHINE_NAME "' is 2",
|
||||||
}, {
|
}, {
|
||||||
/* config: -smp 512
|
/* config: -smp 512
|
||||||
* should tweak the supported max CPUs to 511 for testing */
|
* should tweak the supported max CPUs to 511 for testing */
|
||||||
.config = SMP_CONFIG_GENERIC(T, 512, F, 0, F, 0, F, 0, F, 0),
|
.config = SMP_CONFIG_GENERIC(T, 512, F, 0, F, 0, F, 0, F, 0),
|
||||||
.expect_error = "Invalid SMP CPUs 512. The max CPUs supported "
|
.expect_error = "Invalid SMP CPUs 512. The max CPUs supported "
|
||||||
"by machine '(null)' is 511",
|
"by machine '" SMP_MACHINE_NAME "' is 511",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -480,14 +474,17 @@ static void unsupported_params_init(MachineClass *mc, SMPTestData *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the related machine properties before each sub-test */
|
static void machine_base_class_init(ObjectClass *oc, void *data)
|
||||||
static void smp_machine_class_init(MachineClass *mc)
|
|
||||||
{
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
mc->min_cpus = MIN_CPUS;
|
mc->min_cpus = MIN_CPUS;
|
||||||
mc->max_cpus = MAX_CPUS;
|
mc->max_cpus = MAX_CPUS;
|
||||||
|
|
||||||
mc->smp_props.prefer_sockets = true;
|
mc->smp_props.prefer_sockets = true;
|
||||||
mc->smp_props.dies_supported = false;
|
mc->smp_props.dies_supported = false;
|
||||||
|
|
||||||
|
mc->name = g_strdup(SMP_MACHINE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_generic(void)
|
static void test_generic(void)
|
||||||
@ -498,8 +495,6 @@ static void test_generic(void)
|
|||||||
SMPTestData *data = &(SMPTestData){{ }};
|
SMPTestData *data = &(SMPTestData){{ }};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
smp_machine_class_init(mc);
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
||||||
*data = data_generic_valid[i];
|
*data = data_generic_valid[i];
|
||||||
unsupported_params_init(mc, data);
|
unsupported_params_init(mc, data);
|
||||||
@ -512,7 +507,7 @@ static void test_generic(void)
|
|||||||
smp_parse_test(ms, data, true);
|
smp_parse_test(ms, data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the supported min CPUs and max CPUs */
|
/* Force invalid min CPUs and max CPUs */
|
||||||
mc->min_cpus = 2;
|
mc->min_cpus = 2;
|
||||||
mc->max_cpus = 511;
|
mc->max_cpus = 511;
|
||||||
|
|
||||||
@ -523,6 +518,10 @@ static void test_generic(void)
|
|||||||
smp_parse_test(ms, data, false);
|
smp_parse_test(ms, data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset the supported min CPUs and max CPUs */
|
||||||
|
mc->min_cpus = MIN_CPUS;
|
||||||
|
mc->max_cpus = MAX_CPUS;
|
||||||
|
|
||||||
object_unref(obj);
|
object_unref(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,7 +534,7 @@ static void test_with_dies(void)
|
|||||||
unsigned int num_dies = 2;
|
unsigned int num_dies = 2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
smp_machine_class_init(mc);
|
/* Force the SMP compat properties */
|
||||||
mc->smp_props.dies_supported = true;
|
mc->smp_props.dies_supported = true;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
||||||
@ -575,15 +574,30 @@ static void test_with_dies(void)
|
|||||||
smp_parse_test(ms, data, false);
|
smp_parse_test(ms, data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Restore the SMP compat properties */
|
||||||
|
mc->smp_props.dies_supported = false;
|
||||||
|
|
||||||
object_unref(obj);
|
object_unref(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Type info of the tested machine */
|
||||||
|
static const TypeInfo smp_machine_types[] = {
|
||||||
|
{
|
||||||
|
.name = TYPE_MACHINE,
|
||||||
|
.parent = TYPE_OBJECT,
|
||||||
|
.class_init = machine_base_class_init,
|
||||||
|
.class_size = sizeof(MachineClass),
|
||||||
|
.instance_size = sizeof(MachineState),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_TYPES(smp_machine_types)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
g_test_init(&argc, &argv, NULL);
|
|
||||||
|
|
||||||
module_call_init(MODULE_INIT_QOM);
|
module_call_init(MODULE_INIT_QOM);
|
||||||
type_register_static(&smp_machine_info);
|
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
g_test_add_func("/test-smp-parse/generic", test_generic);
|
g_test_add_func("/test-smp-parse/generic", test_generic);
|
||||||
g_test_add_func("/test-smp-parse/with_dies", test_with_dies);
|
g_test_add_func("/test-smp-parse/with_dies", test_with_dies);
|
||||||
|
@ -2,16 +2,24 @@
|
|||||||
|
|
||||||
.PHONY: vm-build-all vm-clean-all
|
.PHONY: vm-build-all vm-clean-all
|
||||||
|
|
||||||
|
HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m))
|
||||||
|
|
||||||
EFI_AARCH64 = $(wildcard $(BUILD_DIR)/pc-bios/edk2-aarch64-code.fd)
|
EFI_AARCH64 = $(wildcard $(BUILD_DIR)/pc-bios/edk2-aarch64-code.fd)
|
||||||
|
|
||||||
IMAGES := freebsd netbsd openbsd centos fedora haiku.x86_64
|
X86_IMAGES := freebsd netbsd openbsd centos fedora haiku.x86_64
|
||||||
ifneq ($(GENISOIMAGE),)
|
ifneq ($(GENISOIMAGE),)
|
||||||
IMAGES += ubuntu.i386 centos
|
X86_IMAGES += ubuntu.i386 centos
|
||||||
ifneq ($(EFI_AARCH64),)
|
ifneq ($(EFI_AARCH64),)
|
||||||
IMAGES += ubuntu.aarch64 centos.aarch64
|
ARM64_IMAGES += ubuntu.aarch64 centos.aarch64
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HOST_ARCH),x86_64)
|
||||||
|
IMAGES=$(X86_IMAGES) $(if $(USE_TCG),$(ARM64_IMAGES))
|
||||||
|
else ifeq ($(HOST_ARCH),aarch64)
|
||||||
|
IMAGES=$(ARM64_IMAGES) $(if $(USE_TCG),$(X86_IMAGES))
|
||||||
|
endif
|
||||||
|
|
||||||
IMAGES_DIR := $(HOME)/.cache/qemu-vm/images
|
IMAGES_DIR := $(HOME)/.cache/qemu-vm/images
|
||||||
IMAGE_FILES := $(patsubst %, $(IMAGES_DIR)/%.img, $(IMAGES))
|
IMAGE_FILES := $(patsubst %, $(IMAGES_DIR)/%.img, $(IMAGES))
|
||||||
|
|
||||||
@ -43,7 +51,7 @@ else
|
|||||||
endif
|
endif
|
||||||
@echo " vm-build-haiku.x86_64 - Build QEMU in Haiku VM"
|
@echo " vm-build-haiku.x86_64 - Build QEMU in Haiku VM"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " vm-build-all - Build QEMU in all VMs"
|
@echo " vm-build-all - Build QEMU in: $(IMAGES)"
|
||||||
@echo " vm-clean-all - Clean up VM images"
|
@echo " vm-clean-all - Clean up VM images"
|
||||||
@echo
|
@echo
|
||||||
@echo "For trouble-shooting:"
|
@echo "For trouble-shooting:"
|
||||||
@ -52,21 +60,22 @@ endif
|
|||||||
@echo
|
@echo
|
||||||
@echo "Special variables:"
|
@echo "Special variables:"
|
||||||
@echo " BUILD_TARGET=foo - Override the build target"
|
@echo " BUILD_TARGET=foo - Override the build target"
|
||||||
@echo " TARGET_LIST=a,b,c - Override target list in builds"
|
|
||||||
@echo ' EXTRA_CONFIGURE_OPTS="..."'
|
|
||||||
@echo " J=[0..9]* - Override the -jN parameter for make commands"
|
|
||||||
@echo " DEBUG=1 - Enable verbose output on host and interactive debugging"
|
@echo " DEBUG=1 - Enable verbose output on host and interactive debugging"
|
||||||
|
@echo ' EXTRA_CONFIGURE_OPTS="..." - Pass to configure step'
|
||||||
|
@echo " J=[0..9]* - Override the -jN parameter for make commands"
|
||||||
@echo " LOG_CONSOLE=1 - Log console to file in: ~/.cache/qemu-vm "
|
@echo " LOG_CONSOLE=1 - Log console to file in: ~/.cache/qemu-vm "
|
||||||
@echo " V=1 - Enable verbose ouput on host and guest commands"
|
@echo " USE_TCG=1 - Use TCG for cross-arch images"
|
||||||
@echo " QEMU_LOCAL=1 - Use QEMU binary local to this build."
|
|
||||||
@echo " QEMU=/path/to/qemu - Change path to QEMU binary"
|
@echo " QEMU=/path/to/qemu - Change path to QEMU binary"
|
||||||
@echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool"
|
|
||||||
ifeq ($(HAVE_PYTHON_YAML),yes)
|
ifeq ($(HAVE_PYTHON_YAML),yes)
|
||||||
@echo " QEMU_CONFIG=/path/conf.yml - Change path to VM configuration .yml file."
|
@echo " QEMU_CONFIG=/path/conf.yml - Change path to VM configuration .yml file."
|
||||||
else
|
else
|
||||||
@echo " (install python3-yaml to enable support for yaml file to configure a VM.)"
|
@echo " (install python3-yaml to enable support for yaml file to configure a VM.)"
|
||||||
endif
|
endif
|
||||||
@echo " See conf_example_*.yml for file format details."
|
@echo " See conf_example_*.yml for file format details."
|
||||||
|
@echo " QEMU_IMG=/path/to/qemu-img - Change path to qemu-img tool"
|
||||||
|
@echo " QEMU_LOCAL=1 - Use QEMU binary local to this build."
|
||||||
|
@echo " TARGET_LIST=a,b,c - Override target list in builds"
|
||||||
|
@echo " V=1 - Enable verbose ouput on host and guest commands"
|
||||||
|
|
||||||
vm-build-all: $(addprefix vm-build-, $(IMAGES))
|
vm-build-all: $(addprefix vm-build-, $(IMAGES))
|
||||||
|
|
||||||
|
@ -61,11 +61,13 @@ void tran_abort(Transaction *tran)
|
|||||||
{
|
{
|
||||||
TransactionAction *act, *next;
|
TransactionAction *act, *next;
|
||||||
|
|
||||||
QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
|
QSLIST_FOREACH(act, &tran->actions, entry) {
|
||||||
if (act->drv->abort) {
|
if (act->drv->abort) {
|
||||||
act->drv->abort(act->opaque);
|
act->drv->abort(act->opaque);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
|
||||||
if (act->drv->clean) {
|
if (act->drv->clean) {
|
||||||
act->drv->clean(act->opaque);
|
act->drv->clean(act->opaque);
|
||||||
}
|
}
|
||||||
@ -80,11 +82,13 @@ void tran_commit(Transaction *tran)
|
|||||||
{
|
{
|
||||||
TransactionAction *act, *next;
|
TransactionAction *act, *next;
|
||||||
|
|
||||||
QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
|
QSLIST_FOREACH(act, &tran->actions, entry) {
|
||||||
if (act->drv->commit) {
|
if (act->drv->commit) {
|
||||||
act->drv->commit(act->opaque);
|
act->drv->commit(act->opaque);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) {
|
||||||
if (act->drv->clean) {
|
if (act->drv->clean) {
|
||||||
act->drv->clean(act->opaque);
|
act->drv->clean(act->opaque);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user