Cross-merge networking fixes after downstream PR (net-6.17-rc7). No conflicts. Adjacent changes: drivers/net/ethernet/mellanox/mlx5/core/en/fs.h 9536fbe10c9d ("net/mlx5e: Add PSP steering in local NIC RX") 7601a0a46216 ("net/mlx5e: Add a miss level for ipsec crypto offload")
Unified · Split
| @@ -92,8 +92,12 @@ required: · 91 unmodified lines | ||
| 92 | 92 | anyOf: |
| 93 | 93 | - required: |
| 94 | 94 | - qcom,powered-remotely |
| 95 | + - num-channels | |
| 96 | + - qcom,num-ees | |
| 95 | 97 | - required: |
| 96 | 98 | - qcom,controlled-remotely |
| 99 | + - num-channels | |
| 100 | + - qcom,num-ees | |
| 97 | 101 | - required: |
| 98 | 102 | - clocks |
| 99 | 103 | - clock-names |
| @@ -47,21 +47,19 @@ properties: · 46 unmodified lines | ||
| 47 | 47 | const: 0 |
| 48 | 48 | |
| 49 | 49 | clocks: |
| 50 | + minItems: 1 | |
| 50 | 51 | maxItems: 3 |
| 51 | − description: Reference clocks for CP110; MG clock, MG Core clock, AXI clock | |
| 52 | 52 | |
| 53 | 53 | clock-names: |
| 54 | − items: | |
| 55 | − - const: mg_clk | |
| 56 | − - const: mg_core_clk | |
| 57 | − - const: axi_clk | |
| 54 | + minItems: 1 | |
| 55 | + maxItems: 3 | |
| 58 | 56 | |
| 59 | 57 | marvell,system-controller: |
| 60 | 58 | description: Phandle to the Marvell system controller (CP110 only) |
| 61 | 59 | $ref: /schemas/types.yaml#/definitions/phandle |
| 62 | 60 | |
| 63 | 61 | patternProperties: |
| 64 | − '^phy@[0-2]$': | |
| 62 | + '^phy@[0-5]$': | |
| 65 | 63 | description: A COMPHY lane child node |
| 66 | 64 | type: object |
| 67 | 65 | additionalProperties: false |
| @@ -69,10 +67,14 @@ patternProperties: · 1 unmodified line | ||
| 69 | 67 | properties: |
| 70 | 68 | reg: |
| 71 | 69 | description: COMPHY lane number |
| 70 | + maximum: 5 | |
| 72 | 71 | |
| 73 | 72 | '#phy-cells': |
| 74 | 73 | const: 1 |
| 75 | 74 | |
| 75 | + connector: | |
| 76 | + type: object | |
| 77 | + | |
| 76 | 78 | required: |
| 77 | 79 | - reg |
| 78 | 80 | - '#phy-cells' |
| @@ -91,13 +93,24 @@ allOf: · 12 unmodified lines | ||
| 91 | 93 | |
| 92 | 94 | then: |
| 93 | 95 | properties: |
| 94 | − clocks: false | |
| 95 | − clock-names: false | |
| 96 | + clocks: | |
| 97 | + maxItems: 1 | |
| 98 | + clock-names: | |
| 99 | + const: xtal | |
| 96 | 100 | |
| 97 | 101 | required: |
| 98 | 102 | - reg-names |
| 99 | 103 | |
| 100 | 104 | else: |
| 105 | + properties: | |
| 106 | + clocks: | |
| 107 | + minItems: 3 | |
| 108 | + clock-names: | |
| 109 | + items: | |
| 110 | + - const: mg_clk | |
| 111 | + - const: mg_core_clk | |
| 112 | + - const: axi_clk | |
| 113 | + | |
| 101 | 114 | required: |
| 102 | 115 | - marvell,system-controller |
| 103 | 116 | |
| @@ -176,6 +176,8 @@ allOf: · 175 unmodified lines | ||
| 176 | 176 | compatible: |
| 177 | 177 | contains: |
| 178 | 178 | enum: |
| 179 | + - qcom,sa8775p-qmp-gen4x2-pcie-phy | |
| 180 | + - qcom,sa8775p-qmp-gen4x4-pcie-phy | |
| 179 | 181 | - qcom,sc8280xp-qmp-gen3x1-pcie-phy |
| 180 | 182 | - qcom,sc8280xp-qmp-gen3x2-pcie-phy |
| 181 | 183 | - qcom,sc8280xp-qmp-gen3x4-pcie-phy |
| @@ -197,8 +199,6 @@ allOf: · 15 unmodified lines | ||
| 197 | 199 | contains: |
| 198 | 200 | enum: |
| 199 | 201 | - qcom,qcs8300-qmp-gen4x2-pcie-phy |
| 200 | − - qcom,sa8775p-qmp-gen4x2-pcie-phy | |
| 201 | − - qcom,sa8775p-qmp-gen4x4-pcie-phy | |
| 202 | 202 | then: |
| 203 | 203 | properties: |
| 204 | 204 | clocks: |
| @@ -48,7 +48,6 @@ allOf: · 47 unmodified lines | ||
| 48 | 48 | oneOf: |
| 49 | 49 | - required: [ clock-frequency ] |
| 50 | 50 | - required: [ clocks ] |
| 51 | − | |
| 52 | 51 | - if: |
| 53 | 52 | properties: |
| 54 | 53 | compatible: |
| @@ -60,12 +59,39 @@ allOf: · 5 unmodified lines | ||
| 60 | 59 | items: |
| 61 | 60 | - const: uartclk |
| 62 | 61 | - const: reg |
| 63 | − else: | |
| 62 | + - if: | |
| 63 | + properties: | |
| 64 | + compatible: | |
| 65 | + contains: | |
| 66 | + const: spacemit,k1-uart | |
| 67 | + then: | |
| 64 | 68 | properties: |
| 65 | 69 | clock-names: |
| 66 | 70 | items: |
| 67 | 71 | - const: core |
| 68 | 72 | - const: bus |
| 73 | + - if: | |
| 74 | + properties: | |
| 75 | + compatible: | |
| 76 | + contains: | |
| 77 | + enum: | |
| 78 | + - spacemit,k1-uart | |
| 79 | + - nxp,lpc1850-uart | |
| 80 | + then: | |
| 81 | + required: | |
| 82 | + - clocks | |
| 83 | + - clock-names | |
| 84 | + properties: | |
| 85 | + clocks: | |
| 86 | + minItems: 2 | |
| 87 | + clock-names: | |
| 88 | + minItems: 2 | |
| 89 | + else: | |
| 90 | + properties: | |
| 91 | + clocks: | |
| 92 | + maxItems: 1 | |
| 93 | + clock-names: | |
| 94 | + maxItems: 1 | |
| 69 | 95 | |
| 70 | 96 | properties: |
| 71 | 97 | compatible: |
| @@ -162,6 +188,9 @@ properties: · 90 unmodified lines | ||
| 162 | 188 | minItems: 1 |
| 163 | 189 | maxItems: 2 |
| 164 | 190 | oneOf: |
| 191 | + - enum: | |
| 192 | + - main | |
| 193 | + - uart | |
| 165 | 194 | - items: |
| 166 | 195 | - const: core |
| 167 | 196 | - const: bus |
| @@ -264,29 +293,6 @@ required: · 96 unmodified lines | ||
| 264 | 293 | - reg |
| 265 | 294 | - interrupts |
| 266 | 295 | |
| 267 | −if: | |
| 268 | − properties: | |
| 269 | − compatible: | |
| 270 | − contains: | |
| 271 | − enum: | |
| 272 | − - spacemit,k1-uart | |
| 273 | − - nxp,lpc1850-uart | |
| 274 | −then: | |
| 275 | − required: | |
| 276 | − - clocks | |
| 277 | − - clock-names | |
| 278 | − properties: | |
| 279 | − clocks: | |
| 280 | − minItems: 2 | |
| 281 | − clock-names: | |
| 282 | − minItems: 2 | |
| 283 | −else: | |
| 284 | − properties: | |
| 285 | − clocks: | |
| 286 | − maxItems: 1 | |
| 287 | − clock-names: | |
| 288 | − maxItems: 1 | |
| 289 | − | |
| 290 | 296 | unevaluatedProperties: false |
| 291 | 297 | |
| 292 | 298 | examples: |
| @@ -41,7 +41,7 @@ properties: · 40 unmodified lines | ||
| 41 | 41 | - const: dma_intr2 |
| 42 | 42 | |
| 43 | 43 | clocks: |
| 44 | − minItems: 1 | |
| 44 | + maxItems: 1 | |
| 45 | 45 | |
| 46 | 46 | clock-names: |
| 47 | 47 | const: sw_baud |
| @@ -575,8 +575,8 @@ operations: · 574 unmodified lines | ||
| 575 | 575 | - nat-dst |
| 576 | 576 | - timeout |
| 577 | 577 | - mark |
| 578 | − - counter-orig | |
| 579 | − - counter-reply | |
| 578 | + - counters-orig | |
| 579 | + - counters-reply | |
| 580 | 580 | - use |
| 581 | 581 | - id |
| 582 | 582 | - nat-dst |
| @@ -591,7 +591,6 @@ operations: · 8 unmodified lines | ||
| 591 | 591 | request: |
| 592 | 592 | value: 0x101 |
| 593 | 593 | attributes: |
| 594 | − - nfgen-family | |
| 595 | 594 | - mark |
| 596 | 595 | - filter |
| 597 | 596 | - status |
| @@ -608,8 +607,8 @@ operations: · 10 unmodified lines | ||
| 608 | 607 | - nat-dst |
| 609 | 608 | - timeout |
| 610 | 609 | - mark |
| 611 | − - counter-orig | |
| 612 | − - counter-reply | |
| 610 | + - counters-orig | |
| 611 | + - counters-reply | |
| 613 | 612 | - use |
| 614 | 613 | - id |
| 615 | 614 | - nat-dst |
| @@ -28,13 +28,13 @@ definitions: · 27 unmodified lines | ||
| 28 | 28 | traffic-patterns it can take a long time until the |
| 29 | 29 | MPTCP_EVENT_ESTABLISHED is sent. |
| 30 | 30 | Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, sport, |
| 31 | − dport, server-side. | |
| 31 | + dport, server-side, [flags]. | |
| 32 | 32 | - |
| 33 | 33 | name: established |
| 34 | 34 | doc: >- |
| 35 | 35 | A MPTCP connection is established (can start new subflows). |
| 36 | 36 | Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, sport, |
| 37 | − dport, server-side. | |
| 37 | + dport, server-side, [flags]. | |
| 38 | 38 | - |
| 39 | 39 | name: closed |
| 40 | 40 | doc: >- |
| @@ -7238,15 +7238,15 @@ F: include/linux/swiotlb.h · 7237 unmodified lines | ||
| 7238 | 7238 | F: kernel/dma/ |
| 7239 | 7239 | |
| 7240 | 7240 | DMA MAPPING HELPERS DEVICE DRIVER API [RUST] |
| 7241 | −M: Abdiel Janulgue <abdiel.janulgue@gmail.com> | |
| 7242 | 7241 | M: Danilo Krummrich <dakr@kernel.org> |
| 7242 | +R: Abdiel Janulgue <abdiel.janulgue@gmail.com> | |
| 7243 | 7243 | R: Daniel Almeida <daniel.almeida@collabora.com> |
| 7244 | 7244 | R: Robin Murphy <robin.murphy@arm.com> |
| 7245 | 7245 | R: Andreas Hindborg <a.hindborg@kernel.org> |
| 7246 | 7246 | L: rust-for-linux@vger.kernel.org |
| 7247 | 7247 | S: Supported |
| 7248 | 7248 | W: https://rust-for-linux.com |
| 7249 | −T: git https://github.com/Rust-for-Linux/linux.git alloc-next | |
| 7249 | +T: git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git | |
| 7250 | 7250 | F: rust/helpers/dma.c |
| 7251 | 7251 | F: rust/kernel/dma.rs |
| 7252 | 7252 | F: samples/rust/rust_dma.rs |
| @@ -7431,7 +7431,7 @@ S: Supported · 178 unmodified lines | ||
| 7431 | 7431 | F: Documentation/devicetree/bindings/dpll/dpll-device.yaml |
| 7432 | 7432 | F: Documentation/devicetree/bindings/dpll/dpll-pin.yaml |
| 7433 | 7433 | F: Documentation/driver-api/dpll.rst |
| 7434 | −F: drivers/dpll/* | |
| 7434 | +F: drivers/dpll/ | |
| 7435 | 7435 | F: include/linux/dpll.h |
| 7436 | 7436 | F: include/uapi/linux/dpll.h |
| 7437 | 7437 | |
| @@ -8079,7 +8079,6 @@ F: Documentation/devicetree/bindings/gpu/ · 641 unmodified lines | ||
| 8079 | 8079 | F: Documentation/gpu/ |
| 8080 | 8080 | F: drivers/gpu/drm/ |
| 8081 | 8081 | F: drivers/gpu/vga/ |
| 8082 | −F: rust/kernel/drm/ | |
| 8083 | 8082 | F: include/drm/drm |
| 8084 | 8083 | F: include/linux/vga* |
| 8085 | 8084 | F: include/uapi/drm/ |
| @@ -8091,11 +8090,21 @@ X: drivers/gpu/drm/i915/ · 5 unmodified lines | ||
| 8091 | 8090 | X: drivers/gpu/drm/kmb/ |
| 8092 | 8091 | X: drivers/gpu/drm/mediatek/ |
| 8093 | 8092 | X: drivers/gpu/drm/msm/ |
| 8094 | −X: drivers/gpu/drm/nouveau/ | |
| 8093 | +X: drivers/gpu/drm/nova/ | |
| 8095 | 8094 | X: drivers/gpu/drm/radeon/ |
| 8096 | 8095 | X: drivers/gpu/drm/tegra/ |
| 8097 | 8096 | X: drivers/gpu/drm/xe/ |
| 8098 | 8097 | |
| 8098 | +DRM DRIVERS AND COMMON INFRASTRUCTURE [RUST] | |
| 8099 | +M: Danilo Krummrich <dakr@kernel.org> | |
| 8100 | +M: Alice Ryhl <aliceryhl@google.com> | |
| 8101 | +S: Supported | |
| 8102 | +W: https://drm.pages.freedesktop.org/maintainer-tools/drm-rust.html | |
| 8103 | +T: git https://gitlab.freedesktop.org/drm/rust/kernel.git | |
| 8104 | +F: drivers/gpu/drm/nova/ | |
| 8105 | +F: drivers/gpu/nova-core/ | |
| 8106 | +F: rust/kernel/drm/ | |
| 8107 | + | |
| 8099 | 8108 | DRM DRIVERS FOR ALLWINNER A10 |
| 8100 | 8109 | M: Maxime Ripard <mripard@kernel.org> |
| 8101 | 8110 | M: Chen-Yu Tsai <wens@csie.org> |
| @@ -15738,13 +15747,6 @@ S: Supported · 7636 unmodified lines | ||
| 15738 | 15747 | W: http://www.melexis.com |
| 15739 | 15748 | F: drivers/iio/temperature/mlx90635.c |
| 15740 | 15749 | |
| 15741 | −MELFAS MIP4 TOUCHSCREEN DRIVER | |
| 15742 | −M: Sangwon Jee <jeesw@melfas.com> | |
| 15743 | −S: Supported | |
| 15744 | −W: http://www.melfas.com | |
| 15745 | −F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt | |
| 15746 | −F: drivers/input/touchscreen/melfas_mip4.c | |
| 15747 | − | |
| 15748 | 15750 | MELLANOX BLUEFIELD I2C DRIVER |
| 15749 | 15751 | M: Khalil Blaiech <kblaiech@nvidia.com> |
| 15750 | 15752 | M: Asmaa Mnebhi <asmaa@nvidia.com> |
| @@ -16193,6 +16195,7 @@ R: Rik van Riel <riel@surriel.com> · 442 unmodified lines | ||
| 16193 | 16195 | R: Liam R. Howlett <Liam.Howlett@oracle.com> |
| 16194 | 16196 | R: Vlastimil Babka <vbabka@suse.cz> |
| 16195 | 16197 | R: Harry Yoo <harry.yoo@oracle.com> |
| 16198 | +R: Jann Horn <jannh@google.com> | |
| 16196 | 16199 | L: linux-mm@kvack.org |
| 16197 | 16200 | S: Maintained |
| 16198 | 16201 | F: include/linux/rmap.h |
| @@ -16237,6 +16240,7 @@ R: Nico Pache <npache@redhat.com> · 38 unmodified lines | ||
| 16237 | 16240 | R: Ryan Roberts <ryan.roberts@arm.com> |
| 16238 | 16241 | R: Dev Jain <dev.jain@arm.com> |
| 16239 | 16242 | R: Barry Song <baohua@kernel.org> |
| 16243 | +R: Lance Yang <lance.yang@linux.dev> | |
| 16240 | 16244 | L: linux-mm@kvack.org |
| 16241 | 16245 | S: Maintained |
| 16242 | 16246 | W: http://www.linux-mm.org |
| @@ -24271,7 +24275,7 @@ F: Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml · 8028 unmodified lines | ||
| 24271 | 24275 | F: drivers/input/keyboard/sun4i-lradc-keys.c |
| 24272 | 24276 | |
| 24273 | 24277 | SUNDANCE NETWORK DRIVER |
| 24274 | −M: Denis Kirjanov <dkirjanov@suse.de> | |
| 24278 | +M: Denis Kirjanov <kirjanov@gmail.com> | |
| 24275 | 24279 | L: netdev@vger.kernel.org |
| 24276 | 24280 | S: Maintained |
| 24277 | 24281 | F: drivers/net/ethernet/dlink/sundance.c |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | VERSION = 6 |
| 3 | 3 | PATCHLEVEL = 17 |
| 4 | 4 | SUBLEVEL = 0 |
| 5 | −EXTRAVERSION = -rc5 | |
| 5 | +EXTRAVERSION = -rc6 | |
| 6 | 6 | NAME = Baby Opossum Posse |
| 7 | 7 | |
| 8 | 8 | # *DOCUMENTATION* |
| @@ -1369,6 +1369,7 @@ static inline bool kvm_system_needs_idmapped_vectors(void) · 1368 unmodified lines | ||
| 1369 | 1369 | } |
| 1370 | 1370 | |
| 1371 | 1371 | void kvm_init_host_debug_data(void); |
| 1372 | +void kvm_debug_init_vhe(void); | |
| 1372 | 1373 | void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu); |
| 1373 | 1374 | void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu); |
| 1374 | 1375 | void kvm_debug_set_guest_ownership(struct kvm_vcpu *vcpu); |
| @@ -355,11 +355,6 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke · 354 unmodified lines | ||
| 355 | 355 | return pteref; |
| 356 | 356 | } |
| 357 | 357 | |
| 358 | −static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref) | |
| 359 | −{ | |
| 360 | − return pteref; | |
| 361 | −} | |
| 362 | − | |
| 363 | 358 | static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker) |
| 364 | 359 | { |
| 365 | 360 | /* |
| @@ -389,11 +384,6 @@ static inline kvm_pte_t *kvm_dereference_pteref(struct kvm_pgtable_walker *walke · 23 unmodified lines | ||
| 389 | 384 | return rcu_dereference_check(pteref, !(walker->flags & KVM_PGTABLE_WALK_SHARED)); |
| 390 | 385 | } |
| 391 | 386 | |
| 392 | −static inline kvm_pte_t *kvm_dereference_pteref_raw(kvm_pteref_t pteref) | |
| 393 | −{ | |
| 394 | − return rcu_dereference_raw(pteref); | |
| 395 | −} | |
| 396 | − | |
| 397 | 387 | static inline int kvm_pgtable_walk_begin(struct kvm_pgtable_walker *walker) |
| 398 | 388 | { |
| 399 | 389 | if (walker->flags & KVM_PGTABLE_WALK_SHARED) |
| @@ -561,26 +551,6 @@ static inline int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2 · 161 unmodified lines | ||
| 561 | 551 | */ |
| 562 | 552 | void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt); |
| 563 | 553 | |
| 564 | −/** | |
| 565 | − * kvm_pgtable_stage2_destroy_range() - Destroy the unlinked range of addresses. | |
| 566 | − * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*(). | |
| 567 | − * @addr: Intermediate physical address at which to place the mapping. | |
| 568 | − * @size: Size of the mapping. | |
| 569 | − * | |
| 570 | − * The page-table is assumed to be unreachable by any hardware walkers prior | |
| 571 | − * to freeing and therefore no TLB invalidation is performed. | |
| 572 | − */ | |
| 573 | −void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, | |
| 574 | − u64 addr, u64 size); | |
| 575 | − | |
| 576 | −/** | |
| 577 | − * kvm_pgtable_stage2_destroy_pgd() - Destroy the PGD of guest stage-2 page-table. | |
| 578 | − * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init*(). | |
| 579 | − * | |
| 580 | − * It is assumed that the rest of the page-table is freed before this operation. | |
| 581 | − */ | |
| 582 | −void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt); | |
| 583 | − | |
| 584 | 554 | /** |
| 585 | 555 | * kvm_pgtable_stage2_free_unlinked() - Free an unlinked stage-2 paging structure. |
| 586 | 556 | * @mm_ops: Memory management callbacks. |
| @@ -179,9 +179,7 @@ struct pkvm_mapping { · 178 unmodified lines | ||
| 179 | 179 | |
| 180 | 180 | int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu, |
| 181 | 181 | struct kvm_pgtable_mm_ops *mm_ops); |
| 182 | −void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, | |
| 183 | − u64 addr, u64 size); | |
| 184 | −void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt); | |
| 182 | +void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt); | |
| 185 | 183 | int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys, |
| 186 | 184 | enum kvm_pgtable_prot prot, void *mc, |
| 187 | 185 | enum kvm_pgtable_walk_flags flags); |
| @@ -2113,8 +2113,10 @@ static void cpu_hyp_init_features(void) · 2112 unmodified lines | ||
| 2113 | 2113 | { |
| 2114 | 2114 | cpu_set_hyp_vector(); |
| 2115 | 2115 | |
| 2116 | − if (is_kernel_in_hyp_mode()) | |
| 2116 | + if (is_kernel_in_hyp_mode()) { | |
| 2117 | 2117 | kvm_timer_init_vhe(); |
| 2118 | + kvm_debug_init_vhe(); | |
| 2119 | + } | |
| 2118 | 2120 | |
| 2119 | 2121 | if (vgic_present) |
| 2120 | 2122 | kvm_vgic_init_cpu_hardware(); |
| @@ -96,6 +96,13 @@ void kvm_init_host_debug_data(void) · 95 unmodified lines | ||
| 96 | 96 | } |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | +void kvm_debug_init_vhe(void) | |
| 100 | +{ | |
| 101 | + /* Clear PMSCR_EL1.E{0,1}SPE which reset to UNKNOWN values. */ | |
| 102 | + if (SYS_FIELD_GET(ID_AA64DFR0_EL1, PMSVer, read_sysreg(id_aa64dfr0_el1))) | |
| 103 | + write_sysreg_el1(0, SYS_PMSCR); | |
| 104 | +} | |
| 105 | + | |
| 99 | 106 | /* |
| 100 | 107 | * Configures the 'external' MDSCR_EL1 value for the guest, i.e. when the host |
| 101 | 108 | * has taken over MDSCR_EL1. |
| @@ -138,6 +145,9 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu) · 36 unmodified lines | ||
| 138 | 145 | /* Must be called before kvm_vcpu_load_vhe() */ |
| 139 | 146 | KVM_BUG_ON(vcpu_get_flag(vcpu, SYSREGS_ON_CPU), vcpu->kvm); |
| 140 | 147 | |
| 148 | + if (has_vhe()) | |
| 149 | + *host_data_ptr(host_debug_state.mdcr_el2) = read_sysreg(mdcr_el2); | |
| 150 | + | |
| 141 | 151 | /* |
| 142 | 152 | * Determine which of the possible debug states we're in: |
| 143 | 153 | * |
| @@ -184,6 +194,9 @@ void kvm_vcpu_load_debug(struct kvm_vcpu *vcpu) · 40 unmodified lines | ||
| 184 | 194 | |
| 185 | 195 | void kvm_vcpu_put_debug(struct kvm_vcpu *vcpu) |
| 186 | 196 | { |
| 197 | + if (has_vhe()) | |
| 198 | + write_sysreg(*host_data_ptr(host_debug_state.mdcr_el2), mdcr_el2); | |
| 199 | + | |
| 187 | 200 | if (likely(!(vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP))) |
| 188 | 201 | return; |
| 189 | 202 | |
| @@ -431,9 +431,6 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu) · 430 unmodified lines | ||
| 431 | 431 | vcpu_set_flag(vcpu, PMUSERENR_ON_CPU); |
| 432 | 432 | } |
| 433 | 433 | |
| 434 | − *host_data_ptr(host_debug_state.mdcr_el2) = read_sysreg(mdcr_el2); | |
| 435 | − write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2); | |
| 436 | − | |
| 437 | 434 | if (cpus_have_final_cap(ARM64_HAS_HCX)) { |
| 438 | 435 | u64 hcrx = vcpu->arch.hcrx_el2; |
| 439 | 436 | if (is_nested_ctxt(vcpu)) { |
| @@ -454,8 +451,6 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu) · 14 unmodified lines | ||
| 454 | 451 | { |
| 455 | 452 | struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt); |
| 456 | 453 | |
| 457 | − write_sysreg(*host_data_ptr(host_debug_state.mdcr_el2), mdcr_el2); | |
| 458 | − | |
| 459 | 454 | write_sysreg(0, hstr_el2); |
| 460 | 455 | if (system_supports_pmuv3()) { |
| 461 | 456 | write_sysreg(ctxt_sys_reg(hctxt, PMUSERENR_EL0), pmuserenr_el0); |
| @@ -50,6 +50,10 @@ extern void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc); · 49 unmodified lines | ||
| 50 | 50 | static void __activate_traps(struct kvm_vcpu *vcpu) |
| 51 | 51 | { |
| 52 | 52 | ___activate_traps(vcpu, vcpu->arch.hcr_el2); |
| 53 | + | |
| 54 | + *host_data_ptr(host_debug_state.mdcr_el2) = read_sysreg(mdcr_el2); | |
| 55 | + write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2); | |
| 56 | + | |
| 53 | 57 | __activate_traps_common(vcpu); |
| 54 | 58 | __activate_cptr_traps(vcpu); |
| 55 | 59 | |
| @@ -93,6 +97,8 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu) · 37 unmodified lines | ||
| 93 | 97 | isb(); |
| 94 | 98 | } |
| 95 | 99 | |
| 100 | + write_sysreg(*host_data_ptr(host_debug_state.mdcr_el2), mdcr_el2); | |
| 101 | + | |
| 96 | 102 | __deactivate_traps_common(vcpu); |
| 97 | 103 | |
| 98 | 104 | write_sysreg_hcr(this_cpu_ptr(&kvm_init_params)->hcr_el2); |
| @@ -253,7 +253,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu) · 252 unmodified lines | ||
| 253 | 253 | |
| 254 | 254 | *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR); |
| 255 | 255 | *vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR); |
| 256 | − __vcpu_assign_sys_reg(vcpu, read_sysreg_el1(SYS_VBAR), VBAR_EL1); | |
| 256 | + __vcpu_assign_sys_reg(vcpu, VBAR_EL1, read_sysreg_el1(SYS_VBAR)); | |
| 257 | 257 | |
| 258 | 258 | kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC); |
| 259 | 259 | |
| @@ -1551,38 +1551,21 @@ static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx, · 1550 unmodified lines | ||
| 1551 | 1551 | return 0; |
| 1552 | 1552 | } |
| 1553 | 1553 | |
| 1554 | −void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, | |
| 1555 | − u64 addr, u64 size) | |
| 1554 | +void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) | |
| 1556 | 1555 | { |
| 1556 | + size_t pgd_sz; | |
| 1557 | 1557 | struct kvm_pgtable_walker walker = { |
| 1558 | 1558 | .cb = stage2_free_walker, |
| 1559 | 1559 | .flags = KVM_PGTABLE_WALK_LEAF | |
| 1560 | 1560 | KVM_PGTABLE_WALK_TABLE_POST, |
| 1561 | 1561 | }; |
| 1562 | 1562 | |
| 1563 | − WARN_ON(kvm_pgtable_walk(pgt, addr, size, &walker)); | |
| 1564 | −} | |
| 1565 | − | |
| 1566 | −void kvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt) | |
| 1567 | −{ | |
| 1568 | − size_t pgd_sz; | |
| 1569 | − | |
| 1563 | + WARN_ON(kvm_pgtable_walk(pgt, 0, BIT(pgt->ia_bits), &walker)); | |
| 1570 | 1564 | pgd_sz = kvm_pgd_pages(pgt->ia_bits, pgt->start_level) * PAGE_SIZE; |
| 1571 | − | |
| 1572 | − /* | |
| 1573 | − * Since the pgtable is unlinked at this point, and not shared with | |
| 1574 | − * other walkers, safely deference pgd with kvm_dereference_pteref_raw() | |
| 1575 | − */ | |
| 1576 | − pgt->mm_ops->free_pages_exact(kvm_dereference_pteref_raw(pgt->pgd), pgd_sz); | |
| 1565 | + pgt->mm_ops->free_pages_exact(kvm_dereference_pteref(&walker, pgt->pgd), pgd_sz); | |
| 1577 | 1566 | pgt->pgd = NULL; |
| 1578 | 1567 | } |
| 1579 | 1568 | |
| 1580 | −void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) | |
| 1581 | −{ | |
| 1582 | − kvm_pgtable_stage2_destroy_range(pgt, 0, BIT(pgt->ia_bits)); | |
| 1583 | − kvm_pgtable_stage2_destroy_pgd(pgt); | |
| 1584 | −} | |
| 1585 | − | |
| 1586 | 1569 | void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level) |
| 1587 | 1570 | { |
| 1588 | 1571 | kvm_pteref_t ptep = (kvm_pteref_t)pgtable; |
| @@ -904,38 +904,6 @@ static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type) · 903 unmodified lines | ||
| 904 | 904 | return 0; |
| 905 | 905 | } |
| 906 | 906 | |
| 907 | −/* | |
| 908 | − * Assume that @pgt is valid and unlinked from the KVM MMU to free the | |
| 909 | − * page-table without taking the kvm_mmu_lock and without performing any | |
| 910 | − * TLB invalidations. | |
| 911 | − * | |
| 912 | − * Also, the range of addresses can be large enough to cause need_resched | |
| 913 | − * warnings, for instance on CONFIG_PREEMPT_NONE kernels. Hence, invoke | |
| 914 | − * cond_resched() periodically to prevent hogging the CPU for a long time | |
| 915 | − * and schedule something else, if required. | |
| 916 | − */ | |
| 917 | −static void stage2_destroy_range(struct kvm_pgtable *pgt, phys_addr_t addr, | |
| 918 | − phys_addr_t end) | |
| 919 | −{ | |
| 920 | − u64 next; | |
| 921 | − | |
| 922 | − do { | |
| 923 | − next = stage2_range_addr_end(addr, end); | |
| 924 | − KVM_PGT_FN(kvm_pgtable_stage2_destroy_range)(pgt, addr, | |
| 925 | − next - addr); | |
| 926 | − if (next != end) | |
| 927 | − cond_resched(); | |
| 928 | − } while (addr = next, addr != end); | |
| 929 | −} | |
| 930 | − | |
| 931 | −static void kvm_stage2_destroy(struct kvm_pgtable *pgt) | |
| 932 | −{ | |
| 933 | − unsigned int ia_bits = VTCR_EL2_IPA(pgt->mmu->vtcr); | |
| 934 | − | |
| 935 | − stage2_destroy_range(pgt, 0, BIT(ia_bits)); | |
| 936 | − KVM_PGT_FN(kvm_pgtable_stage2_destroy_pgd)(pgt); | |
| 937 | −} | |
| 938 | − | |
| 939 | 907 | /** |
| 940 | 908 | * kvm_init_stage2_mmu - Initialise a S2 MMU structure |
| 941 | 909 | * @kvm: The pointer to the KVM structure |
| @@ -1012,7 +980,7 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t · 70 unmodified lines | ||
| 1012 | 980 | return 0; |
| 1013 | 981 | |
| 1014 | 982 | out_destroy_pgtable: |
| 1015 | − kvm_stage2_destroy(pgt); | |
| 983 | + KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt); | |
| 1016 | 984 | out_free_pgtable: |
| 1017 | 985 | kfree(pgt); |
| 1018 | 986 | return err; |
| @@ -1106,10 +1074,14 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu) · 87 unmodified lines | ||
| 1106 | 1074 | mmu->pgt = NULL; |
| 1107 | 1075 | free_percpu(mmu->last_vcpu_ran); |
| 1108 | 1076 | } |
| 1077 | + | |
| 1078 | + if (kvm_is_nested_s2_mmu(kvm, mmu)) | |
| 1079 | + kvm_init_nested_s2_mmu(mmu); | |
| 1080 | + | |
| 1109 | 1081 | write_unlock(&kvm->mmu_lock); |
| 1110 | 1082 | |
| 1111 | 1083 | if (pgt) { |
| 1112 | − kvm_stage2_destroy(pgt); | |
| 1084 | + KVM_PGT_FN(kvm_pgtable_stage2_destroy)(pgt); | |
| 1113 | 1085 | kfree(pgt); |
| 1114 | 1086 | } |
| 1115 | 1087 | } |
| @@ -1541,11 +1513,6 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, · 425 unmodified lines | ||
| 1541 | 1513 | exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu); |
| 1542 | 1514 | VM_BUG_ON(write_fault && exec_fault); |
| 1543 | 1515 | |
| 1544 | − if (fault_is_perm && !write_fault && !exec_fault) { | |
| 1545 | − kvm_err("Unexpected L2 read permission error\n"); | |
| 1546 | − return -EFAULT; | |
| 1547 | − } | |
| 1548 | − | |
| 1549 | 1516 | if (!is_protected_kvm_enabled()) |
| 1550 | 1517 | memcache = &vcpu->arch.mmu_page_cache; |
| 1551 | 1518 | else |
| @@ -847,7 +847,7 @@ static void kvm_invalidate_vncr_ipa(struct kvm *kvm, u64 start, u64 end) · 846 unmodified lines | ||
| 847 | 847 | |
| 848 | 848 | ipa_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift, |
| 849 | 849 | vt->wr.level)); |
| 850 | − ipa_start = vt->wr.pa & (ipa_size - 1); | |
| 850 | + ipa_start = vt->wr.pa & ~(ipa_size - 1); | |
| 851 | 851 | ipa_end = ipa_start + ipa_size; |
| 852 | 852 | |
| 853 | 853 | if (ipa_end <= start || ipa_start >= end) |
| @@ -887,7 +887,7 @@ static void invalidate_vncr_va(struct kvm *kvm, · 33 unmodified lines | ||
| 887 | 887 | |
| 888 | 888 | va_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift, |
| 889 | 889 | vt->wr.level)); |
| 890 | − va_start = vt->gva & (va_size - 1); | |
| 890 | + va_start = vt->gva & ~(va_size - 1); | |
| 891 | 891 | va_end = va_start + va_size; |
| 892 | 892 | |
| 893 | 893 | switch (scope->type) { |
| @@ -1276,7 +1276,7 @@ static bool kvm_vncr_tlb_lookup(struct kvm_vcpu *vcpu) · 382 unmodified lines | ||
| 1276 | 1276 | !(tcr & TCR_ASID16)) |
| 1277 | 1277 | asid &= GENMASK(7, 0); |
| 1278 | 1278 | |
| 1279 | − return asid != vt->wr.asid; | |
| 1279 | + return asid == vt->wr.asid; | |
| 1280 | 1280 | } |
| 1281 | 1281 | |
| 1282 | 1282 | return true; |
| @@ -316,16 +316,9 @@ static int __pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 start, u64 e · 315 unmodified lines | ||
| 316 | 316 | return 0; |
| 317 | 317 | } |
| 318 | 318 | |
| 319 | −void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt, | |
| 320 | − u64 addr, u64 size) | |
| 319 | +void pkvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) | |
| 321 | 320 | { |
| 322 | − __pkvm_pgtable_stage2_unmap(pgt, addr, addr + size); | |
| 323 | −} | |
| 324 | − | |
| 325 | −void pkvm_pgtable_stage2_destroy_pgd(struct kvm_pgtable *pgt) | |
| 326 | −{ | |
| 327 | − /* Expected to be called after all pKVM mappings have been released. */ | |
| 328 | − WARN_ON_ONCE(!RB_EMPTY_ROOT(&pgt->pkvm_mappings.rb_root)); | |
| 321 | + __pkvm_pgtable_stage2_unmap(pgt, 0, ~(0ULL)); | |
| 329 | 322 | } |
| 330 | 323 | |
| 331 | 324 | int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt, u64 addr, u64 size, |
| @@ -69,7 +69,7 @@ static int iter_mark_lpis(struct kvm *kvm) · 68 unmodified lines | ||
| 69 | 69 | int nr_lpis = 0; |
| 70 | 70 | |
| 71 | 71 | xa_for_each(&dist->lpi_xa, intid, irq) { |
| 72 | − if (!vgic_try_get_irq_kref(irq)) | |
| 72 | + if (!vgic_try_get_irq_ref(irq)) | |
| 73 | 73 | continue; |
| 74 | 74 | |
| 75 | 75 | xa_set_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER); |
| @@ -53,7 +53,7 @@ void kvm_vgic_early_init(struct kvm *kvm) · 52 unmodified lines | ||
| 53 | 53 | { |
| 54 | 54 | struct vgic_dist *dist = &kvm->arch.vgic; |
| 55 | 55 | |
| 56 | − xa_init_flags(&dist->lpi_xa, XA_FLAGS_LOCK_IRQ); | |
| 56 | + xa_init(&dist->lpi_xa); | |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | /* CREATION */ |
| @@ -208,7 +208,7 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis) · 148 unmodified lines | ||
| 208 | 208 | raw_spin_lock_init(&irq->irq_lock); |
| 209 | 209 | irq->vcpu = NULL; |
| 210 | 210 | irq->target_vcpu = vcpu0; |
| 211 | − kref_init(&irq->refcount); | |
| 211 | + refcount_set(&irq->refcount, 0); | |
| 212 | 212 | switch (dist->vgic_model) { |
| 213 | 213 | case KVM_DEV_TYPE_ARM_VGIC_V2: |
| 214 | 214 | irq->targets = 0; |
| @@ -277,7 +277,7 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type) · 62 unmodified lines | ||
| 277 | 277 | irq->intid = i; |
| 278 | 278 | irq->vcpu = NULL; |
| 279 | 279 | irq->target_vcpu = vcpu; |
| 280 | − kref_init(&irq->refcount); | |
| 280 | + refcount_set(&irq->refcount, 0); | |
| 281 | 281 | if (vgic_irq_is_sgi(i)) { |
| 282 | 282 | /* SGIs */ |
| 283 | 283 | irq->enabled = 1; |
| @@ -78,7 +78,6 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, · 77 unmodified lines | ||
| 78 | 78 | { |
| 79 | 79 | struct vgic_dist *dist = &kvm->arch.vgic; |
| 80 | 80 | struct vgic_irq *irq = vgic_get_irq(kvm, intid), *oldirq; |
| 81 | − unsigned long flags; | |
| 82 | 81 | int ret; |
| 83 | 82 | |
| 84 | 83 | /* In this case there is no put, since we keep the reference. */ |
| @@ -89,7 +88,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, · 4 unmodified lines | ||
| 89 | 88 | if (!irq) |
| 90 | 89 | return ERR_PTR(-ENOMEM); |
| 91 | 90 | |
| 92 | − ret = xa_reserve_irq(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT); | |
| 91 | + ret = xa_reserve(&dist->lpi_xa, intid, GFP_KERNEL_ACCOUNT); | |
| 93 | 92 | if (ret) { |
| 94 | 93 | kfree(irq); |
| 95 | 94 | return ERR_PTR(ret); |
| @@ -99,19 +98,19 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, · 3 unmodified lines | ||
| 99 | 98 | raw_spin_lock_init(&irq->irq_lock); |
| 100 | 99 | |
| 101 | 100 | irq->config = VGIC_CONFIG_EDGE; |
| 102 | − kref_init(&irq->refcount); | |
| 101 | + refcount_set(&irq->refcount, 1); | |
| 103 | 102 | irq->intid = intid; |
| 104 | 103 | irq->target_vcpu = vcpu; |
| 105 | 104 | irq->group = 1; |
| 106 | 105 | |
| 107 | − xa_lock_irqsave(&dist->lpi_xa, flags); | |
| 106 | + xa_lock(&dist->lpi_xa); | |
| 108 | 107 | |
| 109 | 108 | /* |
| 110 | 109 | * There could be a race with another vgic_add_lpi(), so we need to |
| 111 | 110 | * check that we don't add a second list entry with the same LPI. |
| 112 | 111 | */ |
| 113 | 112 | oldirq = xa_load(&dist->lpi_xa, intid); |
| 114 | − if (vgic_try_get_irq_kref(oldirq)) { | |
| 113 | + if (vgic_try_get_irq_ref(oldirq)) { | |
| 115 | 114 | /* Someone was faster with adding this LPI, lets use that. */ |
| 116 | 115 | kfree(irq); |
| 117 | 116 | irq = oldirq; |
| @@ -126,7 +125,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, · 8 unmodified lines | ||
| 126 | 125 | } |
| 127 | 126 | |
| 128 | 127 | out_unlock: |
| 129 | − xa_unlock_irqrestore(&dist->lpi_xa, flags); | |
| 128 | + xa_unlock(&dist->lpi_xa); | |
| 130 | 129 | |
| 131 | 130 | if (ret) |
| 132 | 131 | return ERR_PTR(ret); |
| @@ -547,7 +546,7 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db, · 414 unmodified lines | ||
| 547 | 546 | rcu_read_lock(); |
| 548 | 547 | |
| 549 | 548 | irq = xa_load(&its->translation_cache, cache_key); |
| 550 | − if (!vgic_try_get_irq_kref(irq)) | |
| 549 | + if (!vgic_try_get_irq_ref(irq)) | |
| 551 | 550 | irq = NULL; |
| 552 | 551 | |
| 553 | 552 | rcu_read_unlock(); |
| @@ -571,7 +570,7 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its, · 17 unmodified lines | ||
| 571 | 570 | * its_lock, as the ITE (and the reference it holds) cannot be freed. |
| 572 | 571 | */ |
| 573 | 572 | lockdep_assert_held(&its->its_lock); |
| 574 | − vgic_get_irq_kref(irq); | |
| 573 | + vgic_get_irq_ref(irq); | |
| 575 | 574 | |
| 576 | 575 | old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT); |
| 577 | 576 | |
| @@ -518,7 +518,7 @@ static struct vgic_irq *__vgic_host_irq_get_vlpi(struct kvm *kvm, int host_irq) · 517 unmodified lines | ||
| 518 | 518 | if (!irq->hw || irq->host_irq != host_irq) |
| 519 | 519 | continue; |
| 520 | 520 | |
| 521 | − if (!vgic_try_get_irq_kref(irq)) | |
| 521 | + if (!vgic_try_get_irq_ref(irq)) | |
| 522 | 522 | return NULL; |
| 523 | 523 | |
| 524 | 524 | return irq; |
| @@ -28,8 +28,8 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = { · 27 unmodified lines | ||
| 28 | 28 | * kvm->arch.config_lock (mutex) |
| 29 | 29 | * its->cmd_lock (mutex) |
| 30 | 30 | * its->its_lock (mutex) |
| 31 | − * vgic_cpu->ap_list_lock must be taken with IRQs disabled | |
| 32 | − * vgic_dist->lpi_xa.xa_lock must be taken with IRQs disabled | |
| 31 | + * vgic_dist->lpi_xa.xa_lock | |
| 32 | + * vgic_cpu->ap_list_lock must be taken with IRQs disabled | |
| 33 | 33 | * vgic_irq->irq_lock must be taken with IRQs disabled |
| 34 | 34 | * |
| 35 | 35 | * As the ap_list_lock might be taken from the timer interrupt handler, |
| @@ -71,7 +71,7 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid) · 35 unmodified lines | ||
| 71 | 71 | rcu_read_lock(); |
| 72 | 72 | |
| 73 | 73 | irq = xa_load(&dist->lpi_xa, intid); |
| 74 | − if (!vgic_try_get_irq_kref(irq)) | |
| 74 | + if (!vgic_try_get_irq_ref(irq)) | |
| 75 | 75 | irq = NULL; |
| 76 | 76 | |
| 77 | 77 | rcu_read_unlock(); |
| @@ -114,37 +114,66 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid) · 36 unmodified lines | ||
| 114 | 114 | return vgic_get_irq(vcpu->kvm, intid); |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | −/* | |
| 118 | − * We can't do anything in here, because we lack the kvm pointer to | |
| 119 | − * lock and remove the item from the lpi_list. So we keep this function | |
| 120 | − * empty and use the return value of kref_put() to trigger the freeing. | |
| 121 | − */ | |
| 122 | −static void vgic_irq_release(struct kref *ref) | |
| 117 | +static void vgic_release_lpi_locked(struct vgic_dist *dist, struct vgic_irq *irq) | |
| 118 | +{ | |
| 119 | + lockdep_assert_held(&dist->lpi_xa.xa_lock); | |
| 120 | + __xa_erase(&dist->lpi_xa, irq->intid); | |
| 121 | + kfree_rcu(irq, rcu); | |
| 122 | +} | |
| 123 | + | |
| 124 | +static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) | |
| 125 | +{ | |
| 126 | + if (irq->intid < VGIC_MIN_LPI) | |
| 127 | + return false; | |
| 128 | + | |
| 129 | + return refcount_dec_and_test(&irq->refcount); | |
| 130 | +} | |
| 131 | + | |
| 132 | +static __must_check bool vgic_put_irq_norelease(struct kvm *kvm, struct vgic_irq *irq) | |
| 123 | 133 | { |
| 134 | + if (!__vgic_put_irq(kvm, irq)) | |
| 135 | + return false; | |
| 136 | + | |
| 137 | + irq->pending_release = true; | |
| 138 | + return true; | |
| 124 | 139 | } |
| 125 | 140 | |
| 126 | 141 | void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) |
| 127 | 142 | { |
| 128 | 143 | struct vgic_dist *dist = &kvm->arch.vgic; |
| 129 | − unsigned long flags; | |
| 130 | 144 | |
| 131 | − if (irq->intid < VGIC_MIN_LPI) | |
| 132 | − return; | |
| 145 | + if (irq->intid >= VGIC_MIN_LPI) | |
| 146 | + might_lock(&dist->lpi_xa.xa_lock); | |
| 133 | 147 | |
| 134 | − if (!kref_put(&irq->refcount, vgic_irq_release)) | |
| 148 | + if (!__vgic_put_irq(kvm, irq)) | |
| 135 | 149 | return; |
| 136 | 150 | |
| 137 | − xa_lock_irqsave(&dist->lpi_xa, flags); | |
| 138 | − __xa_erase(&dist->lpi_xa, irq->intid); | |
| 139 | − xa_unlock_irqrestore(&dist->lpi_xa, flags); | |
| 151 | + xa_lock(&dist->lpi_xa); | |
| 152 | + vgic_release_lpi_locked(dist, irq); | |
| 153 | + xa_unlock(&dist->lpi_xa); | |
| 154 | +} | |
| 140 | 155 | |
| 141 | − kfree_rcu(irq, rcu); | |
| 156 | +static void vgic_release_deleted_lpis(struct kvm *kvm) | |
| 157 | +{ | |
| 158 | + struct vgic_dist *dist = &kvm->arch.vgic; | |
| 159 | + unsigned long intid; | |
| 160 | + struct vgic_irq *irq; | |
| 161 | + | |
| 162 | + xa_lock(&dist->lpi_xa); | |
| 163 | + | |
| 164 | + xa_for_each(&dist->lpi_xa, intid, irq) { | |
| 165 | + if (irq->pending_release) | |
| 166 | + vgic_release_lpi_locked(dist, irq); | |
| 167 | + } | |
| 168 | + | |
| 169 | + xa_unlock(&dist->lpi_xa); | |
| 142 | 170 | } |
| 143 | 171 | |
| 144 | 172 | void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu) |
| 145 | 173 | { |
| 146 | 174 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
| 147 | 175 | struct vgic_irq *irq, *tmp; |
| 176 | + bool deleted = false; | |
| 148 | 177 | unsigned long flags; |
| 149 | 178 | |
| 150 | 179 | raw_spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags); |
| @@ -155,11 +184,14 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu) · 4 unmodified lines | ||
| 155 | 184 | list_del(&irq->ap_list); |
| 156 | 185 | irq->vcpu = NULL; |
| 157 | 186 | raw_spin_unlock(&irq->irq_lock); |
| 158 | − vgic_put_irq(vcpu->kvm, irq); | |
| 187 | + deleted |= vgic_put_irq_norelease(vcpu->kvm, irq); | |
| 159 | 188 | } |
| 160 | 189 | } |
| 161 | 190 | |
| 162 | 191 | raw_spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags); |
| 192 | + | |
| 193 | + if (deleted) | |
| 194 | + vgic_release_deleted_lpis(vcpu->kvm); | |
| 163 | 195 | } |
| 164 | 196 | |
| 165 | 197 | void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending) |
| @@ -399,7 +431,7 @@ retry: · 233 unmodified lines | ||
| 399 | 431 | * now in the ap_list. This is safe as the caller must already hold a |
| 400 | 432 | * reference on the irq. |
| 401 | 433 | */ |
| 402 | − vgic_get_irq_kref(irq); | |
| 434 | + vgic_get_irq_ref(irq); | |
| 403 | 435 | list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head); |
| 404 | 436 | irq->vcpu = vcpu; |
| 405 | 437 | |
| @@ -630,6 +662,7 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu) · 224 unmodified lines | ||
| 630 | 662 | { |
| 631 | 663 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
| 632 | 664 | struct vgic_irq *irq, *tmp; |
| 665 | + bool deleted_lpis = false; | |
| 633 | 666 | |
| 634 | 667 | DEBUG_SPINLOCK_BUG_ON(!irqs_disabled()); |
| 635 | 668 | |
| @@ -657,12 +690,12 @@ retry: · 21 unmodified lines | ||
| 657 | 690 | |
| 658 | 691 | /* |
| 659 | 692 | * This vgic_put_irq call matches the |
| 660 | − * vgic_get_irq_kref in vgic_queue_irq_unlock, | |
| 693 | + * vgic_get_irq_ref in vgic_queue_irq_unlock, | |
| 661 | 694 | * where we added the LPI to the ap_list. As |
| 662 | 695 | * we remove the irq from the list, we drop |
| 663 | 696 | * also drop the refcount. |
| 664 | 697 | */ |
| 665 | − vgic_put_irq(vcpu->kvm, irq); | |
| 698 | + deleted_lpis |= vgic_put_irq_norelease(vcpu->kvm, irq); | |
| 666 | 699 | continue; |
| 667 | 700 | } |
| 668 | 701 | |
| @@ -725,6 +758,9 @@ retry: · 56 unmodified lines | ||
| 725 | 758 | } |
| 726 | 759 | |
| 727 | 760 | raw_spin_unlock(&vgic_cpu->ap_list_lock); |
| 761 | + | |
| 762 | + if (unlikely(deleted_lpis)) | |
| 763 | + vgic_release_deleted_lpis(vcpu->kvm); | |
| 728 | 764 | } |
| 729 | 765 | |
| 730 | 766 | static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu) |
| @@ -818,7 +854,7 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu) · 87 unmodified lines | ||
| 818 | 854 | * the AP list has been sorted already. |
| 819 | 855 | */ |
| 820 | 856 | if (multi_sgi && irq->priority > prio) { |
| 821 | − _raw_spin_unlock(&irq->irq_lock); | |
| 857 | + raw_spin_unlock(&irq->irq_lock); | |
| 822 | 858 | break; |
| 823 | 859 | } |
| 824 | 860 | |
| @@ -267,7 +267,7 @@ void vgic_v2_put(struct kvm_vcpu *vcpu); · 266 unmodified lines | ||
| 267 | 267 | void vgic_v2_save_state(struct kvm_vcpu *vcpu); |
| 268 | 268 | void vgic_v2_restore_state(struct kvm_vcpu *vcpu); |
| 269 | 269 | |
| 270 | −static inline bool vgic_try_get_irq_kref(struct vgic_irq *irq) | |
| 270 | +static inline bool vgic_try_get_irq_ref(struct vgic_irq *irq) | |
| 271 | 271 | { |
| 272 | 272 | if (!irq) |
| 273 | 273 | return false; |
| @@ -275,12 +275,12 @@ static inline bool vgic_try_get_irq_kref(struct vgic_irq *irq) · 1 unmodified line | ||
| 275 | 275 | if (irq->intid < VGIC_MIN_LPI) |
| 276 | 276 | return true; |
| 277 | 277 | |
| 278 | − return kref_get_unless_zero(&irq->refcount); | |
| 278 | + return refcount_inc_not_zero(&irq->refcount); | |
| 279 | 279 | } |
| 280 | 280 | |
| 281 | −static inline void vgic_get_irq_kref(struct vgic_irq *irq) | |
| 281 | +static inline void vgic_get_irq_ref(struct vgic_irq *irq) | |
| 282 | 282 | { |
| 283 | − WARN_ON_ONCE(!vgic_try_get_irq_kref(irq)); | |
| 283 | + WARN_ON_ONCE(!vgic_try_get_irq_ref(irq)); | |
| 284 | 284 | } |
| 285 | 285 | |
| 286 | 286 | void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu); |
| @@ -2778,12 +2778,19 @@ static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap) · 2777 unmodified lines | ||
| 2778 | 2778 | |
| 2779 | 2779 | static struct page *get_map_page(struct kvm *kvm, u64 uaddr) |
| 2780 | 2780 | { |
| 2781 | + struct mm_struct *mm = kvm->mm; | |
| 2781 | 2782 | struct page *page = NULL; |
| 2783 | + int locked = 1; | |
| 2784 | + | |
| 2785 | + if (mmget_not_zero(mm)) { | |
| 2786 | + mmap_read_lock(mm); | |
| 2787 | + get_user_pages_remote(mm, uaddr, 1, FOLL_WRITE, | |
| 2788 | + &page, &locked); | |
| 2789 | + if (locked) | |
| 2790 | + mmap_read_unlock(mm); | |
| 2791 | + mmput(mm); | |
| 2792 | + } | |
| 2782 | 2793 | |
| 2783 | − mmap_read_lock(kvm->mm); | |
| 2784 | − get_user_pages_remote(kvm->mm, uaddr, 1, FOLL_WRITE, | |
| 2785 | − &page, NULL); | |
| 2786 | − mmap_read_unlock(kvm->mm); | |
| 2787 | 2794 | return page; |
| 2788 | 2795 | } |
| 2789 | 2796 | |
| @@ -4864,12 +4864,12 @@ static void kvm_s390_assert_primary_as(struct kvm_vcpu *vcpu) · 4863 unmodified lines | ||
| 4864 | 4864 | * @vcpu: the vCPU whose gmap is to be fixed up |
| 4865 | 4865 | * @gfn: the guest frame number used for memslots (including fake memslots) |
| 4866 | 4866 | * @gaddr: the gmap address, does not have to match @gfn for ucontrol gmaps |
| 4867 | − * @flags: FOLL_* flags | |
| 4867 | + * @foll: FOLL_* flags | |
| 4868 | 4868 | * |
| 4869 | 4869 | * Return: 0 on success, < 0 in case of error. |
| 4870 | 4870 | * Context: The mm lock must not be held before calling. May sleep. |
| 4871 | 4871 | */ |
| 4872 | −int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int flags) | |
| 4872 | +int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, unsigned int foll) | |
| 4873 | 4873 | { |
| 4874 | 4874 | struct kvm_memory_slot *slot; |
| 4875 | 4875 | unsigned int fault_flags; |
| @@ -4883,13 +4883,13 @@ int __kvm_s390_handle_dat_fault(struct kvm_vcpu *vcpu, gfn_t gfn, gpa_t gaddr, u · 7 unmodified lines | ||
| 4883 | 4883 | if (!slot || slot->flags & KVM_MEMSLOT_INVALID) |
| 4884 | 4884 | return vcpu_post_run_addressing_exception(vcpu); |
| 4885 | 4885 | |
| 4886 | − fault_flags = flags & FOLL_WRITE ? FAULT_FLAG_WRITE : 0; | |
| 4886 | + fault_flags = foll & FOLL_WRITE ? FAULT_FLAG_WRITE : 0; | |
| 4887 | 4887 | if (vcpu->arch.gmap->pfault_enabled) |
| 4888 | − flags |= FOLL_NOWAIT; | |
| 4888 | + foll |= FOLL_NOWAIT; | |
| 4889 | 4889 | vmaddr = __gfn_to_hva_memslot(slot, gfn); |
| 4890 | 4890 | |
| 4891 | 4891 | try_again: |
| 4892 | − pfn = __kvm_faultin_pfn(slot, gfn, flags, &writable, &page); | |
| 4892 | + pfn = __kvm_faultin_pfn(slot, gfn, foll, &writable, &page); | |
| 4893 | 4893 | |
| 4894 | 4894 | /* Access outside memory, inject addressing exception */ |
| 4895 | 4895 | if (is_noslot_pfn(pfn)) |
| @@ -4905,7 +4905,7 @@ try_again: · 9 unmodified lines | ||
| 4905 | 4905 | return 0; |
| 4906 | 4906 | vcpu->stat.pfault_sync++; |
| 4907 | 4907 | /* Could not setup async pfault, try again synchronously */ |
| 4908 | − flags &= ~FOLL_NOWAIT; | |
| 4908 | + foll &= ~FOLL_NOWAIT; | |
| 4909 | 4909 | goto try_again; |
| 4910 | 4910 | } |
| 4911 | 4911 | /* Any other error */ |
| @@ -4925,7 +4925,7 @@ try_again: · 13 unmodified lines | ||
| 4925 | 4925 | return rc; |
| 4926 | 4926 | } |
| 4927 | 4927 | |
| 4928 | −static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, unsigned int flags) | |
| 4928 | +static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, unsigned int foll) | |
| 4929 | 4929 | { |
| 4930 | 4930 | unsigned long gaddr_tmp; |
| 4931 | 4931 | gfn_t gfn; |
| @@ -4950,18 +4950,18 @@ static int vcpu_dat_fault_handler(struct kvm_vcpu *vcpu, unsigned long gaddr, un · 18 unmodified lines | ||
| 4950 | 4950 | } |
| 4951 | 4951 | gfn = gpa_to_gfn(gaddr_tmp); |
| 4952 | 4952 | } |
| 4953 | − return __kvm_s390_handle_dat_fault(vcpu, gfn, gaddr, flags); | |
| 4953 | + return __kvm_s390_handle_dat_fault(vcpu, gfn, gaddr, foll); | |
| 4954 | 4954 | } |
| 4955 | 4955 | |
| 4956 | 4956 | static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu) |
| 4957 | 4957 | { |
| 4958 | − unsigned int flags = 0; | |
| 4958 | + unsigned int foll = 0; | |
| 4959 | 4959 | unsigned long gaddr; |
| 4960 | 4960 | int rc; |
| 4961 | 4961 | |
| 4962 | 4962 | gaddr = current->thread.gmap_teid.addr * PAGE_SIZE; |
| 4963 | 4963 | if (kvm_s390_cur_gmap_fault_is_write()) |
| 4964 | − flags = FAULT_FLAG_WRITE; | |
| 4964 | + foll = FOLL_WRITE; | |
| 4965 | 4965 | |
| 4966 | 4966 | switch (current->thread.gmap_int_code & PGM_INT_CODE_MASK) { |
| 4967 | 4967 | case 0: |
| @@ -5003,7 +5003,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu) · 35 unmodified lines | ||
| 5003 | 5003 | send_sig(SIGSEGV, current, 0); |
| 5004 | 5004 | if (rc != -ENXIO) |
| 5005 | 5005 | break; |
| 5006 | − flags = FAULT_FLAG_WRITE; | |
| 5006 | + foll = FOLL_WRITE; | |
| 5007 | 5007 | fallthrough; |
| 5008 | 5008 | case PGM_PROTECTION: |
| 5009 | 5009 | case PGM_SEGMENT_TRANSLATION: |
| @@ -5013,7 +5013,7 @@ static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu) · 3 unmodified lines | ||
| 5013 | 5013 | case PGM_REGION_SECOND_TRANS: |
| 5014 | 5014 | case PGM_REGION_THIRD_TRANS: |
| 5015 | 5015 | kvm_s390_assert_primary_as(vcpu); |
| 5016 | − return vcpu_dat_fault_handler(vcpu, gaddr, flags); | |
| 5016 | + return vcpu_dat_fault_handler(vcpu, gaddr, foll); | |
| 5017 | 5017 | default: |
| 5018 | 5018 | KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx", |
| 5019 | 5019 | current->thread.gmap_int_code, current->thread.gmap_teid.val); |
| @@ -624,6 +624,17 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) · 623 unmodified lines | ||
| 624 | 624 | int cc, ret; |
| 625 | 625 | u16 dummy; |
| 626 | 626 | |
| 627 | + /* Add the notifier only once. No races because we hold kvm->lock */ | |
| 628 | + if (kvm->arch.pv.mmu_notifier.ops != &kvm_s390_pv_mmu_notifier_ops) { | |
| 629 | + /* The notifier will be unregistered when the VM is destroyed */ | |
| 630 | + kvm->arch.pv.mmu_notifier.ops = &kvm_s390_pv_mmu_notifier_ops; | |
| 631 | + ret = mmu_notifier_register(&kvm->arch.pv.mmu_notifier, kvm->mm); | |
| 632 | + if (ret) { | |
| 633 | + kvm->arch.pv.mmu_notifier.ops = NULL; | |
| 634 | + return ret; | |
| 635 | + } | |
| 636 | + } | |
| 637 | + | |
| 627 | 638 | ret = kvm_s390_pv_alloc_vm(kvm); |
| 628 | 639 | if (ret) |
| 629 | 640 | return ret; |
| @@ -659,11 +670,6 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) · 29 unmodified lines | ||
| 659 | 670 | return -EIO; |
| 660 | 671 | } |
| 661 | 672 | kvm->arch.gmap->guest_handle = uvcb.guest_handle; |
| 662 | − /* Add the notifier only once. No races because we hold kvm->lock */ | |
| 663 | − if (kvm->arch.pv.mmu_notifier.ops != &kvm_s390_pv_mmu_notifier_ops) { | |
| 664 | − kvm->arch.pv.mmu_notifier.ops = &kvm_s390_pv_mmu_notifier_ops; | |
| 665 | − mmu_notifier_register(&kvm->arch.pv.mmu_notifier, kvm->mm); | |
| 666 | − } | |
| 667 | 673 | return 0; |
| 668 | 674 | } |
| 669 | 675 | |
| @@ -1250,10 +1250,12 @@ static int virtio_uml_probe(struct platform_device *pdev) · 1249 unmodified lines | ||
| 1250 | 1250 | device_set_wakeup_capable(&vu_dev->vdev.dev, true); |
| 1251 | 1251 | |
| 1252 | 1252 | rc = register_virtio_device(&vu_dev->vdev); |
| 1253 | − if (rc) | |
| 1253 | + if (rc) { | |
| 1254 | 1254 | put_device(&vu_dev->vdev.dev); |
| 1255 | + return rc; | |
| 1256 | + } | |
| 1255 | 1257 | vu_dev->registered = 1; |
| 1256 | − return rc; | |
| 1258 | + return 0; | |
| 1257 | 1259 | |
| 1258 | 1260 | error_init: |
| 1259 | 1261 | os_close_file(vu_dev->sock); |
| @@ -535,7 +535,7 @@ ssize_t os_rcv_fd_msg(int fd, int *fds, unsigned int n_fds, · 534 unmodified lines | ||
| 535 | 535 | cmsg->cmsg_type != SCM_RIGHTS) |
| 536 | 536 | return n; |
| 537 | 537 | |
| 538 | − memcpy(fds, CMSG_DATA(cmsg), cmsg->cmsg_len); | |
| 538 | + memcpy(fds, CMSG_DATA(cmsg), cmsg->cmsg_len - CMSG_LEN(0)); | |
| 539 | 539 | return n; |
| 540 | 540 | } |
| 541 | 541 | |
| @@ -20,8 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | void stack_protections(unsigned long address) |
| 22 | 22 | { |
| 23 | − if (mprotect((void *) address, UM_THREAD_SIZE, | |
| 24 | − PROT_READ | PROT_WRITE | PROT_EXEC) < 0) | |
| 23 | + if (mprotect((void *) address, UM_THREAD_SIZE, PROT_READ | PROT_WRITE) < 0) | |
| 25 | 24 | panic("protecting stack failed, errno = %d", errno); |
| 26 | 25 | } |
| 27 | 26 | |
| @@ -175,27 +175,30 @@ static void topoext_fixup(struct topo_scan *tscan) · 174 unmodified lines | ||
| 175 | 175 | |
| 176 | 176 | static void parse_topology_amd(struct topo_scan *tscan) |
| 177 | 177 | { |
| 178 | − bool has_topoext = false; | |
| 179 | − | |
| 180 | 178 | /* |
| 181 | − * If the extended topology leaf 0x8000_001e is available | |
| 182 | − * try to get SMT, CORE, TILE, and DIE shifts from extended | |
| 179 | + * Try to get SMT, CORE, TILE, and DIE shifts from extended | |
| 183 | 180 | * CPUID leaf 0x8000_0026 on supported processors first. If |
| 184 | 181 | * extended CPUID leaf 0x8000_0026 is not supported, try to |
| 185 | − * get SMT and CORE shift from leaf 0xb first, then try to | |
| 186 | − * get the CORE shift from leaf 0x8000_0008. | |
| 182 | + * get SMT and CORE shift from leaf 0xb. If either leaf is | |
| 183 | + * available, cpu_parse_topology_ext() will return true. | |
| 187 | 184 | */ |
| 188 | − if (cpu_feature_enabled(X86_FEATURE_TOPOEXT)) | |
| 189 | − has_topoext = cpu_parse_topology_ext(tscan); | |
| 185 | + bool has_xtopology = cpu_parse_topology_ext(tscan); | |
| 190 | 186 | |
| 191 | 187 | if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) |
| 192 | 188 | tscan->c->topo.cpu_type = cpuid_ebx(0x80000026); |
| 193 | 189 | |
| 194 | − if (!has_topoext && !parse_8000_0008(tscan)) | |
| 190 | + /* | |
| 191 | + * If XTOPOLOGY leaves (0x26/0xb) are not available, try to | |
| 192 | + * get the CORE shift from leaf 0x8000_0008 first. | |
| 193 | + */ | |
| 194 | + if (!has_xtopology && !parse_8000_0008(tscan)) | |
| 195 | 195 | return; |
| 196 | 196 | |
| 197 | − /* Prefer leaf 0x8000001e if available */ | |
| 198 | − if (parse_8000_001e(tscan, has_topoext)) | |
| 197 | + /* | |
| 198 | + * Prefer leaf 0x8000001e if available to get the SMT shift and | |
| 199 | + * the initial APIC ID if XTOPOLOGY leaves are not available. | |
| 200 | + */ | |
| 201 | + if (parse_8000_001e(tscan, has_xtopology)) | |
| 199 | 202 | return; |
| 200 | 203 | |
| 201 | 204 | /* Try the NODEID MSR */ |
| @@ -4046,8 +4046,7 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) · 4045 unmodified lines | ||
| 4046 | 4046 | struct vcpu_svm *svm = to_svm(vcpu); |
| 4047 | 4047 | u64 cr8; |
| 4048 | 4048 | |
| 4049 | − if (nested_svm_virtualize_tpr(vcpu) || | |
| 4050 | − kvm_vcpu_apicv_active(vcpu)) | |
| 4049 | + if (nested_svm_virtualize_tpr(vcpu)) | |
| 4051 | 4050 | return; |
| 4052 | 4051 | |
| 4053 | 4052 | cr8 = kvm_get_cr8(vcpu); |
| @@ -1795,6 +1795,7 @@ static int write_same_filled_page(struct zram *zram, unsigned long fill, · 1794 unmodified lines | ||
| 1795 | 1795 | u32 index) |
| 1796 | 1796 | { |
| 1797 | 1797 | zram_slot_lock(zram, index); |
| 1798 | + zram_free_page(zram, index); | |
| 1798 | 1799 | zram_set_flag(zram, index, ZRAM_SAME); |
| 1799 | 1800 | zram_set_handle(zram, index, fill); |
| 1800 | 1801 | zram_slot_unlock(zram, index); |
| @@ -1832,6 +1833,7 @@ static int write_incompressible_page(struct zram *zram, struct page *page, · 31 unmodified lines | ||
| 1832 | 1833 | kunmap_local(src); |
| 1833 | 1834 | |
| 1834 | 1835 | zram_slot_lock(zram, index); |
| 1836 | + zram_free_page(zram, index); | |
| 1835 | 1837 | zram_set_flag(zram, index, ZRAM_HUGE); |
| 1836 | 1838 | zram_set_handle(zram, index, handle); |
| 1837 | 1839 | zram_set_obj_size(zram, index, PAGE_SIZE); |
| @@ -1855,11 +1857,6 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) · 17 unmodified lines | ||
| 1855 | 1857 | unsigned long element; |
| 1856 | 1858 | bool same_filled; |
| 1857 | 1859 | |
| 1858 | − /* First, free memory allocated to this slot (if any) */ | |
| 1859 | − zram_slot_lock(zram, index); | |
| 1860 | − zram_free_page(zram, index); | |
| 1861 | − zram_slot_unlock(zram, index); | |
| 1862 | − | |
| 1863 | 1860 | mem = kmap_local_page(page); |
| 1864 | 1861 | same_filled = page_same_filled(mem, &element); |
| 1865 | 1862 | kunmap_local(mem); |
| @@ -1901,6 +1898,7 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) · 35 unmodified lines | ||
| 1901 | 1898 | zcomp_stream_put(zstrm); |
| 1902 | 1899 | |
| 1903 | 1900 | zram_slot_lock(zram, index); |
| 1901 | + zram_free_page(zram, index); | |
| 1904 | 1902 | zram_set_handle(zram, index, handle); |
| 1905 | 1903 | zram_set_obj_size(zram, index, comp_len); |
| 1906 | 1904 | zram_slot_unlock(zram, index); |
| @@ -48,12 +48,16 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec, · 47 unmodified lines | ||
| 48 | 48 | u32 mask; |
| 49 | 49 | int ret; |
| 50 | 50 | |
| 51 | − if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS) | |
| 52 | − return ERR_PTR(-EINVAL); | |
| 51 | + if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS) { | |
| 52 | + ret = -EINVAL; | |
| 53 | + goto put_device; | |
| 54 | + } | |
| 53 | 55 | |
| 54 | 56 | map = kzalloc(sizeof(*map), GFP_KERNEL); |
| 55 | − if (!map) | |
| 56 | − return ERR_PTR(-ENOMEM); | |
| 57 | + if (!map) { | |
| 58 | + ret = -ENOMEM; | |
| 59 | + goto put_device; | |
| 60 | + } | |
| 57 | 61 | |
| 58 | 62 | chan = dma_spec->args[0]; |
| 59 | 63 | map->req_idx = dma_spec->args[4]; |
| @@ -94,12 +98,15 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec, · 34 unmodified lines | ||
| 94 | 98 | if (ret) |
| 95 | 99 | goto clear_bitmap; |
| 96 | 100 | |
| 101 | + put_device(&pdev->dev); | |
| 97 | 102 | return map; |
| 98 | 103 | |
| 99 | 104 | clear_bitmap: |
| 100 | 105 | clear_bit(map->req_idx, dmamux->used_chans); |
| 101 | 106 | free_map: |
| 102 | 107 | kfree(map); |
| 108 | +put_device: | |
| 109 | + put_device(&pdev->dev); | |
| 103 | 110 | |
| 104 | 111 | return ERR_PTR(ret); |
| 105 | 112 | } |
| @@ -189,27 +189,30 @@ static int idxd_setup_wqs(struct idxd_device *idxd) · 188 unmodified lines | ||
| 189 | 189 | idxd->wq_enable_map = bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL, dev_to_node(dev)); |
| 190 | 190 | if (!idxd->wq_enable_map) { |
| 191 | 191 | rc = -ENOMEM; |
| 192 | − goto err_bitmap; | |
| 192 | + goto err_free_wqs; | |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | 195 | for (i = 0; i < idxd->max_wqs; i++) { |
| 196 | 196 | wq = kzalloc_node(sizeof(*wq), GFP_KERNEL, dev_to_node(dev)); |
| 197 | 197 | if (!wq) { |
| 198 | 198 | rc = -ENOMEM; |
| 199 | − goto err; | |
| 199 | + goto err_unwind; | |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | 202 | idxd_dev_set_type(&wq->idxd_dev, IDXD_DEV_WQ); |
| 203 | 203 | conf_dev = wq_confdev(wq); |
| 204 | 204 | wq->id = i; |
| 205 | 205 | wq->idxd = idxd; |
| 206 | − device_initialize(wq_confdev(wq)); | |
| 206 | + device_initialize(conf_dev); | |
| 207 | 207 | conf_dev->parent = idxd_confdev(idxd); |
| 208 | 208 | conf_dev->bus = &dsa_bus_type; |
| 209 | 209 | conf_dev->type = &idxd_wq_device_type; |
| 210 | 210 | rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id); |
| 211 | − if (rc < 0) | |
| 212 | − goto err; | |
| 211 | + if (rc < 0) { | |
| 212 | + put_device(conf_dev); | |
| 213 | + kfree(wq); | |
| 214 | + goto err_unwind; | |
| 215 | + } | |
| 213 | 216 | |
| 214 | 217 | mutex_init(&wq->wq_lock); |
| 215 | 218 | init_waitqueue_head(&wq->err_queue); |
| @@ -220,15 +223,20 @@ static int idxd_setup_wqs(struct idxd_device *idxd) · 4 unmodified lines | ||
| 220 | 223 | wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; |
| 221 | 224 | wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev)); |
| 222 | 225 | if (!wq->wqcfg) { |
| 226 | + put_device(conf_dev); | |
| 227 | + kfree(wq); | |
| 223 | 228 | rc = -ENOMEM; |
| 224 | − goto err; | |
| 229 | + goto err_unwind; | |
| 225 | 230 | } |
| 226 | 231 | |
| 227 | 232 | if (idxd->hw.wq_cap.op_config) { |
| 228 | 233 | wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL); |
| 229 | 234 | if (!wq->opcap_bmap) { |
| 235 | + kfree(wq->wqcfg); | |
| 236 | + put_device(conf_dev); | |
| 237 | + kfree(wq); | |
| 230 | 238 | rc = -ENOMEM; |
| 231 | − goto err_opcap_bmap; | |
| 239 | + goto err_unwind; | |
| 232 | 240 | } |
| 233 | 241 | bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS); |
| 234 | 242 | } |
| @@ -239,13 +247,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd) · 4 unmodified lines | ||
| 239 | 247 | |
| 240 | 248 | return 0; |
| 241 | 249 | |
| 242 | −err_opcap_bmap: | |
| 243 | − kfree(wq->wqcfg); | |
| 244 | − | |
| 245 | −err: | |
| 246 | − put_device(conf_dev); | |
| 247 | − kfree(wq); | |
| 248 | − | |
| 250 | +err_unwind: | |
| 249 | 251 | while (--i >= 0) { |
| 250 | 252 | wq = idxd->wqs[i]; |
| 251 | 253 | if (idxd->hw.wq_cap.op_config) |
| @@ -254,11 +256,10 @@ err: · 2 unmodified lines | ||
| 254 | 256 | conf_dev = wq_confdev(wq); |
| 255 | 257 | put_device(conf_dev); |
| 256 | 258 | kfree(wq); |
| 257 | − | |
| 258 | 259 | } |
| 259 | 260 | bitmap_free(idxd->wq_enable_map); |
| 260 | 261 | |
| 261 | −err_bitmap: | |
| 262 | +err_free_wqs: | |
| 262 | 263 | kfree(idxd->wqs); |
| 263 | 264 | |
| 264 | 265 | return rc; |
| @@ -1291,10 +1292,12 @@ static void idxd_remove(struct pci_dev *pdev) · 1026 unmodified lines | ||
| 1291 | 1292 | device_unregister(idxd_confdev(idxd)); |
| 1292 | 1293 | idxd_shutdown(pdev); |
| 1293 | 1294 | idxd_device_remove_debugfs(idxd); |
| 1294 | − idxd_cleanup(idxd); | |
| 1295 | + perfmon_pmu_remove(idxd); | |
| 1296 | + idxd_cleanup_interrupts(idxd); | |
| 1297 | + if (device_pasid_enabled(idxd)) | |
| 1298 | + idxd_disable_system_pasid(idxd); | |
| 1295 | 1299 | pci_iounmap(pdev, idxd->reg_base); |
| 1296 | 1300 | put_device(idxd_confdev(idxd)); |
| 1297 | − idxd_free(idxd); | |
| 1298 | 1301 | pci_disable_device(pdev); |
| 1299 | 1302 | } |
| 1300 | 1303 | |
| @@ -1283,13 +1283,17 @@ static int bam_dma_probe(struct platform_device *pdev) · 1282 unmodified lines | ||
| 1283 | 1283 | if (!bdev->bamclk) { |
| 1284 | 1284 | ret = of_property_read_u32(pdev->dev.of_node, "num-channels", |
| 1285 | 1285 | &bdev->num_channels); |
| 1286 | − if (ret) | |
| 1286 | + if (ret) { | |
| 1287 | 1287 | dev_err(bdev->dev, "num-channels unspecified in dt\n"); |
| 1288 | + return ret; | |
| 1289 | + } | |
| 1288 | 1290 | |
| 1289 | 1291 | ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-ees", |
| 1290 | 1292 | &bdev->num_ees); |
| 1291 | − if (ret) | |
| 1293 | + if (ret) { | |
| 1292 | 1294 | dev_err(bdev->dev, "num-ees unspecified in dt\n"); |
| 1295 | + return ret; | |
| 1296 | + } | |
| 1293 | 1297 | } |
| 1294 | 1298 | |
| 1295 | 1299 | ret = clk_prepare_enable(bdev->bamclk); |
| @@ -2064,8 +2064,8 @@ static int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata, · 2063 unmodified lines | ||
| 2064 | 2064 | * priority. So Q0 is the highest priority queue and the last queue has |
| 2065 | 2065 | * the lowest priority. |
| 2066 | 2066 | */ |
| 2067 | − queue_priority_map = devm_kcalloc(dev, ecc->num_tc + 1, sizeof(s8), | |
| 2068 | − GFP_KERNEL); | |
| 2067 | + queue_priority_map = devm_kcalloc(dev, ecc->num_tc + 1, | |
| 2068 | + sizeof(*queue_priority_map), GFP_KERNEL); | |
| 2069 | 2069 | if (!queue_priority_map) |
| 2070 | 2070 | return -ENOMEM; |
| 2071 | 2071 | |
| @@ -211,8 +211,8 @@ static int · 210 unmodified lines | ||
| 211 | 211 | dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll, |
| 212 | 212 | struct netlink_ext_ack *extack) |
| 213 | 213 | { |
| 214 | + DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX + 1) = { 0 }; | |
| 214 | 215 | const struct dpll_device_ops *ops = dpll_device_ops(dpll); |
| 215 | − DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) = { 0 }; | |
| 216 | 216 | enum dpll_clock_quality_level ql; |
| 217 | 217 | int ret; |
| 218 | 218 | |
| @@ -221,7 +221,7 @@ dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll, · 2 unmodified lines | ||
| 221 | 221 | ret = ops->clock_quality_level_get(dpll, dpll_priv(dpll), qls, extack); |
| 222 | 222 | if (ret) |
| 223 | 223 | return ret; |
| 224 | − for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) | |
| 224 | + for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX + 1) | |
| 225 | 225 | if (nla_put_u32(msg, DPLL_A_CLOCK_QUALITY_LEVEL, ql)) |
| 226 | 226 | return -EMSGSIZE; |
| 227 | 227 | |
| @@ -213,19 +213,35 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, · 212 unmodified lines | ||
| 213 | 213 | spin_lock(&kfd_mem_limit.mem_limit_lock); |
| 214 | 214 | |
| 215 | 215 | if (kfd_mem_limit.system_mem_used + system_mem_needed > |
| 216 | − kfd_mem_limit.max_system_mem_limit) | |
| 216 | + kfd_mem_limit.max_system_mem_limit) { | |
| 217 | 217 | pr_debug("Set no_system_mem_limit=1 if using shared memory\n"); |
| 218 | + if (!no_system_mem_limit) { | |
| 219 | + ret = -ENOMEM; | |
| 220 | + goto release; | |
| 221 | + } | |
| 222 | + } | |
| 218 | 223 | |
| 219 | − if ((kfd_mem_limit.system_mem_used + system_mem_needed > | |
| 220 | − kfd_mem_limit.max_system_mem_limit && !no_system_mem_limit) || | |
| 221 | − (kfd_mem_limit.ttm_mem_used + ttm_mem_needed > | |
| 222 | − kfd_mem_limit.max_ttm_mem_limit) || | |
| 223 | − (adev && xcp_id >= 0 && adev->kfd.vram_used[xcp_id] + vram_needed > | |
| 224 | − vram_size - reserved_for_pt - reserved_for_ras - atomic64_read(&adev->vram_pin_size))) { | |
| 224 | + if (kfd_mem_limit.ttm_mem_used + ttm_mem_needed > | |
| 225 | + kfd_mem_limit.max_ttm_mem_limit) { | |
| 225 | 226 | ret = -ENOMEM; |
| 226 | 227 | goto release; |
| 227 | 228 | } |
| 228 | 229 | |
| 230 | + /*if is_app_apu is false and apu_prefer_gtt is true, it is an APU with | |
| 231 | + * carve out < gtt. In that case, VRAM allocation will go to gtt domain, skip | |
| 232 | + * VRAM check since ttm_mem_limit check already cover this allocation | |
| 233 | + */ | |
| 234 | + | |
| 235 | + if (adev && xcp_id >= 0 && (!adev->apu_prefer_gtt || adev->gmc.is_app_apu)) { | |
| 236 | + uint64_t vram_available = | |
| 237 | + vram_size - reserved_for_pt - reserved_for_ras - | |
| 238 | + atomic64_read(&adev->vram_pin_size); | |
| 239 | + if (adev->kfd.vram_used[xcp_id] + vram_needed > vram_available) { | |
| 240 | + ret = -ENOMEM; | |
| 241 | + goto release; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 229 | 245 | /* Update memory accounting by decreasing available system |
| 230 | 246 | * memory, TTM memory and GPU memory as computed above |
| 231 | 247 | */ |
| @@ -1626,11 +1642,15 @@ size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev, · 1394 unmodified lines | ||
| 1626 | 1642 | uint64_t vram_available, system_mem_available, ttm_mem_available; |
| 1627 | 1643 | |
| 1628 | 1644 | spin_lock(&kfd_mem_limit.mem_limit_lock); |
| 1629 | − vram_available = KFD_XCP_MEMORY_SIZE(adev, xcp_id) | |
| 1630 | − - adev->kfd.vram_used_aligned[xcp_id] | |
| 1631 | − - atomic64_read(&adev->vram_pin_size) | |
| 1632 | − - reserved_for_pt | |
| 1633 | − - reserved_for_ras; | |
| 1645 | + if (adev->apu_prefer_gtt && !adev->gmc.is_app_apu) | |
| 1646 | + vram_available = KFD_XCP_MEMORY_SIZE(adev, xcp_id) | |
| 1647 | + - adev->kfd.vram_used_aligned[xcp_id]; | |
| 1648 | + else | |
| 1649 | + vram_available = KFD_XCP_MEMORY_SIZE(adev, xcp_id) | |
| 1650 | + - adev->kfd.vram_used_aligned[xcp_id] | |
| 1651 | + - atomic64_read(&adev->vram_pin_size) | |
| 1652 | + - reserved_for_pt | |
| 1653 | + - reserved_for_ras; | |
| 1634 | 1654 | |
| 1635 | 1655 | if (adev->apu_prefer_gtt) { |
| 1636 | 1656 | system_mem_available = no_system_mem_limit ? |
| @@ -421,8 +421,6 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring) · 420 unmodified lines | ||
| 421 | 421 | dma_fence_put(ring->vmid_wait); |
| 422 | 422 | ring->vmid_wait = NULL; |
| 423 | 423 | ring->me = 0; |
| 424 | − | |
| 425 | − ring->adev->rings[ring->idx] = NULL; | |
| 426 | 424 | } |
| 427 | 425 | |
| 428 | 426 | /** |
| @@ -29,6 +29,8 @@ · 28 unmodified lines | ||
| 29 | 29 | #include "amdgpu.h" |
| 30 | 30 | #include "isp_v4_1_1.h" |
| 31 | 31 | |
| 32 | +MODULE_FIRMWARE("amdgpu/isp_4_1_1.bin"); | |
| 33 | + | |
| 32 | 34 | #define ISP_PERFORMANCE_STATE_LOW 0 |
| 33 | 35 | #define ISP_PERFORMANCE_STATE_HIGH 1 |
| 34 | 36 | |
| @@ -149,12 +149,12 @@ static int psp_v11_0_wait_for_bootloader(struct psp_context *psp) · 148 unmodified lines | ||
| 149 | 149 | int ret; |
| 150 | 150 | int retry_loop; |
| 151 | 151 | |
| 152 | − for (retry_loop = 0; retry_loop < 10; retry_loop++) { | |
| 152 | + for (retry_loop = 0; retry_loop < 20; retry_loop++) { | |
| 153 | 153 | /* Wait for bootloader to signify that is |
| 154 | 154 | ready having bit 31 of C2PMSG_35 set to 1 */ |
| 155 | 155 | ret = psp_wait_for( |
| 156 | 156 | psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_35), |
| 157 | − 0x80000000, 0x80000000, PSP_WAITREG_NOVERBOSE); | |
| 157 | + 0x80000000, 0x8000FFFF, PSP_WAITREG_NOVERBOSE); | |
| 158 | 158 | |
| 159 | 159 | if (ret == 0) |
| 160 | 160 | return 0; |
| @@ -397,18 +397,6 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp) · 236 unmodified lines | ||
| 397 | 397 | |
| 398 | 398 | msleep(500); |
| 399 | 399 | |
| 400 | − offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33); | |
| 401 | − | |
| 402 | − ret = psp_wait_for(psp, offset, MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, | |
| 403 | − 0); | |
| 404 | − | |
| 405 | − if (ret) { | |
| 406 | − DRM_INFO("psp mode 1 reset failed!\n"); | |
| 407 | − return -EINVAL; | |
| 408 | − } | |
| 409 | − | |
| 410 | − DRM_INFO("psp mode1 reset succeed \n"); | |
| 411 | − | |
| 412 | 400 | return 0; |
| 413 | 401 | } |
| 414 | 402 | |
| @@ -665,7 +653,8 @@ static const struct psp_funcs psp_v11_0_funcs = { · 250 unmodified lines | ||
| 665 | 653 | .ring_get_wptr = psp_v11_0_ring_get_wptr, |
| 666 | 654 | .ring_set_wptr = psp_v11_0_ring_set_wptr, |
| 667 | 655 | .load_usbc_pd_fw = psp_v11_0_load_usbc_pd_fw, |
| 668 | − .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw | |
| 656 | + .read_usbc_pd_fw = psp_v11_0_read_usbc_pd_fw, | |
| 657 | + .wait_for_bootloader = psp_v11_0_wait_for_bootloader | |
| 669 | 658 | }; |
| 670 | 659 | |
| 671 | 660 | void psp_v11_0_set_psp_funcs(struct psp_context *psp) |
| @@ -1888,15 +1888,19 @@ static int vcn_v3_0_limit_sched(struct amdgpu_cs_parser *p, · 1887 unmodified lines | ||
| 1888 | 1888 | struct amdgpu_job *job) |
| 1889 | 1889 | { |
| 1890 | 1890 | struct drm_gpu_scheduler **scheds; |
| 1891 | − | |
| 1892 | − /* The create msg must be in the first IB submitted */ | |
| 1893 | − if (atomic_read(&job->base.entity->fence_seq)) | |
| 1894 | − return -EINVAL; | |
| 1891 | + struct dma_fence *fence; | |
| 1895 | 1892 | |
| 1896 | 1893 | /* if VCN0 is harvested, we can't support AV1 */ |
| 1897 | 1894 | if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) |
| 1898 | 1895 | return -EINVAL; |
| 1899 | 1896 | |
| 1897 | + /* wait for all jobs to finish before switching to instance 0 */ | |
| 1898 | + fence = amdgpu_ctx_get_fence(p->ctx, job->base.entity, ~0ull); | |
| 1899 | + if (fence) { | |
| 1900 | + dma_fence_wait(fence, false); | |
| 1901 | + dma_fence_put(fence); | |
| 1902 | + } | |
| 1903 | + | |
| 1900 | 1904 | scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_DEC] |
| 1901 | 1905 | [AMDGPU_RING_PRIO_DEFAULT].sched; |
| 1902 | 1906 | drm_sched_entity_modify_sched(job->base.entity, scheds, 1); |
| @@ -1808,15 +1808,19 @@ static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p, · 1807 unmodified lines | ||
| 1808 | 1808 | struct amdgpu_job *job) |
| 1809 | 1809 | { |
| 1810 | 1810 | struct drm_gpu_scheduler **scheds; |
| 1811 | − | |
| 1812 | − /* The create msg must be in the first IB submitted */ | |
| 1813 | − if (atomic_read(&job->base.entity->fence_seq)) | |
| 1814 | − return -EINVAL; | |
| 1811 | + struct dma_fence *fence; | |
| 1815 | 1812 | |
| 1816 | 1813 | /* if VCN0 is harvested, we can't support AV1 */ |
| 1817 | 1814 | if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) |
| 1818 | 1815 | return -EINVAL; |
| 1819 | 1816 | |
| 1817 | + /* wait for all jobs to finish before switching to instance 0 */ | |
| 1818 | + fence = amdgpu_ctx_get_fence(p->ctx, job->base.entity, ~0ull); | |
| 1819 | + if (fence) { | |
| 1820 | + dma_fence_wait(fence, false); | |
| 1821 | + dma_fence_put(fence); | |
| 1822 | + } | |
| 1823 | + | |
| 1820 | 1824 | scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_ENC] |
| 1821 | 1825 | [AMDGPU_RING_PRIO_0].sched; |
| 1822 | 1826 | drm_sched_entity_modify_sched(job->base.entity, scheds, 1); |
| @@ -1907,22 +1911,16 @@ out: · 84 unmodified lines | ||
| 1907 | 1911 | |
| 1908 | 1912 | #define RADEON_VCN_ENGINE_TYPE_ENCODE (0x00000002) |
| 1909 | 1913 | #define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003) |
| 1910 | − | |
| 1911 | 1914 | #define RADEON_VCN_ENGINE_INFO (0x30000001) |
| 1912 | −#define RADEON_VCN_ENGINE_INFO_MAX_OFFSET 16 | |
| 1913 | − | |
| 1914 | 1915 | #define RENCODE_ENCODE_STANDARD_AV1 2 |
| 1915 | 1916 | #define RENCODE_IB_PARAM_SESSION_INIT 0x00000003 |
| 1916 | −#define RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET 64 | |
| 1917 | 1917 | |
| 1918 | −/* return the offset in ib if id is found, -1 otherwise | |
| 1919 | − * to speed up the searching we only search upto max_offset | |
| 1920 | − */ | |
| 1921 | −static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int max_offset) | |
| 1918 | +/* return the offset in ib if id is found, -1 otherwise */ | |
| 1919 | +static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start) | |
| 1922 | 1920 | { |
| 1923 | 1921 | int i; |
| 1924 | 1922 | |
| 1925 | − for (i = 0; i < ib->length_dw && i < max_offset && ib->ptr[i] >= 8; i += ib->ptr[i]/4) { | |
| 1923 | + for (i = start; i < ib->length_dw && ib->ptr[i] >= 8; i += ib->ptr[i] / 4) { | |
| 1926 | 1924 | if (ib->ptr[i + 1] == id) |
| 1927 | 1925 | return i; |
| 1928 | 1926 | } |
| @@ -1937,33 +1935,29 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, · 8 unmodified lines | ||
| 1937 | 1935 | struct amdgpu_vcn_decode_buffer *decode_buffer; |
| 1938 | 1936 | uint64_t addr; |
| 1939 | 1937 | uint32_t val; |
| 1940 | − int idx; | |
| 1938 | + int idx = 0, sidx; | |
| 1941 | 1939 | |
| 1942 | 1940 | /* The first instance can decode anything */ |
| 1943 | 1941 | if (!ring->me) |
| 1944 | 1942 | return 0; |
| 1945 | 1943 | |
| 1946 | − /* RADEON_VCN_ENGINE_INFO is at the top of ib block */ | |
| 1947 | − idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, | |
| 1948 | − RADEON_VCN_ENGINE_INFO_MAX_OFFSET); | |
| 1949 | − if (idx < 0) /* engine info is missing */ | |
| 1950 | − return 0; | |
| 1951 | − | |
| 1952 | − val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */ | |
| 1953 | − if (val == RADEON_VCN_ENGINE_TYPE_DECODE) { | |
| 1954 | − decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6]; | |
| 1955 | − | |
| 1956 | − if (!(decode_buffer->valid_buf_flag & 0x1)) | |
| 1957 | − return 0; | |
| 1958 | − | |
| 1959 | − addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 | | |
| 1960 | − decode_buffer->msg_buffer_address_lo; | |
| 1961 | − return vcn_v4_0_dec_msg(p, job, addr); | |
| 1962 | − } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) { | |
| 1963 | − idx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, | |
| 1964 | − RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET); | |
| 1965 | − if (idx >= 0 && ib->ptr[idx + 2] == RENCODE_ENCODE_STANDARD_AV1) | |
| 1966 | − return vcn_v4_0_limit_sched(p, job); | |
| 1944 | + while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) { | |
| 1945 | + val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */ | |
| 1946 | + if (val == RADEON_VCN_ENGINE_TYPE_DECODE) { | |
| 1947 | + decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6]; | |
| 1948 | + | |
| 1949 | + if (!(decode_buffer->valid_buf_flag & 0x1)) | |
| 1950 | + return 0; | |
| 1951 | + | |
| 1952 | + addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 | | |
| 1953 | + decode_buffer->msg_buffer_address_lo; | |
| 1954 | + return vcn_v4_0_dec_msg(p, job, addr); | |
| 1955 | + } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) { | |
| 1956 | + sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx); | |
| 1957 | + if (sidx >= 0 && ib->ptr[sidx + 2] == RENCODE_ENCODE_STANDARD_AV1) | |
| 1958 | + return vcn_v4_0_limit_sched(p, job); | |
| 1959 | + } | |
| 1960 | + idx += ib->ptr[idx] / 4; | |
| 1967 | 1961 | } |
| 1968 | 1962 | return 0; |
| 1969 | 1963 | } |
| @@ -1587,7 +1587,8 @@ static int kfd_dev_create_p2p_links(void) · 1586 unmodified lines | ||
| 1587 | 1587 | break; |
| 1588 | 1588 | if (!dev->gpu || !dev->gpu->adev || |
| 1589 | 1589 | (dev->gpu->kfd->hive_id && |
| 1590 | − dev->gpu->kfd->hive_id == new_dev->gpu->kfd->hive_id)) | |
| 1590 | + dev->gpu->kfd->hive_id == new_dev->gpu->kfd->hive_id && | |
| 1591 | + amdgpu_xgmi_get_is_sharing_enabled(dev->gpu->adev, new_dev->gpu->adev))) | |
| 1591 | 1592 | goto next; |
| 1592 | 1593 | |
| 1593 | 1594 | /* check if node(s) is/are peer accessible in one direction or bi-direction */ |
| @@ -2913,6 +2913,17 @@ static int dm_oem_i2c_hw_init(struct amdgpu_device *adev) · 2912 unmodified lines | ||
| 2913 | 2913 | return 0; |
| 2914 | 2914 | } |
| 2915 | 2915 | |
| 2916 | +static void dm_oem_i2c_hw_fini(struct amdgpu_device *adev) | |
| 2917 | +{ | |
| 2918 | + struct amdgpu_display_manager *dm = &adev->dm; | |
| 2919 | + | |
| 2920 | + if (dm->oem_i2c) { | |
| 2921 | + i2c_del_adapter(&dm->oem_i2c->base); | |
| 2922 | + kfree(dm->oem_i2c); | |
| 2923 | + dm->oem_i2c = NULL; | |
| 2924 | + } | |
| 2925 | +} | |
| 2926 | + | |
| 2916 | 2927 | /** |
| 2917 | 2928 | * dm_hw_init() - Initialize DC device |
| 2918 | 2929 | * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. |
| @@ -2963,7 +2974,7 @@ static int dm_hw_fini(struct amdgpu_ip_block *ip_block) · 44 unmodified lines | ||
| 2963 | 2974 | { |
| 2964 | 2975 | struct amdgpu_device *adev = ip_block->adev; |
| 2965 | 2976 | |
| 2966 | − kfree(adev->dm.oem_i2c); | |
| 2977 | + dm_oem_i2c_hw_fini(adev); | |
| 2967 | 2978 | |
| 2968 | 2979 | amdgpu_dm_hpd_fini(adev); |
| 2969 | 2980 | |
| @@ -3127,25 +3138,6 @@ static void dm_destroy_cached_state(struct amdgpu_device *adev) · 157 unmodified lines | ||
| 3127 | 3138 | dm->cached_state = NULL; |
| 3128 | 3139 | } |
| 3129 | 3140 | |
| 3130 | −static void dm_complete(struct amdgpu_ip_block *ip_block) | |
| 3131 | −{ | |
| 3132 | − struct amdgpu_device *adev = ip_block->adev; | |
| 3133 | − | |
| 3134 | − dm_destroy_cached_state(adev); | |
| 3135 | −} | |
| 3136 | − | |
| 3137 | −static int dm_prepare_suspend(struct amdgpu_ip_block *ip_block) | |
| 3138 | −{ | |
| 3139 | − struct amdgpu_device *adev = ip_block->adev; | |
| 3140 | − | |
| 3141 | − if (amdgpu_in_reset(adev)) | |
| 3142 | − return 0; | |
| 3143 | − | |
| 3144 | − WARN_ON(adev->dm.cached_state); | |
| 3145 | − | |
| 3146 | − return dm_cache_state(adev); | |
| 3147 | −} | |
| 3148 | − | |
| 3149 | 3141 | static int dm_suspend(struct amdgpu_ip_block *ip_block) |
| 3150 | 3142 | { |
| 3151 | 3143 | struct amdgpu_device *adev = ip_block->adev; |
| @@ -3571,10 +3563,8 @@ static const struct amd_ip_funcs amdgpu_dm_funcs = { · 419 unmodified lines | ||
| 3571 | 3563 | .early_fini = amdgpu_dm_early_fini, |
| 3572 | 3564 | .hw_init = dm_hw_init, |
| 3573 | 3565 | .hw_fini = dm_hw_fini, |
| 3574 | − .prepare_suspend = dm_prepare_suspend, | |
| 3575 | 3566 | .suspend = dm_suspend, |
| 3576 | 3567 | .resume = dm_resume, |
| 3577 | − .complete = dm_complete, | |
| 3578 | 3568 | .is_idle = dm_is_idle, |
| 3579 | 3569 | .wait_for_idle = dm_wait_for_idle, |
| 3580 | 3570 | .check_soft_reset = dm_check_soft_reset, |
| @@ -809,6 +809,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, · 808 unmodified lines | ||
| 809 | 809 | drm_dp_aux_init(&aconnector->dm_dp_aux.aux); |
| 810 | 810 | drm_dp_cec_register_connector(&aconnector->dm_dp_aux.aux, |
| 811 | 811 | &aconnector->base); |
| 812 | + drm_dp_dpcd_set_probe(&aconnector->dm_dp_aux.aux, false); | |
| 812 | 813 | |
| 813 | 814 | if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_eDP) |
| 814 | 815 | return; |
| @@ -1145,6 +1145,7 @@ struct dc_debug_options { · 1144 unmodified lines | ||
| 1145 | 1145 | bool enable_hblank_borrow; |
| 1146 | 1146 | bool force_subvp_df_throttle; |
| 1147 | 1147 | uint32_t acpi_transition_bitmasks[MAX_PIPES]; |
| 1148 | + bool enable_pg_cntl_debug_logs; | |
| 1148 | 1149 | }; |
| 1149 | 1150 | |
| 1150 | 1151 | |
| @@ -133,30 +133,34 @@ enum dsc_clk_source { · 132 unmodified lines | ||
| 133 | 133 | }; |
| 134 | 134 | |
| 135 | 135 | |
| 136 | −static void dccg35_set_dsc_clk_rcg(struct dccg *dccg, int inst, bool enable) | |
| 136 | +static void dccg35_set_dsc_clk_rcg(struct dccg *dccg, int inst, bool allow_rcg) | |
| 137 | 137 | { |
| 138 | 138 | struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); |
| 139 | 139 | |
| 140 | − if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc && enable) | |
| 140 | + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc && allow_rcg) | |
| 141 | 141 | return; |
| 142 | 142 | |
| 143 | 143 | switch (inst) { |
| 144 | 144 | case 0: |
| 145 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 145 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 146 | 146 | break; |
| 147 | 147 | case 1: |
| 148 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 148 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 149 | 149 | break; |
| 150 | 150 | case 2: |
| 151 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 151 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 152 | 152 | break; |
| 153 | 153 | case 3: |
| 154 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 154 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 155 | 155 | break; |
| 156 | 156 | default: |
| 157 | 157 | BREAK_TO_DEBUGGER(); |
| 158 | 158 | return; |
| 159 | 159 | } |
| 160 | + | |
| 161 | + /* Wait for clock to ramp */ | |
| 162 | + if (!allow_rcg) | |
| 163 | + udelay(10); | |
| 160 | 164 | } |
| 161 | 165 | |
| 162 | 166 | static void dccg35_set_symclk32_se_rcg( |
| @@ -385,35 +389,34 @@ static void dccg35_set_dtbclk_p_rcg(struct dccg *dccg, int inst, bool enable) · 222 unmodified lines | ||
| 385 | 389 | } |
| 386 | 390 | } |
| 387 | 391 | |
| 388 | −static void dccg35_set_dppclk_rcg(struct dccg *dccg, | |
| 389 | − int inst, bool enable) | |
| 392 | +static void dccg35_set_dppclk_rcg(struct dccg *dccg, int inst, bool allow_rcg) | |
| 390 | 393 | { |
| 391 | − | |
| 392 | 394 | struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); |
| 393 | 395 | |
| 394 | − | |
| 395 | − if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && enable) | |
| 396 | + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && allow_rcg) | |
| 396 | 397 | return; |
| 397 | 398 | |
| 398 | 399 | switch (inst) { |
| 399 | 400 | case 0: |
| 400 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 401 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 401 | 402 | break; |
| 402 | 403 | case 1: |
| 403 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 404 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 404 | 405 | break; |
| 405 | 406 | case 2: |
| 406 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 407 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 407 | 408 | break; |
| 408 | 409 | case 3: |
| 409 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable ? 0 : 1); | |
| 410 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1); | |
| 410 | 411 | break; |
| 411 | 412 | default: |
| 412 | 413 | BREAK_TO_DEBUGGER(); |
| 413 | 414 | break; |
| 414 | 415 | } |
| 415 | − //DC_LOG_DEBUG("%s: inst(%d) DPPCLK rcg_disable: %d\n", __func__, inst, enable ? 0 : 1); | |
| 416 | 416 | |
| 417 | + /* Wait for clock to ramp */ | |
| 418 | + if (!allow_rcg) | |
| 419 | + udelay(10); | |
| 417 | 420 | } |
| 418 | 421 | |
| 419 | 422 | static void dccg35_set_dpstreamclk_rcg( |
| @@ -1177,32 +1180,34 @@ static void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst, · 757 unmodified lines | ||
| 1177 | 1180 | } |
| 1178 | 1181 | |
| 1179 | 1182 | static void dccg35_set_dppclk_root_clock_gating(struct dccg *dccg, |
| 1180 | − uint32_t dpp_inst, uint32_t enable) | |
| 1183 | + uint32_t dpp_inst, uint32_t disallow_rcg) | |
| 1181 | 1184 | { |
| 1182 | 1185 | struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); |
| 1183 | 1186 | |
| 1184 | − if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) | |
| 1187 | + if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && !disallow_rcg) | |
| 1185 | 1188 | return; |
| 1186 | 1189 | |
| 1187 | 1190 | |
| 1188 | 1191 | switch (dpp_inst) { |
| 1189 | 1192 | case 0: |
| 1190 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable); | |
| 1193 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, disallow_rcg); | |
| 1191 | 1194 | break; |
| 1192 | 1195 | case 1: |
| 1193 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable); | |
| 1196 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, disallow_rcg); | |
| 1194 | 1197 | break; |
| 1195 | 1198 | case 2: |
| 1196 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable); | |
| 1199 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, disallow_rcg); | |
| 1197 | 1200 | break; |
| 1198 | 1201 | case 3: |
| 1199 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable); | |
| 1202 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, disallow_rcg); | |
| 1200 | 1203 | break; |
| 1201 | 1204 | default: |
| 1202 | 1205 | break; |
| 1203 | 1206 | } |
| 1204 | − //DC_LOG_DEBUG("%s: dpp_inst(%d) rcg: %d\n", __func__, dpp_inst, enable); | |
| 1205 | 1207 | |
| 1208 | + /* Wait for clock to ramp */ | |
| 1209 | + if (disallow_rcg) | |
| 1210 | + udelay(10); | |
| 1206 | 1211 | } |
| 1207 | 1212 | |
| 1208 | 1213 | static void dccg35_get_pixel_rate_div( |
| @@ -1782,8 +1787,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst) · 573 unmodified lines | ||
| 1782 | 1787 | //Disable DTO |
| 1783 | 1788 | switch (inst) { |
| 1784 | 1789 | case 0: |
| 1785 | − if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc) | |
| 1786 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, 1); | |
| 1790 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, 1); | |
| 1787 | 1791 | |
| 1788 | 1792 | REG_UPDATE_2(DSCCLK0_DTO_PARAM, |
| 1789 | 1793 | DSCCLK0_DTO_PHASE, 0, |
| @@ -1791,8 +1795,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst) · 1 unmodified line | ||
| 1791 | 1795 | REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1); |
| 1792 | 1796 | break; |
| 1793 | 1797 | case 1: |
| 1794 | − if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc) | |
| 1795 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, 1); | |
| 1798 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, 1); | |
| 1796 | 1799 | |
| 1797 | 1800 | REG_UPDATE_2(DSCCLK1_DTO_PARAM, |
| 1798 | 1801 | DSCCLK1_DTO_PHASE, 0, |
| @@ -1800,8 +1803,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst) · 1 unmodified line | ||
| 1800 | 1803 | REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1); |
| 1801 | 1804 | break; |
| 1802 | 1805 | case 2: |
| 1803 | − if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc) | |
| 1804 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, 1); | |
| 1806 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, 1); | |
| 1805 | 1807 | |
| 1806 | 1808 | REG_UPDATE_2(DSCCLK2_DTO_PARAM, |
| 1807 | 1809 | DSCCLK2_DTO_PHASE, 0, |
| @@ -1809,8 +1811,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst) · 1 unmodified line | ||
| 1809 | 1811 | REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1); |
| 1810 | 1812 | break; |
| 1811 | 1813 | case 3: |
| 1812 | − if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc) | |
| 1813 | − REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, 1); | |
| 1814 | + REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, 1); | |
| 1814 | 1815 | |
| 1815 | 1816 | REG_UPDATE_2(DSCCLK3_DTO_PARAM, |
| 1816 | 1817 | DSCCLK3_DTO_PHASE, 0, |
| @@ -1821,6 +1822,9 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst) · 4 unmodified lines | ||
| 1821 | 1822 | BREAK_TO_DEBUGGER(); |
| 1822 | 1823 | return; |
| 1823 | 1824 | } |
| 1825 | + | |
| 1826 | + /* Wait for clock to ramp */ | |
| 1827 | + udelay(10); | |
| 1824 | 1828 | } |
| 1825 | 1829 | |
| 1826 | 1830 | static void dccg35_disable_dscclk(struct dccg *dccg, |
| @@ -1864,6 +1868,9 @@ static void dccg35_disable_dscclk(struct dccg *dccg, · 37 unmodified lines | ||
| 1864 | 1868 | default: |
| 1865 | 1869 | return; |
| 1866 | 1870 | } |
| 1871 | + | |
| 1872 | + /* Wait for clock ramp */ | |
| 1873 | + udelay(10); | |
| 1867 | 1874 | } |
| 1868 | 1875 | |
| 1869 | 1876 | static void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst) |
| @@ -2349,10 +2356,7 @@ static void dccg35_disable_symclk_se_cb( · 479 unmodified lines | ||
| 2349 | 2356 | |
| 2350 | 2357 | void dccg35_root_gate_disable_control(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating) |
| 2351 | 2358 | { |
| 2352 | − | |
| 2353 | − if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) { | |
| 2354 | − dccg35_set_dppclk_root_clock_gating(dccg, pipe_idx, disable_clock_gating); | |
| 2355 | − } | |
| 2359 | + dccg35_set_dppclk_root_clock_gating(dccg, pipe_idx, disable_clock_gating); | |
| 2356 | 2360 | } |
| 2357 | 2361 | |
| 2358 | 2362 | static const struct dccg_funcs dccg35_funcs_new = { |
| @@ -955,7 +955,7 @@ enum dc_status dcn20_enable_stream_timing( · 954 unmodified lines | ||
| 955 | 955 | return DC_ERROR_UNEXPECTED; |
| 956 | 956 | } |
| 957 | 957 | |
| 958 | − fsleep(stream->timing.v_total * (stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz)); | |
| 958 | + udelay(stream->timing.v_total * (stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz)); | |
| 959 | 959 | |
| 960 | 960 | params.vertical_total_min = stream->adjust.v_total_min; |
| 961 | 961 | params.vertical_total_max = stream->adjust.v_total_max; |
| @@ -113,6 +113,14 @@ static void enable_memory_low_power(struct dc *dc) · 112 unmodified lines | ||
| 113 | 113 | } |
| 114 | 114 | #endif |
| 115 | 115 | |
| 116 | +static void print_pg_status(struct dc *dc, const char *debug_func, const char *debug_log) | |
| 117 | +{ | |
| 118 | + if (dc->debug.enable_pg_cntl_debug_logs && dc->res_pool->pg_cntl) { | |
| 119 | + if (dc->res_pool->pg_cntl->funcs->print_pg_status) | |
| 120 | + dc->res_pool->pg_cntl->funcs->print_pg_status(dc->res_pool->pg_cntl, debug_func, debug_log); | |
| 121 | + } | |
| 122 | +} | |
| 123 | + | |
| 116 | 124 | void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable) |
| 117 | 125 | { |
| 118 | 126 | REG_UPDATE_3(DMU_CLK_CNTL, |
| @@ -137,6 +145,8 @@ void dcn35_init_hw(struct dc *dc) · 18 unmodified lines | ||
| 137 | 145 | uint32_t user_level = MAX_BACKLIGHT_LEVEL; |
| 138 | 146 | int i; |
| 139 | 147 | |
| 148 | + print_pg_status(dc, __func__, ": start"); | |
| 149 | + | |
| 140 | 150 | if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) |
| 141 | 151 | dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); |
| 142 | 152 | |
| @@ -200,10 +210,7 @@ void dcn35_init_hw(struct dc *dc) · 57 unmodified lines | ||
| 200 | 210 | |
| 201 | 211 | /* we want to turn off all dp displays before doing detection */ |
| 202 | 212 | dc->link_srv->blank_all_dp_displays(dc); |
| 203 | −/* | |
| 204 | − if (hws->funcs.enable_power_gating_plane) | |
| 205 | − hws->funcs.enable_power_gating_plane(dc->hwseq, true); | |
| 206 | −*/ | |
| 213 | + | |
| 207 | 214 | if (res_pool->hubbub && res_pool->hubbub->funcs->dchubbub_init) |
| 208 | 215 | res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub); |
| 209 | 216 | /* If taking control over from VBIOS, we may want to optimize our first |
| @@ -236,6 +243,8 @@ void dcn35_init_hw(struct dc *dc) · 26 unmodified lines | ||
| 236 | 243 | } |
| 237 | 244 | |
| 238 | 245 | hws->funcs.init_pipes(dc, dc->current_state); |
| 246 | + print_pg_status(dc, __func__, ": after init_pipes"); | |
| 247 | + | |
| 239 | 248 | if (dc->res_pool->hubbub->funcs->allow_self_refresh_control && |
| 240 | 249 | !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter) |
| 241 | 250 | dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, |
| @@ -312,6 +321,7 @@ void dcn35_init_hw(struct dc *dc) · 70 unmodified lines | ||
| 312 | 321 | if (dc->res_pool->pg_cntl->funcs->init_pg_status) |
| 313 | 322 | dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl); |
| 314 | 323 | } |
| 324 | + print_pg_status(dc, __func__, ": after init_pg_status"); | |
| 315 | 325 | } |
| 316 | 326 | |
| 317 | 327 | static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) |
| @@ -500,97 +510,6 @@ void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_ · 182 unmodified lines | ||
| 500 | 510 | } |
| 501 | 511 | } |
| 502 | 512 | |
| 503 | −void dcn35_dsc_pg_control( | |
| 504 | − struct dce_hwseq *hws, | |
| 505 | − unsigned int dsc_inst, | |
| 506 | − bool power_on) | |
| 507 | −{ | |
| 508 | − uint32_t power_gate = power_on ? 0 : 1; | |
| 509 | − uint32_t pwr_status = power_on ? 0 : 2; | |
| 510 | − uint32_t org_ip_request_cntl = 0; | |
| 511 | − | |
| 512 | − if (hws->ctx->dc->debug.disable_dsc_power_gate) | |
| 513 | − return; | |
| 514 | − if (hws->ctx->dc->debug.ignore_pg) | |
| 515 | − return; | |
| 516 | − REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); | |
| 517 | − if (org_ip_request_cntl == 0) | |
| 518 | − REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); | |
| 519 | − | |
| 520 | − switch (dsc_inst) { | |
| 521 | − case 0: /* DSC0 */ | |
| 522 | − REG_UPDATE(DOMAIN16_PG_CONFIG, | |
| 523 | − DOMAIN_POWER_GATE, power_gate); | |
| 524 | − | |
| 525 | − REG_WAIT(DOMAIN16_PG_STATUS, | |
| 526 | − DOMAIN_PGFSM_PWR_STATUS, pwr_status, | |
| 527 | − 1, 1000); | |
| 528 | − break; | |
| 529 | − case 1: /* DSC1 */ | |
| 530 | − REG_UPDATE(DOMAIN17_PG_CONFIG, | |
| 531 | − DOMAIN_POWER_GATE, power_gate); | |
| 532 | − | |
| 533 | − REG_WAIT(DOMAIN17_PG_STATUS, | |
| 534 | − DOMAIN_PGFSM_PWR_STATUS, pwr_status, | |
| 535 | − 1, 1000); | |
| 536 | − break; | |
| 537 | − case 2: /* DSC2 */ | |
| 538 | − REG_UPDATE(DOMAIN18_PG_CONFIG, | |
| 539 | − DOMAIN_POWER_GATE, power_gate); | |
| 540 | − | |
| 541 | − REG_WAIT(DOMAIN18_PG_STATUS, | |
| 542 | − DOMAIN_PGFSM_PWR_STATUS, pwr_status, | |
| 543 | − 1, 1000); | |
| 544 | − break; | |
| 545 | − case 3: /* DSC3 */ | |
| 546 | − REG_UPDATE(DOMAIN19_PG_CONFIG, | |
| 547 | − DOMAIN_POWER_GATE, power_gate); | |
| 548 | − | |
| 549 | − REG_WAIT(DOMAIN19_PG_STATUS, | |
| 550 | − DOMAIN_PGFSM_PWR_STATUS, pwr_status, | |
| 551 | − 1, 1000); | |
| 552 | − break; | |
| 553 | − default: | |
| 554 | − BREAK_TO_DEBUGGER(); | |
| 555 | − break; | |
| 556 | − } | |
| 557 | − | |
| 558 | − if (org_ip_request_cntl == 0) | |
| 559 | − REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); | |
| 560 | −} | |
| 561 | − | |
| 562 | −void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) | |
| 563 | −{ | |
| 564 | − bool force_on = true; /* disable power gating */ | |
| 565 | − uint32_t org_ip_request_cntl = 0; | |
| 566 | − | |
| 567 | − if (hws->ctx->dc->debug.disable_hubp_power_gate) | |
| 568 | − return; | |
| 569 | − if (hws->ctx->dc->debug.ignore_pg) | |
| 570 | − return; | |
| 571 | − REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); | |
| 572 | − if (org_ip_request_cntl == 0) | |
| 573 | − REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); | |
| 574 | − /* DCHUBP0/1/2/3/4/5 */ | |
| 575 | − REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 576 | − REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 577 | − /* DPP0/1/2/3/4/5 */ | |
| 578 | − REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 579 | − REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 580 | − | |
| 581 | − force_on = true; /* disable power gating */ | |
| 582 | − if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) | |
| 583 | − force_on = false; | |
| 584 | − | |
| 585 | − /* DCS0/1/2/3/4 */ | |
| 586 | − REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 587 | − REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 588 | − REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 589 | − REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); | |
| 590 | − | |
| 591 | − | |
| 592 | −} | |
| 593 | − | |
| 594 | 513 | /* In headless boot cases, DIG may be turned |
| 595 | 514 | * on which causes HW/SW discrepancies. |
| 596 | 515 | * To avoid this, power down hardware on boot |
| @@ -1453,6 +1372,8 @@ void dcn35_prepare_bandwidth( · 856 unmodified lines | ||
| 1453 | 1372 | } |
| 1454 | 1373 | |
| 1455 | 1374 | dcn20_prepare_bandwidth(dc, context); |
| 1375 | + | |
| 1376 | + print_pg_status(dc, __func__, ": after rcg and power up"); | |
| 1456 | 1377 | } |
| 1457 | 1378 | |
| 1458 | 1379 | void dcn35_optimize_bandwidth( |
| @@ -1461,6 +1382,8 @@ void dcn35_optimize_bandwidth( · 2 unmodified lines | ||
| 1461 | 1382 | { |
| 1462 | 1383 | struct pg_block_update pg_update_state; |
| 1463 | 1384 | |
| 1385 | + print_pg_status(dc, __func__, ": before rcg and power up"); | |
| 1386 | + | |
| 1464 | 1387 | dcn20_optimize_bandwidth(dc, context); |
| 1465 | 1388 | |
| 1466 | 1389 | if (dc->hwss.calc_blocks_to_gate) { |
| @@ -1472,6 +1395,8 @@ void dcn35_optimize_bandwidth( · 5 unmodified lines | ||
| 1472 | 1395 | if (dc->hwss.root_clock_control) |
| 1473 | 1396 | dc->hwss.root_clock_control(dc, &pg_update_state, false); |
| 1474 | 1397 | } |
| 1398 | + | |
| 1399 | + print_pg_status(dc, __func__, ": after rcg and power up"); | |
| 1475 | 1400 | } |
| 1476 | 1401 | |
| 1477 | 1402 | void dcn35_set_drr(struct pipe_ctx **pipe_ctx, |
| @@ -115,7 +115,6 @@ static const struct hw_sequencer_funcs dcn35_funcs = { · 114 unmodified lines | ||
| 115 | 115 | .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, |
| 116 | 116 | .update_visual_confirm_color = dcn10_update_visual_confirm_color, |
| 117 | 117 | .apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations, |
| 118 | − .update_dsc_pg = dcn32_update_dsc_pg, | |
| 119 | 118 | .calc_blocks_to_gate = dcn35_calc_blocks_to_gate, |
| 120 | 119 | .calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate, |
| 121 | 120 | .hw_block_power_up = dcn35_hw_block_power_up, |
| @@ -150,7 +149,6 @@ static const struct hwseq_private_funcs dcn35_private_funcs = { · 28 unmodified lines | ||
| 150 | 149 | .plane_atomic_disable = dcn35_plane_atomic_disable, |
| 151 | 150 | //.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/ |
| 152 | 151 | //.hubp_pg_control = dcn35_hubp_pg_control, |
| 153 | − .enable_power_gating_plane = dcn35_enable_power_gating_plane, | |
| 154 | 152 | .dpp_root_clock_control = dcn35_dpp_root_clock_control, |
| 155 | 153 | .dpstream_root_clock_control = dcn35_dpstream_root_clock_control, |
| 156 | 154 | .physymclk_root_clock_control = dcn35_physymclk_root_clock_control, |
| @@ -165,7 +163,6 @@ static const struct hwseq_private_funcs dcn35_private_funcs = { · 8 unmodified lines | ||
| 165 | 163 | .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, |
| 166 | 164 | .resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio, |
| 167 | 165 | .is_dp_dig_pixel_rate_div_policy = dcn35_is_dp_dig_pixel_rate_div_policy, |
| 168 | − .dsc_pg_control = dcn35_dsc_pg_control, | |
| 169 | 166 | .dsc_pg_status = dcn32_dsc_pg_status, |
| 170 | 167 | .enable_plane = dcn35_enable_plane, |
| 171 | 168 | .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed, |
| @@ -114,7 +114,6 @@ static const struct hw_sequencer_funcs dcn351_funcs = { · 113 unmodified lines | ||
| 114 | 114 | .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, |
| 115 | 115 | .update_visual_confirm_color = dcn10_update_visual_confirm_color, |
| 116 | 116 | .apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations, |
| 117 | − .update_dsc_pg = dcn32_update_dsc_pg, | |
| 118 | 117 | .calc_blocks_to_gate = dcn351_calc_blocks_to_gate, |
| 119 | 118 | .calc_blocks_to_ungate = dcn351_calc_blocks_to_ungate, |
| 120 | 119 | .hw_block_power_up = dcn351_hw_block_power_up, |
| @@ -145,7 +144,6 @@ static const struct hwseq_private_funcs dcn351_private_funcs = { · 24 unmodified lines | ||
| 145 | 144 | .plane_atomic_disable = dcn35_plane_atomic_disable, |
| 146 | 145 | //.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/ |
| 147 | 146 | //.hubp_pg_control = dcn35_hubp_pg_control, |
| 148 | − .enable_power_gating_plane = dcn35_enable_power_gating_plane, | |
| 149 | 147 | .dpp_root_clock_control = dcn35_dpp_root_clock_control, |
| 150 | 148 | .dpstream_root_clock_control = dcn35_dpstream_root_clock_control, |
| 151 | 149 | .physymclk_root_clock_control = dcn35_physymclk_root_clock_control, |
| @@ -159,7 +157,6 @@ static const struct hwseq_private_funcs dcn351_private_funcs = { · 7 unmodified lines | ||
| 159 | 157 | .setup_hpo_hw_control = dcn35_setup_hpo_hw_control, |
| 160 | 158 | .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, |
| 161 | 159 | .is_dp_dig_pixel_rate_div_policy = dcn35_is_dp_dig_pixel_rate_div_policy, |
| 162 | − .dsc_pg_control = dcn35_dsc_pg_control, | |
| 163 | 160 | .dsc_pg_status = dcn32_dsc_pg_status, |
| 164 | 161 | .enable_plane = dcn35_enable_plane, |
| 165 | 162 | .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed, |
| @@ -49,6 +49,7 @@ struct pg_cntl_funcs { · 48 unmodified lines | ||
| 49 | 49 | void (*mem_pg_control)(struct pg_cntl *pg_cntl, bool power_on); |
| 50 | 50 | void (*dio_pg_control)(struct pg_cntl *pg_cntl, bool power_on); |
| 51 | 51 | void (*init_pg_status)(struct pg_cntl *pg_cntl); |
| 52 | + void (*print_pg_status)(struct pg_cntl *pg_cntl, const char *debug_func, const char *debug_log); | |
| 52 | 53 | }; |
| 53 | 54 | |
| 54 | 55 | #endif //__DC_PG_CNTL_H__ |
| @@ -79,16 +79,12 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo · 78 unmodified lines | ||
| 79 | 79 | uint32_t power_gate = power_on ? 0 : 1; |
| 80 | 80 | uint32_t pwr_status = power_on ? 0 : 2; |
| 81 | 81 | uint32_t org_ip_request_cntl = 0; |
| 82 | − bool block_enabled; | |
| 83 | − | |
| 84 | − /*need to enable dscclk regardless DSC_PG*/ | |
| 85 | − if (pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc && power_on) | |
| 86 | − pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc( | |
| 87 | − pg_cntl->ctx->dc->res_pool->dccg, dsc_inst); | |
| 82 | + bool block_enabled = false; | |
| 83 | + bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || | |
| 84 | + pg_cntl->ctx->dc->debug.disable_dsc_power_gate || | |
| 85 | + pg_cntl->ctx->dc->idle_optimizations_allowed; | |
| 88 | 86 | |
| 89 | − if (pg_cntl->ctx->dc->debug.ignore_pg || | |
| 90 | − pg_cntl->ctx->dc->debug.disable_dsc_power_gate || | |
| 91 | − pg_cntl->ctx->dc->idle_optimizations_allowed) | |
| 87 | + if (skip_pg && !power_on) | |
| 92 | 88 | return; |
| 93 | 89 | |
| 94 | 90 | block_enabled = pg_cntl35_dsc_pg_status(pg_cntl, dsc_inst); |
| @@ -111,7 +107,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo · 16 unmodified lines | ||
| 111 | 107 | |
| 112 | 108 | REG_WAIT(DOMAIN16_PG_STATUS, |
| 113 | 109 | DOMAIN_PGFSM_PWR_STATUS, pwr_status, |
| 114 | − 1, 1000); | |
| 110 | + 1, 10000); | |
| 115 | 111 | break; |
| 116 | 112 | case 1: /* DSC1 */ |
| 117 | 113 | REG_UPDATE(DOMAIN17_PG_CONFIG, |
| @@ -119,7 +115,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo · 1 unmodified line | ||
| 119 | 115 | |
| 120 | 116 | REG_WAIT(DOMAIN17_PG_STATUS, |
| 121 | 117 | DOMAIN_PGFSM_PWR_STATUS, pwr_status, |
| 122 | − 1, 1000); | |
| 118 | + 1, 10000); | |
| 123 | 119 | break; |
| 124 | 120 | case 2: /* DSC2 */ |
| 125 | 121 | REG_UPDATE(DOMAIN18_PG_CONFIG, |
| @@ -127,7 +123,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo · 1 unmodified line | ||
| 127 | 123 | |
| 128 | 124 | REG_WAIT(DOMAIN18_PG_STATUS, |
| 129 | 125 | DOMAIN_PGFSM_PWR_STATUS, pwr_status, |
| 130 | − 1, 1000); | |
| 126 | + 1, 10000); | |
| 131 | 127 | break; |
| 132 | 128 | case 3: /* DSC3 */ |
| 133 | 129 | REG_UPDATE(DOMAIN19_PG_CONFIG, |
| @@ -135,7 +131,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo · 1 unmodified line | ||
| 135 | 131 | |
| 136 | 132 | REG_WAIT(DOMAIN19_PG_STATUS, |
| 137 | 133 | DOMAIN_PGFSM_PWR_STATUS, pwr_status, |
| 138 | − 1, 1000); | |
| 134 | + 1, 10000); | |
| 139 | 135 | break; |
| 140 | 136 | default: |
| 141 | 137 | BREAK_TO_DEBUGGER(); |
| @@ -144,12 +140,6 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo · 2 unmodified lines | ||
| 144 | 140 | |
| 145 | 141 | if (dsc_inst < MAX_PIPES) |
| 146 | 142 | pg_cntl->pg_pipe_res_enable[PG_DSC][dsc_inst] = power_on; |
| 147 | − | |
| 148 | − if (pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) { | |
| 149 | − /*this is to disable dscclk*/ | |
| 150 | − pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc( | |
| 151 | − pg_cntl->ctx->dc->res_pool->dccg, dsc_inst); | |
| 152 | − } | |
| 153 | 143 | } |
| 154 | 144 | |
| 155 | 145 | static bool pg_cntl35_hubp_dpp_pg_status(struct pg_cntl *pg_cntl, unsigned int hubp_dpp_inst) |
| @@ -189,11 +179,12 @@ void pg_cntl35_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp · 33 unmodified lines | ||
| 189 | 179 | uint32_t pwr_status = power_on ? 0 : 2; |
| 190 | 180 | uint32_t org_ip_request_cntl; |
| 191 | 181 | bool block_enabled; |
| 182 | + bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || | |
| 183 | + pg_cntl->ctx->dc->debug.disable_hubp_power_gate || | |
| 184 | + pg_cntl->ctx->dc->debug.disable_dpp_power_gate || | |
| 185 | + pg_cntl->ctx->dc->idle_optimizations_allowed; | |
| 192 | 186 | |
| 193 | − if (pg_cntl->ctx->dc->debug.ignore_pg || | |
| 194 | − pg_cntl->ctx->dc->debug.disable_hubp_power_gate || | |
| 195 | − pg_cntl->ctx->dc->debug.disable_dpp_power_gate || | |
| 196 | − pg_cntl->ctx->dc->idle_optimizations_allowed) | |
| 187 | + if (skip_pg && !power_on) | |
| 197 | 188 | return; |
| 198 | 189 | |
| 199 | 190 | block_enabled = pg_cntl35_hubp_dpp_pg_status(pg_cntl, hubp_dpp_inst); |
| @@ -213,22 +204,22 @@ void pg_cntl35_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp · 13 unmodified lines | ||
| 213 | 204 | case 0: |
| 214 | 205 | /* DPP0 & HUBP0 */ |
| 215 | 206 | REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); |
| 216 | − REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); | |
| 207 | + REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000); | |
| 217 | 208 | break; |
| 218 | 209 | case 1: |
| 219 | 210 | /* DPP1 & HUBP1 */ |
| 220 | 211 | REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); |
| 221 | − REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); | |
| 212 | + REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000); | |
| 222 | 213 | break; |
| 223 | 214 | case 2: |
| 224 | 215 | /* DPP2 & HUBP2 */ |
| 225 | 216 | REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); |
| 226 | − REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); | |
| 217 | + REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000); | |
| 227 | 218 | break; |
| 228 | 219 | case 3: |
| 229 | 220 | /* DPP3 & HUBP3 */ |
| 230 | 221 | REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); |
| 231 | − REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); | |
| 222 | + REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000); | |
| 232 | 223 | break; |
| 233 | 224 | default: |
| 234 | 225 | BREAK_TO_DEBUGGER(); |
| @@ -501,6 +492,36 @@ void pg_cntl35_init_pg_status(struct pg_cntl *pg_cntl) · 266 unmodified lines | ||
| 501 | 492 | pg_cntl->pg_res_enable[PG_DWB] = block_enabled; |
| 502 | 493 | } |
| 503 | 494 | |
| 495 | +static void pg_cntl35_print_pg_status(struct pg_cntl *pg_cntl, const char *debug_func, const char *debug_log) | |
| 496 | +{ | |
| 497 | + int i = 0; | |
| 498 | + bool block_enabled = false; | |
| 499 | + | |
| 500 | + DC_LOG_DEBUG("%s: %s", debug_func, debug_log); | |
| 501 | + | |
| 502 | + DC_LOG_DEBUG("PG_CNTL status:\n"); | |
| 503 | + | |
| 504 | + block_enabled = pg_cntl35_io_clk_status(pg_cntl); | |
| 505 | + DC_LOG_DEBUG("ONO0=%d (DCCG, DIO, DCIO)\n", block_enabled ? 1 : 0); | |
| 506 | + | |
| 507 | + block_enabled = pg_cntl35_mem_status(pg_cntl); | |
| 508 | + DC_LOG_DEBUG("ONO1=%d (DCHUBBUB, DCHVM, DCHUBBUBMEM)\n", block_enabled ? 1 : 0); | |
| 509 | + | |
| 510 | + block_enabled = pg_cntl35_plane_otg_status(pg_cntl); | |
| 511 | + DC_LOG_DEBUG("ONO2=%d (MPC, OPP, OPTC, DWB)\n", block_enabled ? 1 : 0); | |
| 512 | + | |
| 513 | + block_enabled = pg_cntl35_hpo_pg_status(pg_cntl); | |
| 514 | + DC_LOG_DEBUG("ONO3=%d (HPO)\n", block_enabled ? 1 : 0); | |
| 515 | + | |
| 516 | + for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) { | |
| 517 | + block_enabled = pg_cntl35_hubp_dpp_pg_status(pg_cntl, i); | |
| 518 | + DC_LOG_DEBUG("ONO%d=%d (DCHUBP%d, DPP%d)\n", 4 + i * 2, block_enabled ? 1 : 0, i, i); | |
| 519 | + | |
| 520 | + block_enabled = pg_cntl35_dsc_pg_status(pg_cntl, i); | |
| 521 | + DC_LOG_DEBUG("ONO%d=%d (DSC%d)\n", 5 + i * 2, block_enabled ? 1 : 0, i); | |
| 522 | + } | |
| 523 | +} | |
| 524 | + | |
| 504 | 525 | static const struct pg_cntl_funcs pg_cntl35_funcs = { |
| 505 | 526 | .init_pg_status = pg_cntl35_init_pg_status, |
| 506 | 527 | .dsc_pg_control = pg_cntl35_dsc_pg_control, |
| @@ -511,7 +532,8 @@ static const struct pg_cntl_funcs pg_cntl35_funcs = { · 4 unmodified lines | ||
| 511 | 532 | .mpcc_pg_control = pg_cntl35_mpcc_pg_control, |
| 512 | 533 | .opp_pg_control = pg_cntl35_opp_pg_control, |
| 513 | 534 | .optc_pg_control = pg_cntl35_optc_pg_control, |
| 514 | − .dwb_pg_control = pg_cntl35_dwb_pg_control | |
| 535 | + .dwb_pg_control = pg_cntl35_dwb_pg_control, | |
| 536 | + .print_pg_status = pg_cntl35_print_pg_status | |
| 515 | 537 | }; |
| 516 | 538 | |
| 517 | 539 | struct pg_cntl *pg_cntl35_create( |
| @@ -1172,7 +1172,7 @@ static void icl_mbus_init(struct intel_display *display) · 1171 unmodified lines | ||
| 1172 | 1172 | if (DISPLAY_VER(display) == 12) |
| 1173 | 1173 | abox_regs |= BIT(0); |
| 1174 | 1174 | |
| 1175 | − for_each_set_bit(i, &abox_regs, sizeof(abox_regs)) | |
| 1175 | + for_each_set_bit(i, &abox_regs, BITS_PER_TYPE(abox_regs)) | |
| 1176 | 1176 | intel_de_rmw(display, MBUS_ABOX_CTL(i), mask, val); |
| 1177 | 1177 | } |
| 1178 | 1178 | |
| @@ -1629,11 +1629,11 @@ static void tgl_bw_buddy_init(struct intel_display *display) · 450 unmodified lines | ||
| 1629 | 1629 | if (table[config].page_mask == 0) { |
| 1630 | 1630 | drm_dbg_kms(display->drm, |
| 1631 | 1631 | "Unknown memory configuration; disabling address buddy logic.\n"); |
| 1632 | − for_each_set_bit(i, &abox_mask, sizeof(abox_mask)) | |
| 1632 | + for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) | |
| 1633 | 1633 | intel_de_write(display, BW_BUDDY_CTL(i), |
| 1634 | 1634 | BW_BUDDY_DISABLE); |
| 1635 | 1635 | } else { |
| 1636 | − for_each_set_bit(i, &abox_mask, sizeof(abox_mask)) { | |
| 1636 | + for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) { | |
| 1637 | 1637 | intel_de_write(display, BW_BUDDY_PAGE_MASK(i), |
| 1638 | 1638 | table[config].page_mask); |
| 1639 | 1639 | |
| @@ -387,19 +387,21 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) · 386 unmodified lines | ||
| 387 | 387 | |
| 388 | 388 | of_id = of_match_node(mtk_drm_of_ids, node); |
| 389 | 389 | if (!of_id) |
| 390 | − goto next_put_node; | |
| 390 | + continue; | |
| 391 | 391 | |
| 392 | 392 | pdev = of_find_device_by_node(node); |
| 393 | 393 | if (!pdev) |
| 394 | − goto next_put_node; | |
| 394 | + continue; | |
| 395 | 395 | |
| 396 | 396 | drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match); |
| 397 | + put_device(&pdev->dev); | |
| 397 | 398 | if (!drm_dev) |
| 398 | − goto next_put_device_pdev_dev; | |
| 399 | + continue; | |
| 399 | 400 | |
| 400 | 401 | temp_drm_priv = dev_get_drvdata(drm_dev); |
| 402 | + put_device(drm_dev); | |
| 401 | 403 | if (!temp_drm_priv) |
| 402 | − goto next_put_device_drm_dev; | |
| 404 | + continue; | |
| 403 | 405 | |
| 404 | 406 | if (temp_drm_priv->data->main_len) |
| 405 | 407 | all_drm_priv[CRTC_MAIN] = temp_drm_priv; |
| @@ -411,17 +413,10 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev) · 5 unmodified lines | ||
| 411 | 413 | if (temp_drm_priv->mtk_drm_bound) |
| 412 | 414 | cnt++; |
| 413 | 415 | |
| 414 | −next_put_device_drm_dev: | |
| 415 | − put_device(drm_dev); | |
| 416 | − | |
| 417 | −next_put_device_pdev_dev: | |
| 418 | − put_device(&pdev->dev); | |
| 419 | − | |
| 420 | −next_put_node: | |
| 421 | − of_node_put(node); | |
| 422 | − | |
| 423 | − if (cnt == MAX_CRTC) | |
| 416 | + if (cnt == MAX_CRTC) { | |
| 417 | + of_node_put(node); | |
| 424 | 418 | break; |
| 419 | + } | |
| 425 | 420 | } |
| 426 | 421 | |
| 427 | 422 | if (drm_priv->data->mmsys_dev_num == cnt) { |
| @@ -240,21 +240,6 @@ nouveau_fence_emit(struct nouveau_fence *fence) · 239 unmodified lines | ||
| 240 | 240 | return ret; |
| 241 | 241 | } |
| 242 | 242 | |
| 243 | −void | |
| 244 | −nouveau_fence_cancel(struct nouveau_fence *fence) | |
| 245 | −{ | |
| 246 | − struct nouveau_fence_chan *fctx = nouveau_fctx(fence); | |
| 247 | − unsigned long flags; | |
| 248 | − | |
| 249 | − spin_lock_irqsave(&fctx->lock, flags); | |
| 250 | − if (!dma_fence_is_signaled_locked(&fence->base)) { | |
| 251 | − dma_fence_set_error(&fence->base, -ECANCELED); | |
| 252 | − if (nouveau_fence_signal(fence)) | |
| 253 | − nvif_event_block(&fctx->event); | |
| 254 | − } | |
| 255 | − spin_unlock_irqrestore(&fctx->lock, flags); | |
| 256 | −} | |
| 257 | − | |
| 258 | 243 | bool |
| 259 | 244 | nouveau_fence_done(struct nouveau_fence *fence) |
| 260 | 245 | { |
| @@ -29,7 +29,6 @@ void nouveau_fence_unref(struct nouveau_fence **); · 28 unmodified lines | ||
| 29 | 29 | |
| 30 | 30 | int nouveau_fence_emit(struct nouveau_fence *); |
| 31 | 31 | bool nouveau_fence_done(struct nouveau_fence *); |
| 32 | −void nouveau_fence_cancel(struct nouveau_fence *fence); | |
| 33 | 32 | int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); |
| 34 | 33 | int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr); |
| 35 | 34 | |
| @@ -11,7 +11,6 @@ · 10 unmodified lines | ||
| 11 | 11 | #include "nouveau_exec.h" |
| 12 | 12 | #include "nouveau_abi16.h" |
| 13 | 13 | #include "nouveau_sched.h" |
| 14 | −#include "nouveau_chan.h" | |
| 15 | 14 | |
| 16 | 15 | #define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 |
| 17 | 16 | |
| @@ -122,9 +121,11 @@ nouveau_job_done(struct nouveau_job *job) · 104 unmodified lines | ||
| 122 | 121 | { |
| 123 | 122 | struct nouveau_sched *sched = job->sched; |
| 124 | 123 | |
| 125 | − spin_lock(&sched->job_list.lock); | |
| 124 | + spin_lock(&sched->job.list.lock); | |
| 126 | 125 | list_del(&job->entry); |
| 127 | − spin_unlock(&sched->job_list.lock); | |
| 126 | + spin_unlock(&sched->job.list.lock); | |
| 127 | + | |
| 128 | + wake_up(&sched->job.wq); | |
| 128 | 129 | } |
| 129 | 130 | |
| 130 | 131 | void |
| @@ -305,9 +306,9 @@ nouveau_job_submit(struct nouveau_job *job) · 174 unmodified lines | ||
| 305 | 306 | } |
| 306 | 307 | |
| 307 | 308 | /* Submit was successful; add the job to the schedulers job list. */ |
| 308 | − spin_lock(&sched->job_list.lock); | |
| 309 | − list_add(&job->entry, &sched->job_list.head); | |
| 310 | − spin_unlock(&sched->job_list.lock); | |
| 309 | + spin_lock(&sched->job.list.lock); | |
| 310 | + list_add(&job->entry, &sched->job.list.head); | |
| 311 | + spin_unlock(&sched->job.list.lock); | |
| 311 | 312 | |
| 312 | 313 | drm_sched_job_arm(&job->base); |
| 313 | 314 | job->done_fence = dma_fence_get(&job->base.s_fence->finished); |
| @@ -392,23 +393,10 @@ nouveau_sched_free_job(struct drm_sched_job *sched_job) · 78 unmodified lines | ||
| 392 | 393 | nouveau_job_fini(job); |
| 393 | 394 | } |
| 394 | 395 | |
| 395 | −static void | |
| 396 | −nouveau_sched_cancel_job(struct drm_sched_job *sched_job) | |
| 397 | −{ | |
| 398 | − struct nouveau_fence *fence; | |
| 399 | − struct nouveau_job *job; | |
| 400 | − | |
| 401 | − job = to_nouveau_job(sched_job); | |
| 402 | − fence = to_nouveau_fence(job->done_fence); | |
| 403 | − | |
| 404 | − nouveau_fence_cancel(fence); | |
| 405 | −} | |
| 406 | − | |
| 407 | 396 | static const struct drm_sched_backend_ops nouveau_sched_ops = { |
| 408 | 397 | .run_job = nouveau_sched_run_job, |
| 409 | 398 | .timedout_job = nouveau_sched_timedout_job, |
| 410 | 399 | .free_job = nouveau_sched_free_job, |
| 411 | − .cancel_job = nouveau_sched_cancel_job, | |
| 412 | 400 | }; |
| 413 | 401 | |
| 414 | 402 | static int |
| @@ -458,8 +446,9 @@ nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, · 43 unmodified lines | ||
| 458 | 446 | goto fail_sched; |
| 459 | 447 | |
| 460 | 448 | mutex_init(&sched->mutex); |
| 461 | − spin_lock_init(&sched->job_list.lock); | |
| 462 | − INIT_LIST_HEAD(&sched->job_list.head); | |
| 449 | + spin_lock_init(&sched->job.list.lock); | |
| 450 | + INIT_LIST_HEAD(&sched->job.list.head); | |
| 451 | + init_waitqueue_head(&sched->job.wq); | |
| 463 | 452 | |
| 464 | 453 | return 0; |
| 465 | 454 | |
| @@ -493,12 +482,16 @@ nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm, · 27 unmodified lines | ||
| 493 | 482 | return 0; |
| 494 | 483 | } |
| 495 | 484 | |
| 485 | + | |
| 496 | 486 | static void |
| 497 | 487 | nouveau_sched_fini(struct nouveau_sched *sched) |
| 498 | 488 | { |
| 499 | 489 | struct drm_gpu_scheduler *drm_sched = &sched->base; |
| 500 | 490 | struct drm_sched_entity *entity = &sched->entity; |
| 501 | 491 | |
| 492 | + rmb(); /* for list_empty to work without lock */ | |
| 493 | + wait_event(sched->job.wq, list_empty(&sched->job.list.head)); | |
| 494 | + | |
| 502 | 495 | drm_sched_entity_fini(entity); |
| 503 | 496 | drm_sched_fini(drm_sched); |
| 504 | 497 | |
| @@ -103,9 +103,12 @@ struct nouveau_sched { · 102 unmodified lines | ||
| 103 | 103 | struct mutex mutex; |
| 104 | 104 | |
| 105 | 105 | struct { |
| 106 | − struct list_head head; | |
| 107 | − spinlock_t lock; | |
| 108 | − } job_list; | |
| 106 | + struct { | |
| 107 | + struct list_head head; | |
| 108 | + spinlock_t lock; | |
| 109 | + } list; | |
| 110 | + struct wait_queue_head wq; | |
| 111 | + } job; | |
| 109 | 112 | }; |
| 110 | 113 | |
| 111 | 114 | int nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm, |
| @@ -1019,8 +1019,8 @@ bind_validate_map_sparse(struct nouveau_job *job, u64 addr, u64 range) · 1018 unmodified lines | ||
| 1019 | 1019 | u64 end = addr + range; |
| 1020 | 1020 | |
| 1021 | 1021 | again: |
| 1022 | − spin_lock(&sched->job_list.lock); | |
| 1023 | − list_for_each_entry(__job, &sched->job_list.head, entry) { | |
| 1022 | + spin_lock(&sched->job.list.lock); | |
| 1023 | + list_for_each_entry(__job, &sched->job.list.head, entry) { | |
| 1024 | 1024 | struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(__job); |
| 1025 | 1025 | |
| 1026 | 1026 | list_for_each_op(op, &bind_job->ops) { |
| @@ -1030,7 +1030,7 @@ again: · 3 unmodified lines | ||
| 1030 | 1030 | |
| 1031 | 1031 | if (!(end <= op_addr || addr >= op_end)) { |
| 1032 | 1032 | nouveau_uvmm_bind_job_get(bind_job); |
| 1033 | − spin_unlock(&sched->job_list.lock); | |
| 1033 | + spin_unlock(&sched->job.list.lock); | |
| 1034 | 1034 | wait_for_completion(&bind_job->complete); |
| 1035 | 1035 | nouveau_uvmm_bind_job_put(bind_job); |
| 1036 | 1036 | goto again; |
| @@ -1038,7 +1038,7 @@ again: · 1 unmodified line | ||
| 1038 | 1038 | } |
| 1039 | 1039 | } |
| 1040 | 1040 | } |
| 1041 | − spin_unlock(&sched->job_list.lock); | |
| 1041 | + spin_unlock(&sched->job.list.lock); | |
| 1042 | 1042 | } |
| 1043 | 1043 | |
| 1044 | 1044 | static int |
| @@ -1094,7 +1094,7 @@ static int panthor_ioctl_group_create(struct drm_device *ddev, void *data, · 1093 unmodified lines | ||
| 1094 | 1094 | struct drm_panthor_queue_create *queue_args; |
| 1095 | 1095 | int ret; |
| 1096 | 1096 | |
| 1097 | − if (!args->queues.count) | |
| 1097 | + if (!args->queues.count || args->queues.count > MAX_CS_PER_CSG) | |
| 1098 | 1098 | return -EINVAL; |
| 1099 | 1099 | |
| 1100 | 1100 | ret = PANTHOR_UOBJ_GET_ARRAY(queue_args, &args->queues); |
| @@ -236,7 +236,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc · 235 unmodified lines | ||
| 236 | 236 | } |
| 237 | 237 | |
| 238 | 238 | xe_bo_lock(external, false); |
| 239 | − err = xe_bo_pin_external(external); | |
| 239 | + err = xe_bo_pin_external(external, false); | |
| 240 | 240 | xe_bo_unlock(external); |
| 241 | 241 | if (err) { |
| 242 | 242 | KUNIT_FAIL(test, "external bo pin err=%pe\n", |
| @@ -89,15 +89,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported, · 88 unmodified lines | ||
| 89 | 89 | return; |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | − /* | |
| 93 | − * If on different devices, the exporter is kept in system if | |
| 94 | − * possible, saving a migration step as the transfer is just | |
| 95 | − * likely as fast from system memory. | |
| 96 | − */ | |
| 97 | − if (params->mem_mask & XE_BO_FLAG_SYSTEM) | |
| 98 | − KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, XE_PL_TT)); | |
| 99 | − else | |
| 100 | − KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type)); | |
| 92 | + KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type)); | |
| 101 | 93 | |
| 102 | 94 | if (params->force_different_devices) |
| 103 | 95 | KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(imported, XE_PL_TT)); |
| @@ -186,6 +186,8 @@ static void try_add_system(struct xe_device *xe, struct xe_bo *bo, · 185 unmodified lines | ||
| 186 | 186 | |
| 187 | 187 | bo->placements[*c] = (struct ttm_place) { |
| 188 | 188 | .mem_type = XE_PL_TT, |
| 189 | + .flags = (bo_flags & XE_BO_FLAG_VRAM_MASK) ? | |
| 190 | + TTM_PL_FLAG_FALLBACK : 0, | |
| 189 | 191 | }; |
| 190 | 192 | *c += 1; |
| 191 | 193 | } |
| @@ -2269,6 +2271,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res) · 2077 unmodified lines | ||
| 2269 | 2271 | /** |
| 2270 | 2272 | * xe_bo_pin_external - pin an external BO |
| 2271 | 2273 | * @bo: buffer object to be pinned |
| 2274 | + * @in_place: Pin in current placement, don't attempt to migrate. | |
| 2272 | 2275 | * |
| 2273 | 2276 | * Pin an external (not tied to a VM, can be exported via dma-buf / prime FD) |
| 2274 | 2277 | * BO. Unique call compared to xe_bo_pin as this function has it own set of |
| @@ -2276,7 +2279,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res) · 1 unmodified line | ||
| 2276 | 2279 | * |
| 2277 | 2280 | * Returns 0 for success, negative error code otherwise. |
| 2278 | 2281 | */ |
| 2279 | −int xe_bo_pin_external(struct xe_bo *bo) | |
| 2282 | +int xe_bo_pin_external(struct xe_bo *bo, bool in_place) | |
| 2280 | 2283 | { |
| 2281 | 2284 | struct xe_device *xe = xe_bo_device(bo); |
| 2282 | 2285 | int err; |
| @@ -2285,9 +2288,11 @@ int xe_bo_pin_external(struct xe_bo *bo) · 2 unmodified lines | ||
| 2285 | 2288 | xe_assert(xe, xe_bo_is_user(bo)); |
| 2286 | 2289 | |
| 2287 | 2290 | if (!xe_bo_is_pinned(bo)) { |
| 2288 | − err = xe_bo_validate(bo, NULL, false); | |
| 2289 | − if (err) | |
| 2290 | − return err; | |
| 2291 | + if (!in_place) { | |
| 2292 | + err = xe_bo_validate(bo, NULL, false); | |
| 2293 | + if (err) | |
| 2294 | + return err; | |
| 2295 | + } | |
| 2291 | 2296 | |
| 2292 | 2297 | spin_lock(&xe->pinned.lock); |
| 2293 | 2298 | list_add_tail(&bo->pinned_link, &xe->pinned.late.external); |
| @@ -2440,6 +2445,9 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict) · 146 unmodified lines | ||
| 2440 | 2445 | }; |
| 2441 | 2446 | int ret; |
| 2442 | 2447 | |
| 2448 | + if (xe_bo_is_pinned(bo)) | |
| 2449 | + return 0; | |
| 2450 | + | |
| 2443 | 2451 | if (vm) { |
| 2444 | 2452 | lockdep_assert_held(&vm->lock); |
| 2445 | 2453 | xe_vm_assert_held(vm); |
| @@ -198,7 +198,7 @@ static inline void xe_bo_unlock_vm_held(struct xe_bo *bo) · 197 unmodified lines | ||
| 198 | 198 | } |
| 199 | 199 | } |
| 200 | 200 | |
| 201 | −int xe_bo_pin_external(struct xe_bo *bo); | |
| 201 | +int xe_bo_pin_external(struct xe_bo *bo, bool in_place); | |
| 202 | 202 | int xe_bo_pin(struct xe_bo *bo); |
| 203 | 203 | void xe_bo_unpin_external(struct xe_bo *bo); |
| 204 | 204 | void xe_bo_unpin(struct xe_bo *bo); |
| @@ -553,6 +553,12 @@ struct xe_device { · 552 unmodified lines | ||
| 553 | 553 | |
| 554 | 554 | /** @pm_notifier: Our PM notifier to perform actions in response to various PM events. */ |
| 555 | 555 | struct notifier_block pm_notifier; |
| 556 | + /** @pm_block: Completion to block validating tasks on suspend / hibernate prepare */ | |
| 557 | + struct completion pm_block; | |
| 558 | + /** @rebind_resume_list: List of wq items to kick on resume. */ | |
| 559 | + struct list_head rebind_resume_list; | |
| 560 | + /** @rebind_resume_lock: Lock to protect the rebind_resume_list */ | |
| 561 | + struct mutex rebind_resume_lock; | |
| 556 | 562 | |
| 557 | 563 | /** @pmt: Support the PMT driver callback interface */ |
| 558 | 564 | struct { |
| @@ -72,7 +72,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach) · 71 unmodified lines | ||
| 72 | 72 | return ret; |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | − ret = xe_bo_pin_external(bo); | |
| 75 | + ret = xe_bo_pin_external(bo, true); | |
| 76 | 76 | xe_assert(xe, !ret); |
| 77 | 77 | |
| 78 | 78 | return 0; |
| @@ -237,6 +237,15 @@ retry: · 236 unmodified lines | ||
| 237 | 237 | goto err_unlock_list; |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | + /* | |
| 241 | + * It's OK to block interruptible here with the vm lock held, since | |
| 242 | + * on task freezing during suspend / hibernate, the call will | |
| 243 | + * return -ERESTARTSYS and the IOCTL will be rerun. | |
| 244 | + */ | |
| 245 | + err = wait_for_completion_interruptible(&xe->pm_block); | |
| 246 | + if (err) | |
| 247 | + goto err_unlock_list; | |
| 248 | + | |
| 240 | 249 | vm_exec.vm = &vm->gpuvm; |
| 241 | 250 | vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT; |
| 242 | 251 | if (xe_vm_in_lr_mode(vm)) { |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include "xe_pcode.h" |
| 25 | 25 | #include "xe_pxp.h" |
| 26 | 26 | #include "xe_trace.h" |
| 27 | +#include "xe_vm.h" | |
| 27 | 28 | #include "xe_wa.h" |
| 28 | 29 | |
| 29 | 30 | /** |
| @@ -290,6 +291,19 @@ static u32 vram_threshold_value(struct xe_device *xe) · 260 unmodified lines | ||
| 290 | 291 | return DEFAULT_VRAM_THRESHOLD; |
| 291 | 292 | } |
| 292 | 293 | |
| 294 | +static void xe_pm_wake_rebind_workers(struct xe_device *xe) | |
| 295 | +{ | |
| 296 | + struct xe_vm *vm, *next; | |
| 297 | + | |
| 298 | + mutex_lock(&xe->rebind_resume_lock); | |
| 299 | + list_for_each_entry_safe(vm, next, &xe->rebind_resume_list, | |
| 300 | + preempt.pm_activate_link) { | |
| 301 | + list_del_init(&vm->preempt.pm_activate_link); | |
| 302 | + xe_vm_resume_rebind_worker(vm); | |
| 303 | + } | |
| 304 | + mutex_unlock(&xe->rebind_resume_lock); | |
| 305 | +} | |
| 306 | + | |
| 293 | 307 | static int xe_pm_notifier_callback(struct notifier_block *nb, |
| 294 | 308 | unsigned long action, void *data) |
| 295 | 309 | { |
| @@ -299,30 +313,30 @@ static int xe_pm_notifier_callback(struct notifier_block *nb, · 3 unmodified lines | ||
| 299 | 313 | switch (action) { |
| 300 | 314 | case PM_HIBERNATION_PREPARE: |
| 301 | 315 | case PM_SUSPEND_PREPARE: |
| 316 | + reinit_completion(&xe->pm_block); | |
| 302 | 317 | xe_pm_runtime_get(xe); |
| 303 | 318 | err = xe_bo_evict_all_user(xe); |
| 304 | − if (err) { | |
| 319 | + if (err) | |
| 305 | 320 | drm_dbg(&xe->drm, "Notifier evict user failed (%d)\n", err); |
| 306 | − xe_pm_runtime_put(xe); | |
| 307 | − break; | |
| 308 | − } | |
| 309 | 321 | |
| 310 | 322 | err = xe_bo_notifier_prepare_all_pinned(xe); |
| 311 | − if (err) { | |
| 323 | + if (err) | |
| 312 | 324 | drm_dbg(&xe->drm, "Notifier prepare pin failed (%d)\n", err); |
| 313 | − xe_pm_runtime_put(xe); | |
| 314 | − } | |
| 325 | + /* | |
| 326 | + * Keep the runtime pm reference until post hibernation / post suspend to | |
| 327 | + * avoid a runtime suspend interfering with evicted objects or backup | |
| 328 | + * allocations. | |
| 329 | + */ | |
| 315 | 330 | break; |
| 316 | 331 | case PM_POST_HIBERNATION: |
| 317 | 332 | case PM_POST_SUSPEND: |
| 333 | + complete_all(&xe->pm_block); | |
| 334 | + xe_pm_wake_rebind_workers(xe); | |
| 318 | 335 | xe_bo_notifier_unprepare_all_pinned(xe); |
| 319 | 336 | xe_pm_runtime_put(xe); |
| 320 | 337 | break; |
| 321 | 338 | } |
| 322 | 339 | |
| 323 | − if (err) | |
| 324 | − return NOTIFY_BAD; | |
| 325 | − | |
| 326 | 340 | return NOTIFY_DONE; |
| 327 | 341 | } |
| 328 | 342 | |
| @@ -344,6 +358,14 @@ int xe_pm_init(struct xe_device *xe) · 15 unmodified lines | ||
| 344 | 358 | if (err) |
| 345 | 359 | return err; |
| 346 | 360 | |
| 361 | + err = drmm_mutex_init(&xe->drm, &xe->rebind_resume_lock); | |
| 362 | + if (err) | |
| 363 | + goto err_unregister; | |
| 364 | + | |
| 365 | + init_completion(&xe->pm_block); | |
| 366 | + complete_all(&xe->pm_block); | |
| 367 | + INIT_LIST_HEAD(&xe->rebind_resume_list); | |
| 368 | + | |
| 347 | 369 | /* For now suspend/resume is only allowed with GuC */ |
| 348 | 370 | if (!xe_device_uc_enabled(xe)) |
| 349 | 371 | return 0; |
| @@ -41,6 +41,8 @@ · 40 unmodified lines | ||
| 41 | 41 | * |
| 42 | 42 | * # echo 1 > /sys/kernel/config/xe/0000:03:00.0/survivability_mode |
| 43 | 43 | * |
| 44 | + * It is the responsibility of the user to clear the mode once firmware flash is complete. | |
| 45 | + * | |
| 44 | 46 | * Refer :ref:`xe_configfs` for more details on how to use configfs |
| 45 | 47 | * |
| 46 | 48 | * Survivability mode is indicated by the below admin-only readable sysfs which provides additional |
| @@ -147,7 +149,6 @@ static void xe_survivability_mode_fini(void *arg) · 100 unmodified lines | ||
| 147 | 149 | struct pci_dev *pdev = to_pci_dev(xe->drm.dev); |
| 148 | 150 | struct device *dev = &pdev->dev; |
| 149 | 151 | |
| 150 | − xe_configfs_clear_survivability_mode(pdev); | |
| 151 | 152 | sysfs_remove_file(&dev->kobj, &dev_attr_survivability_mode.attr); |
| 152 | 153 | } |
| 153 | 154 | |
| @@ -393,6 +393,9 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec) · 392 unmodified lines | ||
| 393 | 393 | list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind, |
| 394 | 394 | &vm->rebind_list); |
| 395 | 395 | |
| 396 | + if (!try_wait_for_completion(&vm->xe->pm_block)) | |
| 397 | + return -EAGAIN; | |
| 398 | + | |
| 396 | 399 | ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false); |
| 397 | 400 | if (ret) |
| 398 | 401 | return ret; |
| @@ -479,6 +482,33 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm, · 80 unmodified lines | ||
| 479 | 482 | return xe_vm_validate_rebind(vm, exec, vm->preempt.num_exec_queues); |
| 480 | 483 | } |
| 481 | 484 | |
| 485 | +static bool vm_suspend_rebind_worker(struct xe_vm *vm) | |
| 486 | +{ | |
| 487 | + struct xe_device *xe = vm->xe; | |
| 488 | + bool ret = false; | |
| 489 | + | |
| 490 | + mutex_lock(&xe->rebind_resume_lock); | |
| 491 | + if (!try_wait_for_completion(&vm->xe->pm_block)) { | |
| 492 | + ret = true; | |
| 493 | + list_move_tail(&vm->preempt.pm_activate_link, &xe->rebind_resume_list); | |
| 494 | + } | |
| 495 | + mutex_unlock(&xe->rebind_resume_lock); | |
| 496 | + | |
| 497 | + return ret; | |
| 498 | +} | |
| 499 | + | |
| 500 | +/** | |
| 501 | + * xe_vm_resume_rebind_worker() - Resume the rebind worker. | |
| 502 | + * @vm: The vm whose preempt worker to resume. | |
| 503 | + * | |
| 504 | + * Resume a preempt worker that was previously suspended by | |
| 505 | + * vm_suspend_rebind_worker(). | |
| 506 | + */ | |
| 507 | +void xe_vm_resume_rebind_worker(struct xe_vm *vm) | |
| 508 | +{ | |
| 509 | + queue_work(vm->xe->ordered_wq, &vm->preempt.rebind_work); | |
| 510 | +} | |
| 511 | + | |
| 482 | 512 | static void preempt_rebind_work_func(struct work_struct *w) |
| 483 | 513 | { |
| 484 | 514 | struct xe_vm *vm = container_of(w, struct xe_vm, preempt.rebind_work); |
| @@ -502,6 +532,11 @@ static void preempt_rebind_work_func(struct work_struct *w) · 17 unmodified lines | ||
| 502 | 532 | } |
| 503 | 533 | |
| 504 | 534 | retry: |
| 535 | + if (!try_wait_for_completion(&vm->xe->pm_block) && vm_suspend_rebind_worker(vm)) { | |
| 536 | + up_write(&vm->lock); | |
| 537 | + return; | |
| 538 | + } | |
| 539 | + | |
| 505 | 540 | if (xe_vm_userptr_check_repin(vm)) { |
| 506 | 541 | err = xe_vm_userptr_pin(vm); |
| 507 | 542 | if (err) |
| @@ -1714,6 +1749,7 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef) · 1206 unmodified lines | ||
| 1714 | 1749 | if (flags & XE_VM_FLAG_LR_MODE) { |
| 1715 | 1750 | INIT_WORK(&vm->preempt.rebind_work, preempt_rebind_work_func); |
| 1716 | 1751 | xe_pm_runtime_get_noresume(xe); |
| 1752 | + INIT_LIST_HEAD(&vm->preempt.pm_activate_link); | |
| 1717 | 1753 | } |
| 1718 | 1754 | |
| 1719 | 1755 | if (flags & XE_VM_FLAG_FAULT_MODE) { |
| @@ -1895,8 +1931,12 @@ void xe_vm_close_and_put(struct xe_vm *vm) · 175 unmodified lines | ||
| 1895 | 1931 | xe_assert(xe, !vm->preempt.num_exec_queues); |
| 1896 | 1932 | |
| 1897 | 1933 | xe_vm_close(vm); |
| 1898 | − if (xe_vm_in_preempt_fence_mode(vm)) | |
| 1934 | + if (xe_vm_in_preempt_fence_mode(vm)) { | |
| 1935 | + mutex_lock(&xe->rebind_resume_lock); | |
| 1936 | + list_del_init(&vm->preempt.pm_activate_link); | |
| 1937 | + mutex_unlock(&xe->rebind_resume_lock); | |
| 1899 | 1938 | flush_work(&vm->preempt.rebind_work); |
| 1939 | + } | |
| 1900 | 1940 | if (xe_vm_in_fault_mode(vm)) |
| 1901 | 1941 | xe_svm_close(vm); |
| 1902 | 1942 | |
| @@ -273,6 +273,8 @@ struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo, · 272 unmodified lines | ||
| 273 | 273 | struct xe_exec_queue *q, u64 addr, |
| 274 | 274 | enum xe_cache_level cache_lvl); |
| 275 | 275 | |
| 276 | +void xe_vm_resume_rebind_worker(struct xe_vm *vm); | |
| 277 | + | |
| 276 | 278 | /** |
| 277 | 279 | * xe_vm_resv() - Return's the vm's reservation object |
| 278 | 280 | * @vm: The vm |
| @@ -293,6 +293,11 @@ struct xe_vm { · 292 unmodified lines | ||
| 293 | 293 | * BOs |
| 294 | 294 | */ |
| 295 | 295 | struct work_struct rebind_work; |
| 296 | + /** | |
| 297 | + * @preempt.pm_activate_link: Link to list of rebind workers to be | |
| 298 | + * kicked on resume. | |
| 299 | + */ | |
| 300 | + struct list_head pm_activate_link; | |
| 296 | 301 | } preempt; |
| 297 | 302 | |
| 298 | 303 | /** @um: unified memory state */ |
| @@ -30,7 +30,8 @@ · 29 unmodified lines | ||
| 30 | 30 | 16022287689 GRAPHICS_VERSION(2001) |
| 31 | 31 | GRAPHICS_VERSION(2004) |
| 32 | 32 | 13011645652 GRAPHICS_VERSION(2004) |
| 33 | − GRAPHICS_VERSION(3001) | |
| 33 | + GRAPHICS_VERSION_RANGE(3000, 3001) | |
| 34 | + GRAPHICS_VERSION(3003) | |
| 34 | 35 | 14022293748 GRAPHICS_VERSION_RANGE(2001, 2002) |
| 35 | 36 | GRAPHICS_VERSION(2004) |
| 36 | 37 | GRAPHICS_VERSION_RANGE(3000, 3001) |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | config NOVA_CORE |
| 2 | 2 | tristate "Nova Core GPU driver" |
| 3 | + depends on 64BIT | |
| 3 | 4 | depends on PCI |
| 4 | 5 | depends on RUST |
| 5 | 6 | depends on RUST_FW_LOADER_ABSTRACTIONS |
| @@ -422,6 +422,7 @@ static const struct xpad_device { · 421 unmodified lines | ||
| 422 | 422 | { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE }, |
| 423 | 423 | { 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT }, |
| 424 | 424 | { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, |
| 425 | + { 0x37d7, 0x2501, "Flydigi Apex 5", 0, XTYPE_XBOX360 }, | |
| 425 | 426 | { 0x413d, 0x2104, "Black Shark Green Ghost Gamepad", 0, XTYPE_XBOX360 }, |
| 426 | 427 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, |
| 427 | 428 | { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } |
| @@ -578,6 +579,7 @@ static const struct usb_device_id xpad_table[] = { · 150 unmodified lines | ||
| 578 | 579 | XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ |
| 579 | 580 | XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ |
| 580 | 581 | XPAD_XBOXONE_VENDOR(0x366c), /* ByoWave controllers */ |
| 582 | + XPAD_XBOX360_VENDOR(0x37d7), /* Flydigi Controllers */ | |
| 581 | 583 | XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */ |
| 582 | 584 | { } |
| 583 | 585 | }; |
| @@ -55,6 +55,7 @@ struct mtk_pmic_regs { · 54 unmodified lines | ||
| 55 | 55 | const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT]; |
| 56 | 56 | u32 pmic_rst_reg; |
| 57 | 57 | u32 rst_lprst_mask; /* Long-press reset timeout bitmask */ |
| 58 | + bool key_release_irq; | |
| 58 | 59 | }; |
| 59 | 60 | |
| 60 | 61 | static const struct mtk_pmic_regs mt6397_regs = { |
| @@ -116,6 +117,7 @@ static const struct mtk_pmic_regs mt6358_regs = { · 55 unmodified lines | ||
| 116 | 117 | MTK_PMIC_HOMEKEY_RST), |
| 117 | 118 | .pmic_rst_reg = MT6358_TOP_RST_MISC, |
| 118 | 119 | .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, |
| 120 | + .key_release_irq = true, | |
| 119 | 121 | }; |
| 120 | 122 | |
| 121 | 123 | static const struct mtk_pmic_regs mt6359_regs = { |
| @@ -129,6 +131,7 @@ static const struct mtk_pmic_regs mt6359_regs = { · 7 unmodified lines | ||
| 129 | 131 | MTK_PMIC_HOMEKEY_RST), |
| 130 | 132 | .pmic_rst_reg = MT6359_TOP_RST_MISC, |
| 131 | 133 | .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, |
| 134 | + .key_release_irq = true, | |
| 132 | 135 | }; |
| 133 | 136 | |
| 134 | 137 | struct mtk_pmic_keys_info { |
| @@ -368,7 +371,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) · 233 unmodified lines | ||
| 368 | 371 | if (keys->keys[index].irq < 0) |
| 369 | 372 | return keys->keys[index].irq; |
| 370 | 373 | |
| 371 | − if (of_device_is_compatible(node, "mediatek,mt6358-keys")) { | |
| 374 | + if (mtk_pmic_regs->key_release_irq) { | |
| 372 | 375 | keys->keys[index].irq_r = platform_get_irq_byname(pdev, |
| 373 | 376 | irqnames_r[index]); |
| 374 | 377 | |
| @@ -2427,6 +2427,9 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, · 2426 unmodified lines | ||
| 2427 | 2427 | if (error) |
| 2428 | 2428 | return error; |
| 2429 | 2429 | |
| 2430 | + if (!iqs7222->kp_type[chan_index][i]) | |
| 2431 | + continue; | |
| 2432 | + | |
| 2430 | 2433 | if (!dev_desc->event_offset) |
| 2431 | 2434 | continue; |
| 2432 | 2435 | |
| @@ -1155,6 +1155,20 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { · 1154 unmodified lines | ||
| 1155 | 1155 | .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | |
| 1156 | 1156 | SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) |
| 1157 | 1157 | }, |
| 1158 | + { | |
| 1159 | + .matches = { | |
| 1160 | + DMI_MATCH(DMI_BOARD_NAME, "XxHP4NAx"), | |
| 1161 | + }, | |
| 1162 | + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | | |
| 1163 | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) | |
| 1164 | + }, | |
| 1165 | + { | |
| 1166 | + .matches = { | |
| 1167 | + DMI_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"), | |
| 1168 | + }, | |
| 1169 | + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | | |
| 1170 | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) | |
| 1171 | + }, | |
| 1158 | 1172 | /* |
| 1159 | 1173 | * A lot of modern Clevo barebones have touchpad and/or keyboard issues |
| 1160 | 1174 | * after suspend fixable with the forcenorestore quirk. |
| @@ -133,7 +133,7 @@ struct journal_sector { · 132 unmodified lines | ||
| 133 | 133 | commit_id_t commit_id; |
| 134 | 134 | }; |
| 135 | 135 | |
| 136 | −#define MAX_TAG_SIZE (JOURNAL_SECTOR_DATA - JOURNAL_MAC_PER_SECTOR - offsetof(struct journal_entry, last_bytes[MAX_SECTORS_PER_BLOCK])) | |
| 136 | +#define MAX_TAG_SIZE 255 | |
| 137 | 137 | |
| 138 | 138 | #define METADATA_PADDING_SECTORS 8 |
| 139 | 139 | |
| @@ -3813,8 +3813,10 @@ static void raid_io_hints(struct dm_target *ti, struct queue_limits *limits) · 3812 unmodified lines | ||
| 3813 | 3813 | struct raid_set *rs = ti->private; |
| 3814 | 3814 | unsigned int chunk_size_bytes = to_bytes(rs->md.chunk_sectors); |
| 3815 | 3815 | |
| 3816 | − limits->io_min = chunk_size_bytes; | |
| 3817 | − limits->io_opt = chunk_size_bytes * mddev_data_stripes(rs); | |
| 3816 | + if (chunk_size_bytes) { | |
| 3817 | + limits->io_min = chunk_size_bytes; | |
| 3818 | + limits->io_opt = chunk_size_bytes * mddev_data_stripes(rs); | |
| 3819 | + } | |
| 3818 | 3820 | } |
| 3819 | 3821 | |
| 3820 | 3822 | static void raid_presuspend(struct dm_target *ti) |
| @@ -456,11 +456,15 @@ static void stripe_io_hints(struct dm_target *ti, · 455 unmodified lines | ||
| 456 | 456 | struct queue_limits *limits) |
| 457 | 457 | { |
| 458 | 458 | struct stripe_c *sc = ti->private; |
| 459 | − unsigned int chunk_size = sc->chunk_size << SECTOR_SHIFT; | |
| 459 | + unsigned int io_min, io_opt; | |
| 460 | 460 | |
| 461 | 461 | limits->chunk_sectors = sc->chunk_size; |
| 462 | − limits->io_min = chunk_size; | |
| 463 | − limits->io_opt = chunk_size * sc->stripes; | |
| 462 | + | |
| 463 | + if (!check_shl_overflow(sc->chunk_size, SECTOR_SHIFT, &io_min) && | |
| 464 | + !check_mul_overflow(io_min, sc->stripes, &io_opt)) { | |
| 465 | + limits->io_min = io_min; | |
| 466 | + limits->io_opt = io_opt; | |
| 467 | + } | |
| 464 | 468 | } |
| 465 | 469 | |
| 466 | 470 | static struct target_type stripe_target = { |
| @@ -185,8 +185,8 @@ config MTD_POWERNV_FLASH · 184 unmodified lines | ||
| 185 | 185 | |
| 186 | 186 | config MTD_INTEL_DG |
| 187 | 187 | tristate "Intel Discrete Graphics non-volatile memory driver" |
| 188 | − depends on AUXILIARY_BUS | |
| 189 | − depends on MTD | |
| 188 | + depends on AUXILIARY_BUS && MTD | |
| 189 | + depends on DRM_I915!=n || DRM_XE!=n || COMPILE_TEST | |
| 190 | 190 | help |
| 191 | 191 | This provides an MTD device to access Intel Discrete Graphics |
| 192 | 192 | non-volatile memory. |
| @@ -1377,14 +1377,24 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, · 1376 unmodified lines | ||
| 1377 | 1377 | if (ret) |
| 1378 | 1378 | return ret; |
| 1379 | 1379 | |
| 1380 | + /* | |
| 1381 | + * Read setup timing depends on the operation done on the NAND: | |
| 1382 | + * | |
| 1383 | + * NRD_SETUP = max(tAR, tCLR) | |
| 1384 | + */ | |
| 1385 | + timeps = max(conf->timings.sdr.tAR_min, conf->timings.sdr.tCLR_min); | |
| 1386 | + ncycles = DIV_ROUND_UP(timeps, mckperiodps); | |
| 1387 | + totalcycles += ncycles; | |
| 1388 | + ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NRD_SHIFT, ncycles); | |
| 1389 | + if (ret) | |
| 1390 | + return ret; | |
| 1391 | + | |
| 1380 | 1392 | /* |
| 1381 | 1393 | * The read cycle timing is directly matching tRC, but is also |
| 1382 | 1394 | * dependent on the setup and hold timings we calculated earlier, |
| 1383 | 1395 | * which gives: |
| 1384 | 1396 | * |
| 1385 | − * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD) | |
| 1386 | − * | |
| 1387 | − * NRD_SETUP is always 0. | |
| 1397 | + * NRD_CYCLE = max(tRC, NRD_SETUP + NRD_PULSE + NRD_HOLD) | |
| 1388 | 1398 | */ |
| 1389 | 1399 | ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps); |
| 1390 | 1400 | ncycles = max(totalcycles, ncycles); |
| @@ -935,10 +935,10 @@ static void ma35_chips_cleanup(struct ma35_nand_info *nand) · 934 unmodified lines | ||
| 935 | 935 | |
| 936 | 936 | static int ma35_nand_chips_init(struct device *dev, struct ma35_nand_info *nand) |
| 937 | 937 | { |
| 938 | − struct device_node *np = dev->of_node, *nand_np; | |
| 938 | + struct device_node *np = dev->of_node; | |
| 939 | 939 | int ret; |
| 940 | 940 | |
| 941 | − for_each_child_of_node(np, nand_np) { | |
| 941 | + for_each_child_of_node_scoped(np, nand_np) { | |
| 942 | 942 | ret = ma35_nand_chip_init(dev, nand, nand_np); |
| 943 | 943 | if (ret) { |
| 944 | 944 | ma35_chips_cleanup(nand); |
| @@ -272,6 +272,7 @@ struct stm32_fmc2_nfc { · 271 unmodified lines | ||
| 272 | 272 | struct sg_table dma_data_sg; |
| 273 | 273 | struct sg_table dma_ecc_sg; |
| 274 | 274 | u8 *ecc_buf; |
| 275 | + dma_addr_t dma_ecc_addr; | |
| 275 | 276 | int dma_ecc_len; |
| 276 | 277 | u32 tx_dma_max_burst; |
| 277 | 278 | u32 rx_dma_max_burst; |
| @@ -902,17 +903,10 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, · 624 unmodified lines | ||
| 902 | 903 | |
| 903 | 904 | if (!write_data && !raw) { |
| 904 | 905 | /* Configure DMA ECC status */ |
| 905 | − p = nfc->ecc_buf; | |
| 906 | 906 | for_each_sg(nfc->dma_ecc_sg.sgl, sg, eccsteps, s) { |
| 907 | − sg_set_buf(sg, p, nfc->dma_ecc_len); | |
| 908 | − p += nfc->dma_ecc_len; | |
| 909 | − } | |
| 910 | − | |
| 911 | − ret = dma_map_sg(nfc->dev, nfc->dma_ecc_sg.sgl, | |
| 912 | − eccsteps, dma_data_dir); | |
| 913 | − if (!ret) { | |
| 914 | − ret = -EIO; | |
| 915 | − goto err_unmap_data; | |
| 907 | + sg_dma_address(sg) = nfc->dma_ecc_addr + | |
| 908 | + s * nfc->dma_ecc_len; | |
| 909 | + sg_dma_len(sg) = nfc->dma_ecc_len; | |
| 916 | 910 | } |
| 917 | 911 | |
| 918 | 912 | desc_ecc = dmaengine_prep_slave_sg(nfc->dma_ecc_ch, |
| @@ -921,7 +915,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, · 2 unmodified lines | ||
| 921 | 915 | DMA_PREP_INTERRUPT); |
| 922 | 916 | if (!desc_ecc) { |
| 923 | 917 | ret = -ENOMEM; |
| 924 | − goto err_unmap_ecc; | |
| 918 | + goto err_unmap_data; | |
| 925 | 919 | } |
| 926 | 920 | |
| 927 | 921 | reinit_completion(&nfc->dma_ecc_complete); |
| @@ -929,7 +923,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, · 1 unmodified line | ||
| 929 | 923 | desc_ecc->callback_param = &nfc->dma_ecc_complete; |
| 930 | 924 | ret = dma_submit_error(dmaengine_submit(desc_ecc)); |
| 931 | 925 | if (ret) |
| 932 | − goto err_unmap_ecc; | |
| 926 | + goto err_unmap_data; | |
| 933 | 927 | |
| 934 | 928 | dma_async_issue_pending(nfc->dma_ecc_ch); |
| 935 | 929 | } |
| @@ -949,7 +943,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, · 13 unmodified lines | ||
| 949 | 943 | if (!write_data && !raw) |
| 950 | 944 | dmaengine_terminate_all(nfc->dma_ecc_ch); |
| 951 | 945 | ret = -ETIMEDOUT; |
| 952 | − goto err_unmap_ecc; | |
| 946 | + goto err_unmap_data; | |
| 953 | 947 | } |
| 954 | 948 | |
| 955 | 949 | /* Wait DMA data transfer completion */ |
| @@ -969,11 +963,6 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, · 13 unmodified lines | ||
| 969 | 963 | } |
| 970 | 964 | } |
| 971 | 965 | |
| 972 | −err_unmap_ecc: | |
| 973 | − if (!write_data && !raw) | |
| 974 | − dma_unmap_sg(nfc->dev, nfc->dma_ecc_sg.sgl, | |
| 975 | − eccsteps, dma_data_dir); | |
| 976 | − | |
| 977 | 966 | err_unmap_data: |
| 978 | 967 | dma_unmap_sg(nfc->dev, nfc->dma_data_sg.sgl, eccsteps, dma_data_dir); |
| 979 | 968 | |
| @@ -996,9 +985,21 @@ static int stm32_fmc2_nfc_seq_write(struct nand_chip *chip, const u8 *buf, · 16 unmodified lines | ||
| 996 | 985 | |
| 997 | 986 | /* Write oob */ |
| 998 | 987 | if (oob_required) { |
| 999 | − ret = nand_change_write_column_op(chip, mtd->writesize, | |
| 1000 | − chip->oob_poi, mtd->oobsize, | |
| 1001 | − false); | |
| 988 | + unsigned int offset_in_page = mtd->writesize; | |
| 989 | + const void *buf = chip->oob_poi; | |
| 990 | + unsigned int len = mtd->oobsize; | |
| 991 | + | |
| 992 | + if (!raw) { | |
| 993 | + struct mtd_oob_region oob_free; | |
| 994 | + | |
| 995 | + mtd_ooblayout_free(mtd, 0, &oob_free); | |
| 996 | + offset_in_page += oob_free.offset; | |
| 997 | + buf += oob_free.offset; | |
| 998 | + len = oob_free.length; | |
| 999 | + } | |
| 1000 | + | |
| 1001 | + ret = nand_change_write_column_op(chip, offset_in_page, | |
| 1002 | + buf, len, false); | |
| 1002 | 1003 | if (ret) |
| 1003 | 1004 | return ret; |
| 1004 | 1005 | } |
| @@ -1610,7 +1611,8 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc) · 605 unmodified lines | ||
| 1610 | 1611 | return ret; |
| 1611 | 1612 | |
| 1612 | 1613 | /* Allocate a buffer to store ECC status registers */ |
| 1613 | − nfc->ecc_buf = devm_kzalloc(nfc->dev, FMC2_MAX_ECC_BUF_LEN, GFP_KERNEL); | |
| 1614 | + nfc->ecc_buf = dmam_alloc_coherent(nfc->dev, FMC2_MAX_ECC_BUF_LEN, | |
| 1615 | + &nfc->dma_ecc_addr, GFP_KERNEL); | |
| 1614 | 1616 | if (!nfc->ecc_buf) |
| 1615 | 1617 | return -ENOMEM; |
| 1616 | 1618 | |
| @@ -176,6 +176,36 @@ static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { · 175 unmodified lines | ||
| 176 | 176 | .free = w25n02kv_ooblayout_free, |
| 177 | 177 | }; |
| 178 | 178 | |
| 179 | +static int w25n01jw_ooblayout_ecc(struct mtd_info *mtd, int section, | |
| 180 | + struct mtd_oob_region *region) | |
| 181 | +{ | |
| 182 | + if (section > 3) | |
| 183 | + return -ERANGE; | |
| 184 | + | |
| 185 | + region->offset = (16 * section) + 12; | |
| 186 | + region->length = 4; | |
| 187 | + | |
| 188 | + return 0; | |
| 189 | +} | |
| 190 | + | |
| 191 | +static int w25n01jw_ooblayout_free(struct mtd_info *mtd, int section, | |
| 192 | + struct mtd_oob_region *region) | |
| 193 | +{ | |
| 194 | + if (section > 3) | |
| 195 | + return -ERANGE; | |
| 196 | + | |
| 197 | + region->offset = (16 * section); | |
| 198 | + region->length = 12; | |
| 199 | + | |
| 200 | + /* Extract BBM */ | |
| 201 | + if (!section) { | |
| 202 | + region->offset += 2; | |
| 203 | + region->length -= 2; | |
| 204 | + } | |
| 205 | + | |
| 206 | + return 0; | |
| 207 | +} | |
| 208 | + | |
| 179 | 209 | static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section, |
| 180 | 210 | struct mtd_oob_region *region) |
| 181 | 211 | { |
| @@ -206,6 +236,11 @@ static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section, · 24 unmodified lines | ||
| 206 | 236 | return 0; |
| 207 | 237 | } |
| 208 | 238 | |
| 239 | +static const struct mtd_ooblayout_ops w25n01jw_ooblayout = { | |
| 240 | + .ecc = w25n01jw_ooblayout_ecc, | |
| 241 | + .free = w25n01jw_ooblayout_free, | |
| 242 | +}; | |
| 243 | + | |
| 209 | 244 | static const struct mtd_ooblayout_ops w35n01jw_ooblayout = { |
| 210 | 245 | .ecc = w35n01jw_ooblayout_ecc, |
| 211 | 246 | .free = w35n01jw_ooblayout_free, |
| @@ -394,7 +429,7 @@ static const struct spinand_info winbond_spinand_table[] = { · 182 unmodified lines | ||
| 394 | 429 | &write_cache_variants, |
| 395 | 430 | &update_cache_variants), |
| 396 | 431 | 0, |
| 397 | − SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), | |
| 432 | + SPINAND_ECCINFO(&w25n01jw_ooblayout, NULL), | |
| 398 | 433 | SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), |
| 399 | 434 | SPINAND_INFO("W25N01KV", /* 3.3V */ |
| 400 | 435 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), |
| @@ -2053,6 +2053,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, · 2052 unmodified lines | ||
| 2053 | 2053 | memcpy(ss.__data, bond_dev->dev_addr, bond_dev->addr_len); |
| 2054 | 2054 | } else if (bond->params.fail_over_mac == BOND_FOM_FOLLOW && |
| 2055 | 2055 | BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP && |
| 2056 | + bond_has_slaves(bond) && | |
| 2056 | 2057 | memcmp(slave_dev->dev_addr, bond_dev->dev_addr, bond_dev->addr_len) == 0) { |
| 2057 | 2058 | /* Set slave to random address to avoid duplicate mac |
| 2058 | 2059 | * address in later fail over. |
| @@ -3257,7 +3258,6 @@ static void bond_ns_send_all(struct bonding *bond, struct slave *slave) · 1198 unmodified lines | ||
| 3257 | 3258 | /* Find out through which dev should the packet go */ |
| 3258 | 3259 | memset(&fl6, 0, sizeof(struct flowi6)); |
| 3259 | 3260 | fl6.daddr = targets[i]; |
| 3260 | − fl6.flowi6_oif = bond->dev->ifindex; | |
| 3261 | 3261 | |
| 3262 | 3262 | dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6); |
| 3263 | 3263 | if (dst->error) { |
| @@ -4230,8 +4230,7 @@ static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev) · 4229 unmodified lines | ||
| 4230 | 4230 | |
| 4231 | 4231 | cnic_bnx2x_delete_wait(dev, 0); |
| 4232 | 4232 | |
| 4233 | − cancel_delayed_work(&cp->delete_task); | |
| 4234 | − flush_workqueue(cnic_wq); | |
| 4233 | + cancel_delayed_work_sync(&cp->delete_task); | |
| 4235 | 4234 | |
| 4236 | 4235 | if (atomic_read(&cp->iscsi_conn) != 0) |
| 4237 | 4236 | netdev_warn(dev->netdev, "%d iSCSI connections not destroyed\n", |
| @@ -126,7 +126,7 @@ int octeon_init_instr_queue(struct octeon_device *oct, · 125 unmodified lines | ||
| 126 | 126 | oct->io_qmask.iq |= BIT_ULL(iq_no); |
| 127 | 127 | |
| 128 | 128 | /* Set the 32B/64B mode for each input queue */ |
| 129 | − oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no); | |
| 129 | + oct->io_qmask.iq64B |= ((u64)(conf->instr_type == 64) << iq_no); | |
| 130 | 130 | iq->iqcmd_64B = (conf->instr_type == 64); |
| 131 | 131 | |
| 132 | 132 | oct->fn_list.setup_iq_regs(oct, iq_no); |
| @@ -2736,7 +2736,7 @@ static int dpaa2_switch_setup_dpbp(struct ethsw_core *ethsw) · 2735 unmodified lines | ||
| 2736 | 2736 | dev_err(dev, "dpsw_ctrl_if_set_pools() failed\n"); |
| 2737 | 2737 | goto err_get_attr; |
| 2738 | 2738 | } |
| 2739 | − ethsw->bpid = dpbp_attrs.id; | |
| 2739 | + ethsw->bpid = dpbp_attrs.bpid; | |
| 2740 | 2740 | |
| 2741 | 2741 | return 0; |
| 2742 | 2742 | |
| @@ -948,9 +948,6 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi, · 947 unmodified lines | ||
| 948 | 948 | if (!eop_desc) |
| 949 | 949 | break; |
| 950 | 950 | |
| 951 | − /* prevent any other reads prior to eop_desc */ | |
| 952 | − smp_rmb(); | |
| 953 | − | |
| 954 | 951 | i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); |
| 955 | 952 | /* we have caught up to head, no work left to do */ |
| 956 | 953 | if (tx_head == tx_desc) |
| @@ -894,10 +894,6 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, · 893 unmodified lines | ||
| 894 | 894 | __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page, |
| 895 | 895 | rx_buf->page_offset, size); |
| 896 | 896 | sinfo->xdp_frags_size += size; |
| 897 | − /* remember frag count before XDP prog execution; bpf_xdp_adjust_tail() | |
| 898 | − * can pop off frags but driver has to handle it on its own | |
| 899 | − */ | |
| 900 | − rx_ring->nr_frags = sinfo->nr_frags; | |
| 901 | 897 | |
| 902 | 898 | if (page_is_pfmemalloc(rx_buf->page)) |
| 903 | 899 | xdp_buff_set_frag_pfmemalloc(xdp); |
| @@ -968,20 +964,20 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, · 64 unmodified lines | ||
| 968 | 964 | /** |
| 969 | 965 | * ice_get_pgcnts - grab page_count() for gathered fragments |
| 970 | 966 | * @rx_ring: Rx descriptor ring to store the page counts on |
| 967 | + * @ntc: the next to clean element (not included in this frame!) | |
| 971 | 968 | * |
| 972 | 969 | * This function is intended to be called right before running XDP |
| 973 | 970 | * program so that the page recycling mechanism will be able to take |
| 974 | 971 | * a correct decision regarding underlying pages; this is done in such |
| 975 | 972 | * way as XDP program can change the refcount of page |
| 976 | 973 | */ |
| 977 | −static void ice_get_pgcnts(struct ice_rx_ring *rx_ring) | |
| 974 | +static void ice_get_pgcnts(struct ice_rx_ring *rx_ring, unsigned int ntc) | |
| 978 | 975 | { |
| 979 | − u32 nr_frags = rx_ring->nr_frags + 1; | |
| 980 | 976 | u32 idx = rx_ring->first_desc; |
| 981 | 977 | struct ice_rx_buf *rx_buf; |
| 982 | 978 | u32 cnt = rx_ring->count; |
| 983 | 979 | |
| 984 | − for (int i = 0; i < nr_frags; i++) { | |
| 980 | + while (idx != ntc) { | |
| 985 | 981 | rx_buf = &rx_ring->rx_buf[idx]; |
| 986 | 982 | rx_buf->pgcnt = page_count(rx_buf->page); |
| 987 | 983 | |
| @@ -1153,62 +1149,51 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf) · 165 unmodified lines | ||
| 1153 | 1149 | } |
| 1154 | 1150 | |
| 1155 | 1151 | /** |
| 1156 | − * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all frame frags | |
| 1152 | + * ice_put_rx_mbuf - ice_put_rx_buf() caller, for all buffers in frame | |
| 1157 | 1153 | * @rx_ring: Rx ring with all the auxiliary data |
| 1158 | 1154 | * @xdp: XDP buffer carrying linear + frags part |
| 1159 | − * @xdp_xmit: XDP_TX/XDP_REDIRECT verdict storage | |
| 1160 | − * @ntc: a current next_to_clean value to be stored at rx_ring | |
| 1155 | + * @ntc: the next to clean element (not included in this frame!) | |
| 1161 | 1156 | * @verdict: return code from XDP program execution |
| 1162 | 1157 | * |
| 1163 | − * Walk through gathered fragments and satisfy internal page | |
| 1164 | − * recycle mechanism; we take here an action related to verdict | |
| 1165 | − * returned by XDP program; | |
| 1158 | + * Called after XDP program is completed, or on error with verdict set to | |
| 1159 | + * ICE_XDP_CONSUMED. | |
| 1160 | + * | |
| 1161 | + * Walk through buffers from first_desc to the end of the frame, releasing | |
| 1162 | + * buffers and satisfying internal page recycle mechanism. The action depends | |
| 1163 | + * on verdict from XDP program. | |
| 1166 | 1164 | */ |
| 1167 | 1165 | static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, |
| 1168 | − u32 *xdp_xmit, u32 ntc, u32 verdict) | |
| 1166 | + u32 ntc, u32 verdict) | |
| 1169 | 1167 | { |
| 1170 | − u32 nr_frags = rx_ring->nr_frags + 1; | |
| 1171 | 1168 | u32 idx = rx_ring->first_desc; |
| 1172 | 1169 | u32 cnt = rx_ring->count; |
| 1173 | − u32 post_xdp_frags = 1; | |
| 1174 | 1170 | struct ice_rx_buf *buf; |
| 1175 | − int i; | |
| 1171 | + u32 xdp_frags = 0; | |
| 1172 | + int i = 0; | |
| 1176 | 1173 | |
| 1177 | 1174 | if (unlikely(xdp_buff_has_frags(xdp))) |
| 1178 | − post_xdp_frags += xdp_get_shared_info_from_buff(xdp)->nr_frags; | |
| 1175 | + xdp_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags; | |
| 1179 | 1176 | |
| 1180 | − for (i = 0; i < post_xdp_frags; i++) { | |
| 1177 | + while (idx != ntc) { | |
| 1181 | 1178 | buf = &rx_ring->rx_buf[idx]; |
| 1179 | + if (++idx == cnt) | |
| 1180 | + idx = 0; | |
| 1182 | 1181 | |
| 1183 | − if (verdict & (ICE_XDP_TX | ICE_XDP_REDIR)) { | |
| 1182 | + /* An XDP program could release fragments from the end of the | |
| 1183 | + * buffer. For these, we need to keep the pagecnt_bias as-is. | |
| 1184 | + * To do this, only adjust pagecnt_bias for fragments up to | |
| 1185 | + * the total remaining after the XDP program has run. | |
| 1186 | + */ | |
| 1187 | + if (verdict != ICE_XDP_CONSUMED) | |
| 1184 | 1188 | ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); |
| 1185 | − *xdp_xmit |= verdict; | |
| 1186 | − } else if (verdict & ICE_XDP_CONSUMED) { | |
| 1189 | + else if (i++ <= xdp_frags) | |
| 1187 | 1190 | buf->pagecnt_bias++; |
| 1188 | − } else if (verdict == ICE_XDP_PASS) { | |
| 1189 | − ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); | |
| 1190 | − } | |
| 1191 | 1191 | |
| 1192 | 1192 | ice_put_rx_buf(rx_ring, buf); |
| 1193 | − | |
| 1194 | − if (++idx == cnt) | |
| 1195 | − idx = 0; | |
| 1196 | − } | |
| 1197 | − /* handle buffers that represented frags released by XDP prog; | |
| 1198 | − * for these we keep pagecnt_bias as-is; refcount from struct page | |
| 1199 | − * has been decremented within XDP prog and we do not have to increase | |
| 1200 | − * the biased refcnt | |
| 1201 | − */ | |
| 1202 | − for (; i < nr_frags; i++) { | |
| 1203 | − buf = &rx_ring->rx_buf[idx]; | |
| 1204 | − ice_put_rx_buf(rx_ring, buf); | |
| 1205 | − if (++idx == cnt) | |
| 1206 | − idx = 0; | |
| 1207 | 1193 | } |
| 1208 | 1194 | |
| 1209 | 1195 | xdp->data = NULL; |
| 1210 | 1196 | rx_ring->first_desc = ntc; |
| 1211 | − rx_ring->nr_frags = 0; | |
| 1212 | 1197 | } |
| 1213 | 1198 | |
| 1214 | 1199 | /** |
| @@ -1316,6 +1301,10 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) · 101 unmodified lines | ||
| 1316 | 1301 | /* retrieve a buffer from the ring */ |
| 1317 | 1302 | rx_buf = ice_get_rx_buf(rx_ring, size, ntc); |
| 1318 | 1303 | |
| 1304 | + /* Increment ntc before calls to ice_put_rx_mbuf() */ | |
| 1305 | + if (++ntc == cnt) | |
| 1306 | + ntc = 0; | |
| 1307 | + | |
| 1319 | 1308 | if (!xdp->data) { |
| 1320 | 1309 | void *hard_start; |
| 1321 | 1310 | |
| @@ -1324,24 +1313,23 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) · 2 unmodified lines | ||
| 1324 | 1313 | xdp_prepare_buff(xdp, hard_start, offset, size, !!offset); |
| 1325 | 1314 | xdp_buff_clear_frags_flag(xdp); |
| 1326 | 1315 | } else if (ice_add_xdp_frag(rx_ring, xdp, rx_buf, size)) { |
| 1327 | − ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc, ICE_XDP_CONSUMED); | |
| 1316 | + ice_put_rx_mbuf(rx_ring, xdp, ntc, ICE_XDP_CONSUMED); | |
| 1328 | 1317 | break; |
| 1329 | 1318 | } |
| 1330 | − if (++ntc == cnt) | |
| 1331 | − ntc = 0; | |
| 1332 | 1319 | |
| 1333 | 1320 | /* skip if it is NOP desc */ |
| 1334 | 1321 | if (ice_is_non_eop(rx_ring, rx_desc)) |
| 1335 | 1322 | continue; |
| 1336 | 1323 | |
| 1337 | − ice_get_pgcnts(rx_ring); | |
| 1324 | + ice_get_pgcnts(rx_ring, ntc); | |
| 1338 | 1325 | xdp_verdict = ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_desc); |
| 1339 | 1326 | if (xdp_verdict == ICE_XDP_PASS) |
| 1340 | 1327 | goto construct_skb; |
| 1341 | 1328 | total_rx_bytes += xdp_get_buff_len(xdp); |
| 1342 | 1329 | total_rx_pkts++; |
| 1343 | 1330 | |
| 1344 | − ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); | |
| 1331 | + ice_put_rx_mbuf(rx_ring, xdp, ntc, xdp_verdict); | |
| 1332 | + xdp_xmit |= xdp_verdict & (ICE_XDP_TX | ICE_XDP_REDIR); | |
| 1345 | 1333 | |
| 1346 | 1334 | continue; |
| 1347 | 1335 | construct_skb: |
| @@ -1354,7 +1342,7 @@ construct_skb: · 6 unmodified lines | ||
| 1354 | 1342 | rx_ring->ring_stats->rx_stats.alloc_buf_failed++; |
| 1355 | 1343 | xdp_verdict = ICE_XDP_CONSUMED; |
| 1356 | 1344 | } |
| 1357 | − ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); | |
| 1345 | + ice_put_rx_mbuf(rx_ring, xdp, ntc, xdp_verdict); | |
| 1358 | 1346 | |
| 1359 | 1347 | if (!skb) |
| 1360 | 1348 | break; |
| @@ -358,7 +358,6 @@ struct ice_rx_ring { · 357 unmodified lines | ||
| 358 | 358 | struct ice_tx_ring *xdp_ring; |
| 359 | 359 | struct ice_rx_ring *next; /* pointer to next ring in q_vector */ |
| 360 | 360 | struct xsk_buff_pool *xsk_pool; |
| 361 | − u32 nr_frags; | |
| 362 | 361 | u16 max_frame; |
| 363 | 362 | u16 rx_buf_len; |
| 364 | 363 | dma_addr_t dma; /* physical address of ring */ |
| @@ -345,6 +345,7 @@ struct igc_adapter { · 344 unmodified lines | ||
| 345 | 345 | /* LEDs */ |
| 346 | 346 | struct mutex led_mutex; |
| 347 | 347 | struct igc_led_classdev *leds; |
| 348 | + bool leds_available; | |
| 348 | 349 | }; |
| 349 | 350 | |
| 350 | 351 | void igc_up(struct igc_adapter *adapter); |
| @@ -7335,8 +7335,14 @@ static int igc_probe(struct pci_dev *pdev, · 7334 unmodified lines | ||
| 7335 | 7335 | |
| 7336 | 7336 | if (IS_ENABLED(CONFIG_IGC_LEDS)) { |
| 7337 | 7337 | err = igc_led_setup(adapter); |
| 7338 | − if (err) | |
| 7339 | − goto err_register; | |
| 7338 | + if (err) { | |
| 7339 | + netdev_warn_once(netdev, | |
| 7340 | + "LED init failed (%d); continuing without LED support\n", | |
| 7341 | + err); | |
| 7342 | + adapter->leds_available = false; | |
| 7343 | + } else { | |
| 7344 | + adapter->leds_available = true; | |
| 7345 | + } | |
| 7340 | 7346 | } |
| 7341 | 7347 | |
| 7342 | 7348 | return 0; |
| @@ -7392,7 +7398,7 @@ static void igc_remove(struct pci_dev *pdev) · 49 unmodified lines | ||
| 7392 | 7398 | cancel_work_sync(&adapter->watchdog_task); |
| 7393 | 7399 | hrtimer_cancel(&adapter->hrtimer); |
| 7394 | 7400 | |
| 7395 | − if (IS_ENABLED(CONFIG_IGC_LEDS)) | |
| 7401 | + if (IS_ENABLED(CONFIG_IGC_LEDS) && adapter->leds_available) | |
| 7396 | 7402 | igc_led_free(adapter); |
| 7397 | 7403 | |
| 7398 | 7404 | /* Release control of h/w to f/w. If f/w is AMT enabled, this |
| @@ -6978,6 +6978,13 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter, · 6977 unmodified lines | ||
| 6978 | 6978 | break; |
| 6979 | 6979 | } |
| 6980 | 6980 | |
| 6981 | + /* Make sure the SWFW semaphore is in a valid state */ | |
| 6982 | + if (hw->mac.ops.init_swfw_sync) | |
| 6983 | + hw->mac.ops.init_swfw_sync(hw); | |
| 6984 | + | |
| 6985 | + if (hw->mac.type == ixgbe_mac_e610) | |
| 6986 | + mutex_init(&hw->aci.lock); | |
| 6987 | + | |
| 6981 | 6988 | #ifdef IXGBE_FCOE |
| 6982 | 6989 | /* FCoE support exists, always init the FCoE lock */ |
| 6983 | 6990 | spin_lock_init(&adapter->fcoe.lock); |
| @@ -11648,10 +11655,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 4664 unmodified lines | ||
| 11648 | 11655 | if (err) |
| 11649 | 11656 | goto err_sw_init; |
| 11650 | 11657 | |
| 11651 | − /* Make sure the SWFW semaphore is in a valid state */ | |
| 11652 | − if (hw->mac.ops.init_swfw_sync) | |
| 11653 | − hw->mac.ops.init_swfw_sync(hw); | |
| 11654 | − | |
| 11655 | 11658 | if (ixgbe_check_fw_error(adapter)) |
| 11656 | 11659 | return ixgbe_recovery_probe(adapter); |
| 11657 | 11660 | |
| @@ -11855,8 +11858,6 @@ skip_sriov: · 197 unmodified lines | ||
| 11855 | 11858 | ether_addr_copy(hw->mac.addr, hw->mac.perm_addr); |
| 11856 | 11859 | ixgbe_mac_set_default_filter(adapter); |
| 11857 | 11860 | |
| 11858 | − if (hw->mac.type == ixgbe_mac_e610) | |
| 11859 | − mutex_init(&hw->aci.lock); | |
| 11860 | 11861 | timer_setup(&adapter->service_timer, ixgbe_service_timer, 0); |
| 11861 | 11862 | |
| 11862 | 11863 | if (ixgbe_removed(hw->hw_addr)) { |
| @@ -12016,9 +12017,9 @@ err_register: · 153 unmodified lines | ||
| 12016 | 12017 | devl_unlock(adapter->devlink); |
| 12017 | 12018 | ixgbe_release_hw_control(adapter); |
| 12018 | 12019 | ixgbe_clear_interrupt_scheme(adapter); |
| 12020 | +err_sw_init: | |
| 12019 | 12021 | if (hw->mac.type == ixgbe_mac_e610) |
| 12020 | 12022 | mutex_destroy(&adapter->hw.aci.lock); |
| 12021 | −err_sw_init: | |
| 12022 | 12023 | ixgbe_disable_sriov(adapter); |
| 12023 | 12024 | adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; |
| 12024 | 12025 | iounmap(adapter->io_addr); |
| @@ -12070,10 +12071,8 @@ static void ixgbe_remove(struct pci_dev *pdev) · 45 unmodified lines | ||
| 12070 | 12071 | set_bit(__IXGBE_REMOVING, &adapter->state); |
| 12071 | 12072 | cancel_work_sync(&adapter->service_task); |
| 12072 | 12073 | |
| 12073 | − if (adapter->hw.mac.type == ixgbe_mac_e610) { | |
| 12074 | + if (adapter->hw.mac.type == ixgbe_mac_e610) | |
| 12074 | 12075 | ixgbe_disable_link_status_events(adapter); |
| 12075 | − mutex_destroy(&adapter->hw.aci.lock); | |
| 12076 | − } | |
| 12077 | 12076 | |
| 12078 | 12077 | if (adapter->mii_bus) |
| 12079 | 12078 | mdiobus_unregister(adapter->mii_bus); |
| @@ -12133,6 +12132,9 @@ static void ixgbe_remove(struct pci_dev *pdev) · 53 unmodified lines | ||
| 12133 | 12132 | disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); |
| 12134 | 12133 | free_netdev(netdev); |
| 12135 | 12134 | |
| 12135 | + if (adapter->hw.mac.type == ixgbe_mac_e610) | |
| 12136 | + mutex_destroy(&adapter->hw.aci.lock); | |
| 12137 | + | |
| 12136 | 12138 | if (disable_dev) |
| 12137 | 12139 | pci_disable_device(pdev); |
| 12138 | 12140 | } |
| @@ -1124,11 +1124,24 @@ static int octep_set_features(struct net_device *dev, netdev_features_t features · 1123 unmodified lines | ||
| 1124 | 1124 | return err; |
| 1125 | 1125 | } |
| 1126 | 1126 | |
| 1127 | +static bool octep_is_vf_valid(struct octep_device *oct, int vf) | |
| 1128 | +{ | |
| 1129 | + if (vf >= CFG_GET_ACTIVE_VFS(oct->conf)) { | |
| 1130 | + netdev_err(oct->netdev, "Invalid VF ID %d\n", vf); | |
| 1131 | + return false; | |
| 1132 | + } | |
| 1133 | + | |
| 1134 | + return true; | |
| 1135 | +} | |
| 1136 | + | |
| 1127 | 1137 | static int octep_get_vf_config(struct net_device *dev, int vf, |
| 1128 | 1138 | struct ifla_vf_info *ivi) |
| 1129 | 1139 | { |
| 1130 | 1140 | struct octep_device *oct = netdev_priv(dev); |
| 1131 | 1141 | |
| 1142 | + if (!octep_is_vf_valid(oct, vf)) | |
| 1143 | + return -EINVAL; | |
| 1144 | + | |
| 1132 | 1145 | ivi->vf = vf; |
| 1133 | 1146 | ether_addr_copy(ivi->mac, oct->vf_info[vf].mac_addr); |
| 1134 | 1147 | ivi->spoofchk = true; |
| @@ -1143,6 +1156,9 @@ static int octep_set_vf_mac(struct net_device *dev, int vf, u8 *mac) · 8 unmodified lines | ||
| 1143 | 1156 | struct octep_device *oct = netdev_priv(dev); |
| 1144 | 1157 | int err; |
| 1145 | 1158 | |
| 1159 | + if (!octep_is_vf_valid(oct, vf)) | |
| 1160 | + return -EINVAL; | |
| 1161 | + | |
| 1146 | 1162 | if (!is_valid_ether_addr(mac)) { |
| 1147 | 1163 | dev_err(&oct->pdev->dev, "Invalid MAC Address %pM\n", mac); |
| 1148 | 1164 | return -EADDRNOTAVAIL; |
| @@ -196,6 +196,7 @@ static void octep_pfvf_get_mac_addr(struct octep_device *oct, u32 vf_id, · 195 unmodified lines | ||
| 196 | 196 | vf_id); |
| 197 | 197 | return; |
| 198 | 198 | } |
| 199 | + ether_addr_copy(oct->vf_info[vf_id].mac_addr, rsp->s_set_mac.mac_addr); | |
| 199 | 200 | rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK; |
| 200 | 201 | } |
| 201 | 202 | |
| @@ -205,6 +206,8 @@ static void octep_pfvf_dev_remove(struct octep_device *oct, u32 vf_id, · 3 unmodified lines | ||
| 205 | 206 | { |
| 206 | 207 | int err; |
| 207 | 208 | |
| 209 | + /* Reset VF-specific information maintained by the PF */ | |
| 210 | + memset(&oct->vf_info[vf_id], 0, sizeof(struct octep_pfvf_info)); | |
| 208 | 211 | err = octep_ctrl_net_dev_remove(oct, vf_id); |
| 209 | 212 | if (err) { |
| 210 | 213 | rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK; |
| @@ -491,7 +491,7 @@ void otx2_ptp_destroy(struct otx2_nic *pfvf) · 490 unmodified lines | ||
| 491 | 491 | if (!ptp) |
| 492 | 492 | return; |
| 493 | 493 | |
| 494 | − cancel_delayed_work(&pfvf->ptp->synctstamp_work); | |
| 494 | + cancel_delayed_work_sync(&pfvf->ptp->synctstamp_work); | |
| 495 | 495 | |
| 496 | 496 | ptp_clock_unregister(ptp->ptp_clock); |
| 497 | 497 | kfree(ptp); |
| @@ -92,6 +92,7 @@ enum { · 91 unmodified lines | ||
| 92 | 92 | MLX5E_ACCEL_FS_ESP_FT_LEVEL = MLX5E_INNER_TTC_FT_LEVEL + 1, |
| 93 | 93 | MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL, |
| 94 | 94 | MLX5E_ACCEL_FS_POL_FT_LEVEL, |
| 95 | + MLX5E_ACCEL_FS_POL_MISS_FT_LEVEL, | |
| 95 | 96 | MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL, |
| 96 | 97 | #endif |
| 97 | 98 | }; |
| @@ -185,6 +185,7 @@ struct mlx5e_ipsec_rx_create_attr { · 184 unmodified lines | ||
| 185 | 185 | u32 family; |
| 186 | 186 | int prio; |
| 187 | 187 | int pol_level; |
| 188 | + int pol_miss_level; | |
| 188 | 189 | int sa_level; |
| 189 | 190 | int status_level; |
| 190 | 191 | enum mlx5_flow_namespace_type chains_ns; |
| @@ -747,6 +747,7 @@ static void ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec, · 746 unmodified lines | ||
| 747 | 747 | attr->family = family; |
| 748 | 748 | attr->prio = MLX5E_NIC_PRIO; |
| 749 | 749 | attr->pol_level = MLX5E_ACCEL_FS_POL_FT_LEVEL; |
| 750 | + attr->pol_miss_level = MLX5E_ACCEL_FS_POL_MISS_FT_LEVEL; | |
| 750 | 751 | attr->sa_level = MLX5E_ACCEL_FS_ESP_FT_LEVEL; |
| 751 | 752 | attr->status_level = MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL; |
| 752 | 753 | attr->chains_ns = MLX5_FLOW_NAMESPACE_KERNEL; |
| @@ -833,7 +834,7 @@ static int ipsec_rx_chains_create_miss(struct mlx5e_ipsec *ipsec, · 80 unmodified lines | ||
| 833 | 834 | |
| 834 | 835 | ft_attr.max_fte = 1; |
| 835 | 836 | ft_attr.autogroup.max_num_groups = 1; |
| 836 | − ft_attr.level = attr->pol_level; | |
| 837 | + ft_attr.level = attr->pol_miss_level; | |
| 837 | 838 | ft_attr.prio = attr->prio; |
| 838 | 839 | |
| 839 | 840 | ft = mlx5_create_auto_grouped_flow_table(attr->ns, &ft_attr); |
| @@ -140,8 +140,6 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv) · 139 unmodified lines | ||
| 140 | 140 | if (up) { |
| 141 | 141 | netdev_info(priv->netdev, "Link up\n"); |
| 142 | 142 | netif_carrier_on(priv->netdev); |
| 143 | − mlx5e_port_manual_buffer_config(priv, 0, priv->netdev->mtu, | |
| 144 | − NULL, NULL, NULL); | |
| 145 | 143 | } else { |
| 146 | 144 | netdev_info(priv->netdev, "Link down\n"); |
| 147 | 145 | netif_carrier_off(priv->netdev); |
| @@ -1506,12 +1506,21 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = { · 1505 unmodified lines | ||
| 1506 | 1506 | static int |
| 1507 | 1507 | mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) |
| 1508 | 1508 | { |
| 1509 | − struct mlx5e_priv *priv = netdev_priv(mlx5_uplink_netdev_get(dev)); | |
| 1510 | 1509 | struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep); |
| 1510 | + struct net_device *netdev; | |
| 1511 | + struct mlx5e_priv *priv; | |
| 1512 | + int err; | |
| 1513 | + | |
| 1514 | + netdev = mlx5_uplink_netdev_get(dev); | |
| 1515 | + if (!netdev) | |
| 1516 | + return 0; | |
| 1511 | 1517 | |
| 1518 | + priv = netdev_priv(netdev); | |
| 1512 | 1519 | rpriv->netdev = priv->netdev; |
| 1513 | − return mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile, | |
| 1514 | − rpriv); | |
| 1520 | + err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile, | |
| 1521 | + rpriv); | |
| 1522 | + mlx5_uplink_netdev_put(dev, netdev); | |
| 1523 | + return err; | |
| 1515 | 1524 | } |
| 1516 | 1525 | |
| 1517 | 1526 | static void |
| @@ -1638,8 +1647,16 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep) · 120 unmodified lines | ||
| 1638 | 1647 | { |
| 1639 | 1648 | struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep); |
| 1640 | 1649 | struct net_device *netdev = rpriv->netdev; |
| 1641 | − struct mlx5e_priv *priv = netdev_priv(netdev); | |
| 1642 | − void *ppriv = priv->ppriv; | |
| 1650 | + struct mlx5e_priv *priv; | |
| 1651 | + void *ppriv; | |
| 1652 | + | |
| 1653 | + if (!netdev) { | |
| 1654 | + ppriv = rpriv; | |
| 1655 | + goto free_ppriv; | |
| 1656 | + } | |
| 1657 | + | |
| 1658 | + priv = netdev_priv(netdev); | |
| 1659 | + ppriv = priv->ppriv; | |
| 1643 | 1660 | |
| 1644 | 1661 | if (rep->vport == MLX5_VPORT_UPLINK) { |
| 1645 | 1662 | mlx5e_vport_uplink_rep_unload(rpriv); |
| @@ -1515,6 +1515,7 @@ static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev) · 1514 unmodified lines | ||
| 1515 | 1515 | speed = lksettings.base.speed; |
| 1516 | 1516 | |
| 1517 | 1517 | out: |
| 1518 | + mlx5_uplink_netdev_put(mdev, slave); | |
| 1518 | 1519 | return speed; |
| 1519 | 1520 | } |
| 1520 | 1521 | |
| @@ -114,9 +114,9 @@ · 113 unmodified lines | ||
| 114 | 114 | #define ETHTOOL_NUM_PRIOS 11 |
| 115 | 115 | #define ETHTOOL_MIN_LEVEL (KERNEL_MIN_LEVEL + ETHTOOL_NUM_PRIOS) |
| 116 | 116 | /* Vlan, mac, ttc, inner ttc, {UDP/ANY/aRFS/accel/{esp, esp_err}}, IPsec policy, |
| 117 | − * {IPsec RoCE MPV,Alias table},IPsec RoCE policy | |
| 117 | + * IPsec policy miss, {IPsec RoCE MPV,Alias table},IPsec RoCE policy | |
| 118 | 118 | */ |
| 119 | −#define KERNEL_NIC_PRIO_NUM_LEVELS 10 | |
| 119 | +#define KERNEL_NIC_PRIO_NUM_LEVELS 11 | |
| 120 | 120 | #define KERNEL_NIC_NUM_PRIOS 1 |
| 121 | 121 | /* One more level for tc, and one more for promisc */ |
| 122 | 122 | #define KERNEL_MIN_LEVEL (KERNEL_NIC_PRIO_NUM_LEVELS + 2) |
| @@ -47,7 +47,20 @@ int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data); · 46 unmodified lines | ||
| 47 | 47 | |
| 48 | 48 | static inline struct net_device *mlx5_uplink_netdev_get(struct mlx5_core_dev *mdev) |
| 49 | 49 | { |
| 50 | − return mdev->mlx5e_res.uplink_netdev; | |
| 50 | + struct mlx5e_resources *mlx5e_res = &mdev->mlx5e_res; | |
| 51 | + struct net_device *netdev; | |
| 52 | + | |
| 53 | + mutex_lock(&mlx5e_res->uplink_netdev_lock); | |
| 54 | + netdev = mlx5e_res->uplink_netdev; | |
| 55 | + netdev_hold(netdev, &mlx5e_res->tracker, GFP_KERNEL); | |
| 56 | + mutex_unlock(&mlx5e_res->uplink_netdev_lock); | |
| 57 | + return netdev; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static inline void mlx5_uplink_netdev_put(struct mlx5_core_dev *mdev, | |
| 61 | + struct net_device *netdev) | |
| 62 | +{ | |
| 63 | + netdev_put(netdev, &mdev->mlx5e_res.tracker); | |
| 51 | 64 | } |
| 52 | 65 | |
| 53 | 66 | struct mlx5_sd; |
| @@ -1170,7 +1170,11 @@ const struct mlx5_link_info *mlx5_port_ptys2info(struct mlx5_core_dev *mdev, · 1169 unmodified lines | ||
| 1170 | 1170 | mlx5e_port_get_link_mode_info_arr(mdev, &table, &max_size, |
| 1171 | 1171 | force_legacy); |
| 1172 | 1172 | i = find_first_bit(&temp, max_size); |
| 1173 | − if (i < max_size) | |
| 1173 | + | |
| 1174 | + /* mlx5e_link_info has holes. Check speed | |
| 1175 | + * is not zero as indication of one. | |
| 1176 | + */ | |
| 1177 | + if (i < max_size && table[i].speed) | |
| 1174 | 1178 | return &table[i]; |
| 1175 | 1179 | |
| 1176 | 1180 | return NULL; |
| @@ -820,7 +820,7 @@ static void rx_irq(struct net_device *ndev) · 819 unmodified lines | ||
| 820 | 820 | struct ns83820 *dev = PRIV(ndev); |
| 821 | 821 | struct rx_info *info = &dev->rx_info; |
| 822 | 822 | unsigned next_rx; |
| 823 | − int rx_rc, len; | |
| 823 | + int len; | |
| 824 | 824 | u32 cmdsts; |
| 825 | 825 | __le32 *desc; |
| 826 | 826 | unsigned long flags; |
| @@ -881,8 +881,10 @@ static void rx_irq(struct net_device *ndev) · 54 unmodified lines | ||
| 881 | 881 | if (likely(CMDSTS_OK & cmdsts)) { |
| 882 | 882 | #endif |
| 883 | 883 | skb_put(skb, len); |
| 884 | − if (unlikely(!skb)) | |
| 884 | + if (unlikely(!skb)) { | |
| 885 | + ndev->stats.rx_dropped++; | |
| 885 | 886 | goto netdev_mangle_me_harder_failed; |
| 887 | + } | |
| 886 | 888 | if (cmdsts & CMDSTS_DEST_MULTI) |
| 887 | 889 | ndev->stats.multicast++; |
| 888 | 890 | ndev->stats.rx_packets++; |
| @@ -901,15 +903,12 @@ static void rx_irq(struct net_device *ndev) · 12 unmodified lines | ||
| 901 | 903 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_IPV6), tag); |
| 902 | 904 | } |
| 903 | 905 | #endif |
| 904 | − rx_rc = netif_rx(skb); | |
| 905 | − if (NET_RX_DROP == rx_rc) { | |
| 906 | −netdev_mangle_me_harder_failed: | |
| 907 | − ndev->stats.rx_dropped++; | |
| 908 | − } | |
| 906 | + netif_rx(skb); | |
| 909 | 907 | } else { |
| 910 | 908 | dev_kfree_skb_irq(skb); |
| 911 | 909 | } |
| 912 | 910 | |
| 911 | +netdev_mangle_me_harder_failed: | |
| 913 | 912 | nr++; |
| 914 | 913 | next_rx = info->next_rx; |
| 915 | 914 | desc = info->descs + (DESC_SIZE * next_rx); |
| @@ -4462,10 +4462,11 @@ static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn, · 4461 unmodified lines | ||
| 4462 | 4462 | goto out; |
| 4463 | 4463 | } |
| 4464 | 4464 | |
| 4465 | − /* Add override window info to buffer */ | |
| 4465 | + /* Add override window info to buffer, preventing buffer overflow */ | |
| 4466 | 4466 | override_window_dwords = |
| 4467 | − qed_rd(p_hwfn, p_ptt, GRC_REG_NUMBER_VALID_OVERRIDE_WINDOW) * | |
| 4468 | − PROTECTION_OVERRIDE_ELEMENT_DWORDS; | |
| 4467 | + min(qed_rd(p_hwfn, p_ptt, GRC_REG_NUMBER_VALID_OVERRIDE_WINDOW) * | |
| 4468 | + PROTECTION_OVERRIDE_ELEMENT_DWORDS, | |
| 4469 | + PROTECTION_OVERRIDE_DEPTH_DWORDS); | |
| 4469 | 4470 | if (override_window_dwords) { |
| 4470 | 4471 | addr = BYTES_TO_DWORDS(GRC_REG_PROTECTION_OVERRIDE_WINDOW); |
| 4471 | 4472 | offset += qed_grc_dump_addr_range(p_hwfn, |
| @@ -2092,7 +2092,7 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, · 2091 unmodified lines | ||
| 2092 | 2092 | break; |
| 2093 | 2093 | } |
| 2094 | 2094 | |
| 2095 | − if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && | |
| 2095 | + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_7000 && | |
| 2096 | 2096 | trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) |
| 2097 | 2097 | len = DIV_ROUND_UP(len, 4); |
| 2098 | 2098 | |
| @@ -1168,12 +1168,6 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev, · 1167 unmodified lines | ||
| 1168 | 1168 | return devm_ioremap_resource(&pdev->dev, &port->regs); |
| 1169 | 1169 | } |
| 1170 | 1170 | |
| 1171 | −#define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03) | |
| 1172 | −#define DT_TYPE_IO 0x1 | |
| 1173 | −#define DT_TYPE_MEM32 0x2 | |
| 1174 | −#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF) | |
| 1175 | −#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) | |
| 1176 | − | |
| 1177 | 1171 | static int mvebu_get_tgt_attr(struct device_node *np, int devfn, |
| 1178 | 1172 | unsigned long type, |
| 1179 | 1173 | unsigned int *tgt, |
| @@ -1189,19 +1183,12 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn, · 9 unmodified lines | ||
| 1189 | 1183 | return -EINVAL; |
| 1190 | 1184 | |
| 1191 | 1185 | for_each_of_range(&parser, &range) { |
| 1192 | − unsigned long rtype; | |
| 1193 | 1186 | u32 slot = upper_32_bits(range.bus_addr); |
| 1194 | 1187 | |
| 1195 | − if (DT_FLAGS_TO_TYPE(range.flags) == DT_TYPE_IO) | |
| 1196 | − rtype = IORESOURCE_IO; | |
| 1197 | − else if (DT_FLAGS_TO_TYPE(range.flags) == DT_TYPE_MEM32) | |
| 1198 | − rtype = IORESOURCE_MEM; | |
| 1199 | − else | |
| 1200 | − continue; | |
| 1201 | − | |
| 1202 | − if (slot == PCI_SLOT(devfn) && type == rtype) { | |
| 1203 | − *tgt = DT_CPUADDR_TO_TARGET(range.cpu_addr); | |
| 1204 | − *attr = DT_CPUADDR_TO_ATTR(range.cpu_addr); | |
| 1188 | + if (slot == PCI_SLOT(devfn) && | |
| 1189 | + type == (range.flags & IORESOURCE_TYPE_BITS)) { | |
| 1190 | + *tgt = (range.parent_bus_addr >> 56) & 0xFF; | |
| 1191 | + *attr = (range.parent_bus_addr >> 48) & 0xFF; | |
| 1205 | 1192 | return 0; |
| 1206 | 1193 | } |
| 1207 | 1194 | } |
| @@ -127,13 +127,13 @@ static int eusb2_repeater_init(struct phy *phy) · 126 unmodified lines | ||
| 127 | 127 | rptr->cfg->init_tbl[i].value); |
| 128 | 128 | |
| 129 | 129 | /* Override registers from devicetree values */ |
| 130 | − if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &val)) | |
| 130 | + if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val)) | |
| 131 | 131 | regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, val); |
| 132 | 132 | |
| 133 | 133 | if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &val)) |
| 134 | 134 | regmap_write(regmap, base + EUSB2_TUNE_HSDISC, val); |
| 135 | 135 | |
| 136 | − if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val)) | |
| 136 | + if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &val)) | |
| 137 | 137 | regmap_write(regmap, base + EUSB2_TUNE_IUSB2, val); |
| 138 | 138 | |
| 139 | 139 | /* Wait for status OK */ |
| @@ -3067,6 +3067,14 @@ struct qmp_pcie { · 3066 unmodified lines | ||
| 3067 | 3067 | struct clk_fixed_rate aux_clk_fixed; |
| 3068 | 3068 | }; |
| 3069 | 3069 | |
| 3070 | +static bool qphy_checkbits(const void __iomem *base, u32 offset, u32 val) | |
| 3071 | +{ | |
| 3072 | + u32 reg; | |
| 3073 | + | |
| 3074 | + reg = readl(base + offset); | |
| 3075 | + return (reg & val) == val; | |
| 3076 | +} | |
| 3077 | + | |
| 3070 | 3078 | static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) |
| 3071 | 3079 | { |
| 3072 | 3080 | u32 reg; |
| @@ -4339,16 +4347,21 @@ static int qmp_pcie_init(struct phy *phy) · 1266 unmodified lines | ||
| 4339 | 4347 | struct qmp_pcie *qmp = phy_get_drvdata(phy); |
| 4340 | 4348 | const struct qmp_phy_cfg *cfg = qmp->cfg; |
| 4341 | 4349 | void __iomem *pcs = qmp->pcs; |
| 4342 | − bool phy_initialized = !!(readl(pcs + cfg->regs[QPHY_START_CTRL])); | |
| 4343 | 4350 | int ret; |
| 4344 | 4351 | |
| 4345 | − qmp->skip_init = qmp->nocsr_reset && phy_initialized; | |
| 4346 | 4352 | /* |
| 4347 | − * We need to check the existence of init sequences in two cases: | |
| 4348 | − * 1. The PHY doesn't support no_csr reset. | |
| 4349 | − * 2. The PHY supports no_csr reset but isn't initialized by bootloader. | |
| 4350 | − * As we can't skip init in these two cases. | |
| 4353 | + * We can skip PHY initialization if all of the following conditions | |
| 4354 | + * are met: | |
| 4355 | + * 1. The PHY supports the nocsr_reset that preserves the PHY config. | |
| 4356 | + * 2. The PHY was started (and not powered down again) by the | |
| 4357 | + * bootloader, with all of the expected bits set correctly. | |
| 4358 | + * In this case, we can continue without having the init sequence | |
| 4359 | + * defined in the driver. | |
| 4351 | 4360 | */ |
| 4361 | + qmp->skip_init = qmp->nocsr_reset && | |
| 4362 | + qphy_checkbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START) && | |
| 4363 | + qphy_checkbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], cfg->pwrdn_ctrl); | |
| 4364 | + | |
| 4352 | 4365 | if (!qmp->skip_init && !cfg->tbls.serdes_num) { |
| 4353 | 4366 | dev_err(qmp->dev, "Init sequence not available\n"); |
| 4354 | 4367 | return -ENODATA; |
| @@ -3164,18 +3164,22 @@ tegra210_xusb_padctl_probe(struct device *dev, · 3163 unmodified lines | ||
| 3164 | 3164 | } |
| 3165 | 3165 | |
| 3166 | 3166 | pdev = of_find_device_by_node(np); |
| 3167 | + of_node_put(np); | |
| 3167 | 3168 | if (!pdev) { |
| 3168 | 3169 | dev_warn(dev, "PMC device is not available\n"); |
| 3169 | 3170 | goto out; |
| 3170 | 3171 | } |
| 3171 | 3172 | |
| 3172 | − if (!platform_get_drvdata(pdev)) | |
| 3173 | + if (!platform_get_drvdata(pdev)) { | |
| 3174 | + put_device(&pdev->dev); | |
| 3173 | 3175 | return ERR_PTR(-EPROBE_DEFER); |
| 3176 | + } | |
| 3174 | 3177 | |
| 3175 | 3178 | padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk"); |
| 3176 | 3179 | if (!padctl->regmap) |
| 3177 | 3180 | dev_info(dev, "failed to find PMC regmap\n"); |
| 3178 | 3181 | |
| 3182 | + put_device(&pdev->dev); | |
| 3179 | 3183 | out: |
| 3180 | 3184 | return &padctl->base; |
| 3181 | 3185 | } |
| @@ -34,6 +34,7 @@ enum { · 33 unmodified lines | ||
| 34 | 34 | PHY_GMII_SEL_PORT_MODE = 0, |
| 35 | 35 | PHY_GMII_SEL_RGMII_ID_MODE, |
| 36 | 36 | PHY_GMII_SEL_RMII_IO_CLK_EN, |
| 37 | + PHY_GMII_SEL_FIXED_TX_DELAY, | |
| 37 | 38 | PHY_GMII_SEL_LAST, |
| 38 | 39 | }; |
| 39 | 40 | |
| @@ -127,6 +128,11 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) · 87 unmodified lines | ||
| 127 | 128 | goto unsupported; |
| 128 | 129 | } |
| 129 | 130 | |
| 131 | + /* With a fixed delay, some modes are not supported at all. */ | |
| 132 | + if (soc_data->features & BIT(PHY_GMII_SEL_FIXED_TX_DELAY) && | |
| 133 | + rgmii_id != 0) | |
| 134 | + return -EINVAL; | |
| 135 | + | |
| 130 | 136 | if_phy->phy_if_mode = submode; |
| 131 | 137 | |
| 132 | 138 | dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n", |
| @@ -210,25 +216,46 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = { · 77 unmodified lines | ||
| 210 | 216 | |
| 211 | 217 | static const |
| 212 | 218 | struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = { |
| 213 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), }, | |
| 214 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), }, | |
| 215 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), }, | |
| 216 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), }, | |
| 217 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), }, | |
| 218 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), }, | |
| 219 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), }, | |
| 220 | − { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), }, | |
| 219 | + { | |
| 220 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), | |
| 221 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x0, 4, 4), | |
| 222 | + }, { | |
| 223 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), | |
| 224 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x4, 4, 4), | |
| 225 | + }, { | |
| 226 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), | |
| 227 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x8, 4, 4), | |
| 228 | + }, { | |
| 229 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), | |
| 230 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0xC, 4, 4), | |
| 231 | + }, { | |
| 232 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), | |
| 233 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x10, 4, 4), | |
| 234 | + }, { | |
| 235 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), | |
| 236 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x14, 4, 4), | |
| 237 | + }, { | |
| 238 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), | |
| 239 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x18, 4, 4), | |
| 240 | + }, { | |
| 241 | + [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), | |
| 242 | + [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x1C, 4, 4), | |
| 243 | + }, | |
| 221 | 244 | }; |
| 222 | 245 | |
| 223 | 246 | static const |
| 224 | 247 | struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = { |
| 225 | 248 | .use_of_data = true, |
| 249 | + .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) | | |
| 250 | + BIT(PHY_GMII_SEL_FIXED_TX_DELAY), | |
| 226 | 251 | .regfields = phy_gmii_sel_fields_am654, |
| 227 | 252 | }; |
| 228 | 253 | |
| 229 | 254 | static const |
| 230 | 255 | struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { |
| 231 | 256 | .use_of_data = true, |
| 257 | + .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) | | |
| 258 | + BIT(PHY_GMII_SEL_FIXED_TX_DELAY), | |
| 232 | 259 | .regfields = phy_gmii_sel_fields_am654, |
| 233 | 260 | .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | |
| 234 | 261 | BIT(PHY_INTERFACE_MODE_USXGMII), |
| @@ -239,6 +266,8 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { · 4 unmodified lines | ||
| 239 | 266 | static const |
| 240 | 267 | struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = { |
| 241 | 268 | .use_of_data = true, |
| 269 | + .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) | | |
| 270 | + BIT(PHY_GMII_SEL_FIXED_TX_DELAY), | |
| 242 | 271 | .regfields = phy_gmii_sel_fields_am654, |
| 243 | 272 | .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII), |
| 244 | 273 | .num_ports = 8, |
| @@ -248,6 +277,8 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j721e = { · 3 unmodified lines | ||
| 248 | 277 | static const |
| 249 | 278 | struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw9g_soc_j784s4 = { |
| 250 | 279 | .use_of_data = true, |
| 280 | + .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) | | |
| 281 | + BIT(PHY_GMII_SEL_FIXED_TX_DELAY), | |
| 251 | 282 | .regfields = phy_gmii_sel_fields_am654, |
| 252 | 283 | .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | |
| 253 | 284 | BIT(PHY_INTERFACE_MODE_USXGMII), |
| @@ -363,6 +363,13 @@ static void omap_usb2_init_errata(struct omap_usb *phy) · 362 unmodified lines | ||
| 363 | 363 | phy->flags |= OMAP_USB2_DISABLE_CHRG_DET; |
| 364 | 364 | } |
| 365 | 365 | |
| 366 | +static void omap_usb2_put_device(void *_dev) | |
| 367 | +{ | |
| 368 | + struct device *dev = _dev; | |
| 369 | + | |
| 370 | + put_device(dev); | |
| 371 | +} | |
| 372 | + | |
| 366 | 373 | static int omap_usb2_probe(struct platform_device *pdev) |
| 367 | 374 | { |
| 368 | 375 | struct omap_usb *phy; |
| @@ -373,6 +380,7 @@ static int omap_usb2_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 373 | 380 | struct device_node *control_node; |
| 374 | 381 | struct platform_device *control_pdev; |
| 375 | 382 | const struct usb_phy_data *phy_data; |
| 383 | + int ret; | |
| 376 | 384 | |
| 377 | 385 | phy_data = device_get_match_data(&pdev->dev); |
| 378 | 386 | if (!phy_data) |
| @@ -423,6 +431,11 @@ static int omap_usb2_probe(struct platform_device *pdev) · 44 unmodified lines | ||
| 423 | 431 | return -EINVAL; |
| 424 | 432 | } |
| 425 | 433 | phy->control_dev = &control_pdev->dev; |
| 434 | + | |
| 435 | + ret = devm_add_action_or_reset(&pdev->dev, omap_usb2_put_device, | |
| 436 | + phy->control_dev); | |
| 437 | + if (ret) | |
| 438 | + return ret; | |
| 426 | 439 | } else { |
| 427 | 440 | if (of_property_read_u32_index(node, |
| 428 | 441 | "syscon-phy-power", 1, |
| @@ -667,12 +667,20 @@ static int ti_pipe3_get_clk(struct ti_pipe3 *phy) · 666 unmodified lines | ||
| 667 | 667 | return 0; |
| 668 | 668 | } |
| 669 | 669 | |
| 670 | +static void ti_pipe3_put_device(void *_dev) | |
| 671 | +{ | |
| 672 | + struct device *dev = _dev; | |
| 673 | + | |
| 674 | + put_device(dev); | |
| 675 | +} | |
| 676 | + | |
| 670 | 677 | static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy) |
| 671 | 678 | { |
| 672 | 679 | struct device *dev = phy->dev; |
| 673 | 680 | struct device_node *node = dev->of_node; |
| 674 | 681 | struct device_node *control_node; |
| 675 | 682 | struct platform_device *control_pdev; |
| 683 | + int ret; | |
| 676 | 684 | |
| 677 | 685 | phy->phy_power_syscon = syscon_regmap_lookup_by_phandle(node, |
| 678 | 686 | "syscon-phy-power"); |
| @@ -704,6 +712,11 @@ static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy) · 25 unmodified lines | ||
| 704 | 712 | } |
| 705 | 713 | |
| 706 | 714 | phy->control_dev = &control_pdev->dev; |
| 715 | + | |
| 716 | + ret = devm_add_action_or_reset(dev, ti_pipe3_put_device, | |
| 717 | + phy->control_dev); | |
| 718 | + if (ret) | |
| 719 | + return ret; | |
| 707 | 720 | } |
| 708 | 721 | |
| 709 | 722 | if (phy->mode == PIPE3_MODE_PCIE) { |
| @@ -239,6 +239,14 @@ static const struct dmi_system_id fwbug_list[] = { · 238 unmodified lines | ||
| 239 | 239 | DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"), |
| 240 | 240 | } |
| 241 | 241 | }, |
| 242 | + { | |
| 243 | + .ident = "MECHREVO Yilong15Pro Series GM5HG7A", | |
| 244 | + .driver_data = &quirk_spurious_8042, | |
| 245 | + .matches = { | |
| 246 | + DMI_MATCH(DMI_SYS_VENDOR, "MECHREVO"), | |
| 247 | + DMI_MATCH(DMI_PRODUCT_NAME, "Yilong15Pro Series GM5HG7A"), | |
| 248 | + } | |
| 249 | + }, | |
| 242 | 250 | /* https://bugzilla.kernel.org/show_bug.cgi?id=220116 */ |
| 243 | 251 | { |
| 244 | 252 | .ident = "PCSpecialist Lafite Pro V 14M", |
| @@ -403,6 +403,7 @@ static const struct acpi_device_id amd_pmf_acpi_ids[] = { · 402 unmodified lines | ||
| 403 | 403 | {"AMDI0103", 0}, |
| 404 | 404 | {"AMDI0105", 0}, |
| 405 | 405 | {"AMDI0107", 0}, |
| 406 | + {"AMDI0108", 0}, | |
| 406 | 407 | { } |
| 407 | 408 | }; |
| 408 | 409 | MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids); |
| @@ -673,6 +673,8 @@ static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, · 672 unmodified lines | ||
| 673 | 673 | if (atkbd_reports_vol_keys) |
| 674 | 674 | *code = ASUS_WMI_KEY_IGNORE; |
| 675 | 675 | break; |
| 676 | + case 0x5D: /* Wireless console Toggle */ | |
| 677 | + case 0x5E: /* Wireless console Enable / Keyboard Attach, Detach */ | |
| 676 | 678 | case 0x5F: /* Wireless console Disable / Special Key */ |
| 677 | 679 | if (quirks->key_wlan_event) |
| 678 | 680 | *code = quirks->key_wlan_event; |
| @@ -124,6 +124,13 @@ static const struct dmi_system_id dmi_table[] = { · 123 unmodified lines | ||
| 124 | 124 | }, |
| 125 | 125 | .driver_data = (void *)aok_zoe_a1, |
| 126 | 126 | }, |
| 127 | + { | |
| 128 | + .matches = { | |
| 129 | + DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), | |
| 130 | + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1X"), | |
| 131 | + }, | |
| 132 | + .driver_data = (void *)oxp_fly, | |
| 133 | + }, | |
| 127 | 134 | { |
| 128 | 135 | .matches = { |
| 129 | 136 | DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), |
| @@ -306,6 +313,13 @@ static const struct dmi_system_id dmi_table[] = { · 176 unmodified lines | ||
| 306 | 313 | }, |
| 307 | 314 | .driver_data = (void *)oxp_x1, |
| 308 | 315 | }, |
| 316 | + { | |
| 317 | + .matches = { | |
| 318 | + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), | |
| 319 | + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro EVA-02"), | |
| 320 | + }, | |
| 321 | + .driver_data = (void *)oxp_x1, | |
| 322 | + }, | |
| 309 | 323 | {}, |
| 310 | 324 | }; |
| 311 | 325 | |
| @@ -1919,8 +1919,8 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) · 1918 unmodified lines | ||
| 1919 | 1919 | bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; |
| 1920 | 1920 | |
| 1921 | 1921 | cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); |
| 1922 | − if ((cache.flags & 0xff) == 0xff) | |
| 1923 | − cache.flags = -1; /* read error */ | |
| 1922 | + if (di->chip == BQ27000 && (cache.flags & 0xff) == 0xff) | |
| 1923 | + cache.flags = -ENODEV; /* bq27000 hdq read error */ | |
| 1924 | 1924 | if (cache.flags >= 0) { |
| 1925 | 1925 | cache.capacity = bq27xxx_battery_read_soc(di); |
| 1926 | 1926 | |
| @@ -83,9 +83,11 @@ static int sy7636a_regulator_probe(struct platform_device *pdev) · 82 unmodified lines | ||
| 83 | 83 | if (!regmap) |
| 84 | 84 | return -EPROBE_DEFER; |
| 85 | 85 | |
| 86 | − gdp = devm_gpiod_get(pdev->dev.parent, "epd-pwr-good", GPIOD_IN); | |
| 86 | + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); | |
| 87 | + | |
| 88 | + gdp = devm_gpiod_get(&pdev->dev, "epd-pwr-good", GPIOD_IN); | |
| 87 | 89 | if (IS_ERR(gdp)) { |
| 88 | − dev_err(pdev->dev.parent, "Power good GPIO fault %ld\n", PTR_ERR(gdp)); | |
| 90 | + dev_err(&pdev->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp)); | |
| 89 | 91 | return PTR_ERR(gdp); |
| 90 | 92 | } |
| 91 | 93 | |
| @@ -105,7 +107,6 @@ static int sy7636a_regulator_probe(struct platform_device *pdev) · 13 unmodified lines | ||
| 105 | 107 | } |
| 106 | 108 | |
| 107 | 109 | config.dev = &pdev->dev; |
| 108 | − config.dev->of_node = pdev->dev.parent->of_node; | |
| 109 | 110 | config.regmap = regmap; |
| 110 | 111 | |
| 111 | 112 | rdev = devm_regulator_register(&pdev->dev, &desc, &config); |
| @@ -543,10 +543,10 @@ static ssize_t hvc_write(struct tty_struct *tty, const u8 *buf, size_t count) · 542 unmodified lines | ||
| 543 | 543 | } |
| 544 | 544 | |
| 545 | 545 | /* |
| 546 | − * Racy, but harmless, kick thread if there is still pending data. | |
| 546 | + * Kick thread to flush if there's still pending data | |
| 547 | + * or to wakeup the write queue. | |
| 547 | 548 | */ |
| 548 | − if (hp->n_outbuf) | |
| 549 | − hvc_kick(); | |
| 549 | + hvc_kick(); | |
| 550 | 550 | |
| 551 | 551 | return written; |
| 552 | 552 | } |
| @@ -1177,17 +1177,6 @@ static int sc16is7xx_startup(struct uart_port *port) · 1176 unmodified lines | ||
| 1177 | 1177 | sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, |
| 1178 | 1178 | SC16IS7XX_FCR_FIFO_BIT); |
| 1179 | 1179 | |
| 1180 | − /* Enable EFR */ | |
| 1181 | − sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, | |
| 1182 | − SC16IS7XX_LCR_CONF_MODE_B); | |
| 1183 | − | |
| 1184 | − regcache_cache_bypass(one->regmap, true); | |
| 1185 | − | |
| 1186 | − /* Enable write access to enhanced features and internal clock div */ | |
| 1187 | − sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, | |
| 1188 | − SC16IS7XX_EFR_ENABLE_BIT, | |
| 1189 | − SC16IS7XX_EFR_ENABLE_BIT); | |
| 1190 | − | |
| 1191 | 1180 | /* Enable TCR/TLR */ |
| 1192 | 1181 | sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, |
| 1193 | 1182 | SC16IS7XX_MCR_TCRTLR_BIT, |
| @@ -1199,7 +1188,8 @@ static int sc16is7xx_startup(struct uart_port *port) · 5 unmodified lines | ||
| 1199 | 1188 | SC16IS7XX_TCR_RX_RESUME(24) | |
| 1200 | 1189 | SC16IS7XX_TCR_RX_HALT(48)); |
| 1201 | 1190 | |
| 1202 | − regcache_cache_bypass(one->regmap, false); | |
| 1191 | + /* Disable TCR/TLR access */ | |
| 1192 | + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, 0); | |
| 1203 | 1193 | |
| 1204 | 1194 | /* Now, initialize the UART */ |
| 1205 | 1195 | sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); |
| @@ -33,7 +33,6 @@ · 32 unmodified lines | ||
| 33 | 33 | #define CDNS_UART_MINOR 0 /* works best with devtmpfs */ |
| 34 | 34 | #define CDNS_UART_NR_PORTS 16 |
| 35 | 35 | #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ |
| 36 | −#define CDNS_UART_REGISTER_SPACE 0x1000 | |
| 37 | 36 | #define TX_TIMEOUT 500000 |
| 38 | 37 | |
| 39 | 38 | /* Rx Trigger level */ |
| @@ -1098,15 +1097,15 @@ static int cdns_uart_verify_port(struct uart_port *port, · 1058 unmodified lines | ||
| 1098 | 1097 | */ |
| 1099 | 1098 | static int cdns_uart_request_port(struct uart_port *port) |
| 1100 | 1099 | { |
| 1101 | − if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE, | |
| 1100 | + if (!request_mem_region(port->mapbase, port->mapsize, | |
| 1102 | 1101 | CDNS_UART_NAME)) { |
| 1103 | 1102 | return -ENOMEM; |
| 1104 | 1103 | } |
| 1105 | 1104 | |
| 1106 | − port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE); | |
| 1105 | + port->membase = ioremap(port->mapbase, port->mapsize); | |
| 1107 | 1106 | if (!port->membase) { |
| 1108 | 1107 | dev_err(port->dev, "Unable to map registers\n"); |
| 1109 | − release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); | |
| 1108 | + release_mem_region(port->mapbase, port->mapsize); | |
| 1110 | 1109 | return -ENOMEM; |
| 1111 | 1110 | } |
| 1112 | 1111 | return 0; |
| @@ -1121,7 +1120,7 @@ static int cdns_uart_request_port(struct uart_port *port) · 8 unmodified lines | ||
| 1121 | 1120 | */ |
| 1122 | 1121 | static void cdns_uart_release_port(struct uart_port *port) |
| 1123 | 1122 | { |
| 1124 | − release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); | |
| 1123 | + release_mem_region(port->mapbase, port->mapsize); | |
| 1125 | 1124 | iounmap(port->membase); |
| 1126 | 1125 | port->membase = NULL; |
| 1127 | 1126 | } |
| @@ -1780,6 +1779,7 @@ static int cdns_uart_probe(struct platform_device *pdev) · 652 unmodified lines | ||
| 1780 | 1779 | * and triggers invocation of the config_port() entry point. |
| 1781 | 1780 | */ |
| 1782 | 1781 | port->mapbase = res->start; |
| 1782 | + port->mapsize = resource_size(res); | |
| 1783 | 1783 | port->irq = irq; |
| 1784 | 1784 | port->dev = &pdev->dev; |
| 1785 | 1785 | port->uartclk = clk_get_rate(cdns_uart_data->uartclk); |
| @@ -119,11 +119,11 @@ ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf) · 118 unmodified lines | ||
| 119 | 119 | guard(mutex)(&usb_dynids_lock); |
| 120 | 120 | list_for_each_entry(dynid, &dynids->list, node) |
| 121 | 121 | if (dynid->id.bInterfaceClass != 0) |
| 122 | − count += sysfs_emit_at(&buf[count], count, "%04x %04x %02x\n", | |
| 122 | + count += sysfs_emit_at(buf, count, "%04x %04x %02x\n", | |
| 123 | 123 | dynid->id.idVendor, dynid->id.idProduct, |
| 124 | 124 | dynid->id.bInterfaceClass); |
| 125 | 125 | else |
| 126 | − count += sysfs_emit_at(&buf[count], count, "%04x %04x\n", | |
| 126 | + count += sysfs_emit_at(buf, count, "%04x %04x\n", | |
| 127 | 127 | dynid->id.idVendor, dynid->id.idProduct); |
| 128 | 128 | return count; |
| 129 | 129 | } |
| @@ -1599,6 +1599,7 @@ static int f_midi2_create_card(struct f_midi2 *midi2) · 1598 unmodified lines | ||
| 1599 | 1599 | strscpy(fb->info.name, ump_fb_name(b), |
| 1600 | 1600 | sizeof(fb->info.name)); |
| 1601 | 1601 | } |
| 1602 | + snd_ump_update_group_attrs(ump); | |
| 1602 | 1603 | } |
| 1603 | 1604 | |
| 1604 | 1605 | for (i = 0; i < midi2->num_eps; i++) { |
| @@ -1736,9 +1737,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2, · 131 unmodified lines | ||
| 1736 | 1737 | case USB_SPEED_HIGH: |
| 1737 | 1738 | midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(512); |
| 1738 | 1739 | midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(512); |
| 1739 | − for (i = 0; i < midi2->num_eps; i++) | |
| 1740 | + for (i = 0; i < midi2->num_eps; i++) { | |
| 1740 | 1741 | midi2_midi2_ep_out_desc[i].wMaxPacketSize = |
| 1741 | 1742 | cpu_to_le16(512); |
| 1743 | + midi2_midi2_ep_in_desc[i].wMaxPacketSize = | |
| 1744 | + cpu_to_le16(512); | |
| 1745 | + } | |
| 1742 | 1746 | fallthrough; |
| 1743 | 1747 | case USB_SPEED_FULL: |
| 1744 | 1748 | midi1_in_eps = midi2_midi1_ep_in_descs; |
| @@ -1747,9 +1751,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2, · 2 unmodified lines | ||
| 1747 | 1751 | case USB_SPEED_SUPER: |
| 1748 | 1752 | midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(1024); |
| 1749 | 1753 | midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(1024); |
| 1750 | − for (i = 0; i < midi2->num_eps; i++) | |
| 1754 | + for (i = 0; i < midi2->num_eps; i++) { | |
| 1751 | 1755 | midi2_midi2_ep_out_desc[i].wMaxPacketSize = |
| 1752 | 1756 | cpu_to_le16(1024); |
| 1757 | + midi2_midi2_ep_in_desc[i].wMaxPacketSize = | |
| 1758 | + cpu_to_le16(1024); | |
| 1759 | + } | |
| 1753 | 1760 | midi1_in_eps = midi2_midi1_ep_in_ss_descs; |
| 1754 | 1761 | midi1_out_eps = midi2_midi1_ep_out_ss_descs; |
| 1755 | 1762 | break; |
| @@ -765,8 +765,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) · 764 unmodified lines | ||
| 765 | 765 | if (!dum->driver) |
| 766 | 766 | return -ESHUTDOWN; |
| 767 | 767 | |
| 768 | − local_irq_save(flags); | |
| 769 | − spin_lock(&dum->lock); | |
| 768 | + spin_lock_irqsave(&dum->lock, flags); | |
| 770 | 769 | list_for_each_entry(iter, &ep->queue, queue) { |
| 771 | 770 | if (&iter->req != _req) |
| 772 | 771 | continue; |
| @@ -776,15 +775,16 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) · 3 unmodified lines | ||
| 776 | 775 | retval = 0; |
| 777 | 776 | break; |
| 778 | 777 | } |
| 779 | − spin_unlock(&dum->lock); | |
| 780 | 778 | |
| 781 | 779 | if (retval == 0) { |
| 782 | 780 | dev_dbg(udc_dev(dum), |
| 783 | 781 | "dequeued req %p from %s, len %d buf %p\n", |
| 784 | 782 | req, _ep->name, _req->length, _req->buf); |
| 783 | + spin_unlock(&dum->lock); | |
| 785 | 784 | usb_gadget_giveback_request(_ep, _req); |
| 785 | + spin_lock(&dum->lock); | |
| 786 | 786 | } |
| 787 | − local_irq_restore(flags); | |
| 787 | + spin_unlock_irqrestore(&dum->lock, flags); | |
| 788 | 788 | return retval; |
| 789 | 789 | } |
| 790 | 790 | |
| @@ -101,13 +101,34 @@ static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings) · 100 unmodified lines | ||
| 101 | 101 | return string_length; |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | +static void xhci_dbc_init_ep_contexts(struct xhci_dbc *dbc) | |
| 105 | +{ | |
| 106 | + struct xhci_ep_ctx *ep_ctx; | |
| 107 | + unsigned int max_burst; | |
| 108 | + dma_addr_t deq; | |
| 109 | + | |
| 110 | + max_burst = DBC_CTRL_MAXBURST(readl(&dbc->regs->control)); | |
| 111 | + | |
| 112 | + /* Populate bulk out endpoint context: */ | |
| 113 | + ep_ctx = dbc_bulkout_ctx(dbc); | |
| 114 | + deq = dbc_bulkout_enq(dbc); | |
| 115 | + ep_ctx->ep_info = 0; | |
| 116 | + ep_ctx->ep_info2 = dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst); | |
| 117 | + ep_ctx->deq = cpu_to_le64(deq | dbc->ring_out->cycle_state); | |
| 118 | + | |
| 119 | + /* Populate bulk in endpoint context: */ | |
| 120 | + ep_ctx = dbc_bulkin_ctx(dbc); | |
| 121 | + deq = dbc_bulkin_enq(dbc); | |
| 122 | + ep_ctx->ep_info = 0; | |
| 123 | + ep_ctx->ep_info2 = dbc_epctx_info2(BULK_IN_EP, 1024, max_burst); | |
| 124 | + ep_ctx->deq = cpu_to_le64(deq | dbc->ring_in->cycle_state); | |
| 125 | +} | |
| 126 | + | |
| 104 | 127 | static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) |
| 105 | 128 | { |
| 106 | 129 | struct dbc_info_context *info; |
| 107 | − struct xhci_ep_ctx *ep_ctx; | |
| 108 | 130 | u32 dev_info; |
| 109 | − dma_addr_t deq, dma; | |
| 110 | − unsigned int max_burst; | |
| 131 | + dma_addr_t dma; | |
| 111 | 132 | |
| 112 | 133 | if (!dbc) |
| 113 | 134 | return; |
| @@ -121,20 +142,8 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) · 7 unmodified lines | ||
| 121 | 142 | info->serial = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3); |
| 122 | 143 | info->length = cpu_to_le32(string_length); |
| 123 | 144 | |
| 124 | − /* Populate bulk out endpoint context: */ | |
| 125 | − ep_ctx = dbc_bulkout_ctx(dbc); | |
| 126 | − max_burst = DBC_CTRL_MAXBURST(readl(&dbc->regs->control)); | |
| 127 | − deq = dbc_bulkout_enq(dbc); | |
| 128 | − ep_ctx->ep_info = 0; | |
| 129 | − ep_ctx->ep_info2 = dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst); | |
| 130 | − ep_ctx->deq = cpu_to_le64(deq | dbc->ring_out->cycle_state); | |
| 131 | − | |
| 132 | − /* Populate bulk in endpoint context: */ | |
| 133 | − ep_ctx = dbc_bulkin_ctx(dbc); | |
| 134 | − deq = dbc_bulkin_enq(dbc); | |
| 135 | − ep_ctx->ep_info = 0; | |
| 136 | − ep_ctx->ep_info2 = dbc_epctx_info2(BULK_IN_EP, 1024, max_burst); | |
| 137 | − ep_ctx->deq = cpu_to_le64(deq | dbc->ring_in->cycle_state); | |
| 145 | + /* Populate bulk in and out endpoint contexts: */ | |
| 146 | + xhci_dbc_init_ep_contexts(dbc); | |
| 138 | 147 | |
| 139 | 148 | /* Set DbC context and info registers: */ |
| 140 | 149 | lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp); |
| @@ -436,6 +445,42 @@ dbc_alloc_ctx(struct device *dev, gfp_t flags) · 295 unmodified lines | ||
| 436 | 445 | return ctx; |
| 437 | 446 | } |
| 438 | 447 | |
| 448 | +static void xhci_dbc_ring_init(struct xhci_ring *ring) | |
| 449 | +{ | |
| 450 | + struct xhci_segment *seg = ring->first_seg; | |
| 451 | + | |
| 452 | + /* clear all trbs on ring in case of old ring */ | |
| 453 | + memset(seg->trbs, 0, TRB_SEGMENT_SIZE); | |
| 454 | + | |
| 455 | + /* Only event ring does not use link TRB */ | |
| 456 | + if (ring->type != TYPE_EVENT) { | |
| 457 | + union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1]; | |
| 458 | + | |
| 459 | + trb->link.segment_ptr = cpu_to_le64(ring->first_seg->dma); | |
| 460 | + trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK)); | |
| 461 | + } | |
| 462 | + xhci_initialize_ring_info(ring); | |
| 463 | +} | |
| 464 | + | |
| 465 | +static int xhci_dbc_reinit_ep_rings(struct xhci_dbc *dbc) | |
| 466 | +{ | |
| 467 | + struct xhci_ring *in_ring = dbc->eps[BULK_IN].ring; | |
| 468 | + struct xhci_ring *out_ring = dbc->eps[BULK_OUT].ring; | |
| 469 | + | |
| 470 | + if (!in_ring || !out_ring || !dbc->ctx) { | |
| 471 | + dev_warn(dbc->dev, "Can't re-init unallocated endpoints\n"); | |
| 472 | + return -ENODEV; | |
| 473 | + } | |
| 474 | + | |
| 475 | + xhci_dbc_ring_init(in_ring); | |
| 476 | + xhci_dbc_ring_init(out_ring); | |
| 477 | + | |
| 478 | + /* set ep context enqueue, dequeue, and cycle to initial values */ | |
| 479 | + xhci_dbc_init_ep_contexts(dbc); | |
| 480 | + | |
| 481 | + return 0; | |
| 482 | +} | |
| 483 | + | |
| 439 | 484 | static struct xhci_ring * |
| 440 | 485 | xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags) |
| 441 | 486 | { |
| @@ -464,15 +509,10 @@ xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags) · 22 unmodified lines | ||
| 464 | 509 | |
| 465 | 510 | seg->dma = dma; |
| 466 | 511 | |
| 467 | − /* Only event ring does not use link TRB */ | |
| 468 | − if (type != TYPE_EVENT) { | |
| 469 | − union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1]; | |
| 470 | − | |
| 471 | − trb->link.segment_ptr = cpu_to_le64(dma); | |
| 472 | − trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK)); | |
| 473 | − } | |
| 474 | 512 | INIT_LIST_HEAD(&ring->td_list); |
| 475 | − xhci_initialize_ring_info(ring); | |
| 513 | + | |
| 514 | + xhci_dbc_ring_init(ring); | |
| 515 | + | |
| 476 | 516 | return ring; |
| 477 | 517 | dma_fail: |
| 478 | 518 | kfree(seg); |
| @@ -864,7 +904,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) · 385 unmodified lines | ||
| 864 | 904 | dev_info(dbc->dev, "DbC cable unplugged\n"); |
| 865 | 905 | dbc->state = DS_ENABLED; |
| 866 | 906 | xhci_dbc_flush_requests(dbc); |
| 867 | − | |
| 907 | + xhci_dbc_reinit_ep_rings(dbc); | |
| 868 | 908 | return EVT_DISC; |
| 869 | 909 | } |
| 870 | 910 | |
| @@ -874,7 +914,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) · 3 unmodified lines | ||
| 874 | 914 | writel(portsc, &dbc->regs->portsc); |
| 875 | 915 | dbc->state = DS_ENABLED; |
| 876 | 916 | xhci_dbc_flush_requests(dbc); |
| 877 | − | |
| 917 | + xhci_dbc_reinit_ep_rings(dbc); | |
| 878 | 918 | return EVT_DISC; |
| 879 | 919 | } |
| 880 | 920 | |
| @@ -962,7 +962,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i · 961 unmodified lines | ||
| 962 | 962 | out: |
| 963 | 963 | /* we are now at a leaf device */ |
| 964 | 964 | xhci_debugfs_remove_slot(xhci, slot_id); |
| 965 | − xhci_free_virt_device(xhci, vdev, slot_id); | |
| 965 | + xhci_free_virt_device(xhci, xhci->devs[slot_id], slot_id); | |
| 966 | 966 | } |
| 967 | 967 | |
| 968 | 968 | int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, |
| @@ -1322,7 +1322,18 @@ static const struct usb_device_id option_ids[] = { · 1321 unmodified lines | ||
| 1322 | 1322 | .driver_info = NCTRL(0) | RSVD(3) }, |
| 1323 | 1323 | { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff), /* Telit LE910C1-EUX (ECM) */ |
| 1324 | 1324 | .driver_info = NCTRL(0) }, |
| 1325 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1034, 0xff), /* Telit LE910C4-WWX (rmnet) */ | |
| 1326 | + .driver_info = RSVD(2) }, | |
| 1325 | 1327 | { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1035, 0xff) }, /* Telit LE910C4-WWX (ECM) */ |
| 1328 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1036, 0xff) }, /* Telit LE910C4-WWX */ | |
| 1329 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1037, 0xff), /* Telit LE910C4-WWX (rmnet) */ | |
| 1330 | + .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) }, | |
| 1331 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1038, 0xff), /* Telit LE910C4-WWX (rmnet) */ | |
| 1332 | + .driver_info = NCTRL(0) | RSVD(3) }, | |
| 1333 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103b, 0xff), /* Telit LE910C4-WWX */ | |
| 1334 | + .driver_info = NCTRL(0) | NCTRL(1) }, | |
| 1335 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103c, 0xff), /* Telit LE910C4-WWX */ | |
| 1336 | + .driver_info = NCTRL(0) }, | |
| 1326 | 1337 | { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), |
| 1327 | 1338 | .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, |
| 1328 | 1339 | { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1), |
| @@ -1369,6 +1380,12 @@ static const struct usb_device_id option_ids[] = { · 40 unmodified lines | ||
| 1369 | 1380 | .driver_info = NCTRL(0) | RSVD(1) }, |
| 1370 | 1381 | { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990A (PCIe) */ |
| 1371 | 1382 | .driver_info = RSVD(0) }, |
| 1383 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1077, 0xff), /* Telit FN990A (rmnet + audio) */ | |
| 1384 | + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, | |
| 1385 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1078, 0xff), /* Telit FN990A (MBIM + audio) */ | |
| 1386 | + .driver_info = NCTRL(0) | RSVD(1) }, | |
| 1387 | + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1079, 0xff), /* Telit FN990A (RNDIS + audio) */ | |
| 1388 | + .driver_info = NCTRL(2) | RSVD(3) }, | |
| 1372 | 1389 | { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990A (rmnet) */ |
| 1373 | 1390 | .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, |
| 1374 | 1391 | { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990A (MBIM) */ |
| @@ -2426,17 +2426,21 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, · 2425 unmodified lines | ||
| 2426 | 2426 | case ADEV_NONE: |
| 2427 | 2427 | break; |
| 2428 | 2428 | case ADEV_NOTIFY_USB_AND_QUEUE_VDM: |
| 2429 | − WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL)); | |
| 2430 | − typec_altmode_vdm(adev, p[0], &p[1], cnt); | |
| 2429 | + if (rx_sop_type == TCPC_TX_SOP_PRIME) { | |
| 2430 | + typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt); | |
| 2431 | + } else { | |
| 2432 | + WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL)); | |
| 2433 | + typec_altmode_vdm(adev, p[0], &p[1], cnt); | |
| 2434 | + } | |
| 2431 | 2435 | break; |
| 2432 | 2436 | case ADEV_QUEUE_VDM: |
| 2433 | − if (response_tx_sop_type == TCPC_TX_SOP_PRIME) | |
| 2437 | + if (rx_sop_type == TCPC_TX_SOP_PRIME) | |
| 2434 | 2438 | typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt); |
| 2435 | 2439 | else |
| 2436 | 2440 | typec_altmode_vdm(adev, p[0], &p[1], cnt); |
| 2437 | 2441 | break; |
| 2438 | 2442 | case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL: |
| 2439 | − if (response_tx_sop_type == TCPC_TX_SOP_PRIME) { | |
| 2443 | + if (rx_sop_type == TCPC_TX_SOP_PRIME) { | |
| 2440 | 2444 | if (typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, |
| 2441 | 2445 | p[0], &p[1], cnt)) { |
| 2442 | 2446 | int svdm_version = typec_get_cable_svdm_version( |
| @@ -1795,7 +1795,14 @@ static int reclaim_bgs_cmp(void *unused, const struct list_head *a, · 1794 unmodified lines | ||
| 1795 | 1795 | bg1 = list_entry(a, struct btrfs_block_group, bg_list); |
| 1796 | 1796 | bg2 = list_entry(b, struct btrfs_block_group, bg_list); |
| 1797 | 1797 | |
| 1798 | − return bg1->used > bg2->used; | |
| 1798 | + /* | |
| 1799 | + * Some other task may be updating the ->used field concurrently, but it | |
| 1800 | + * is not serious if we get a stale value or load/store tearing issues, | |
| 1801 | + * as sorting the list of block groups to reclaim is not critical and an | |
| 1802 | + * occasional imperfect order is ok. So silence KCSAN and avoid the | |
| 1803 | + * overhead of locking or any other synchronization. | |
| 1804 | + */ | |
| 1805 | + return data_race(bg1->used > bg2->used); | |
| 1799 | 1806 | } |
| 1800 | 1807 | |
| 1801 | 1808 | static inline bool btrfs_should_reclaim(const struct btrfs_fs_info *fs_info) |
| @@ -1843,7 +1843,6 @@ static void fill_stack_inode_item(struct btrfs_trans_handle *trans, · 1842 unmodified lines | ||
| 1843 | 1843 | |
| 1844 | 1844 | int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev) |
| 1845 | 1845 | { |
| 1846 | − struct btrfs_fs_info *fs_info = inode->root->fs_info; | |
| 1847 | 1846 | struct btrfs_delayed_node *delayed_node; |
| 1848 | 1847 | struct btrfs_inode_item *inode_item; |
| 1849 | 1848 | struct inode *vfs_inode = &inode->vfs_inode; |
| @@ -1864,8 +1863,6 @@ int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev) · 14 unmodified lines | ||
| 1864 | 1863 | i_uid_write(vfs_inode, btrfs_stack_inode_uid(inode_item)); |
| 1865 | 1864 | i_gid_write(vfs_inode, btrfs_stack_inode_gid(inode_item)); |
| 1866 | 1865 | btrfs_i_size_write(inode, btrfs_stack_inode_size(inode_item)); |
| 1867 | − btrfs_inode_set_file_extent_range(inode, 0, | |
| 1868 | − round_up(i_size_read(vfs_inode), fs_info->sectorsize)); | |
| 1869 | 1866 | vfs_inode->i_mode = btrfs_stack_inode_mode(inode_item); |
| 1870 | 1867 | set_nlink(vfs_inode, btrfs_stack_inode_nlink(inode_item)); |
| 1871 | 1868 | inode_set_bytes(vfs_inode, btrfs_stack_inode_nbytes(inode_item)); |
| @@ -3885,10 +3885,6 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path · 3884 unmodified lines | ||
| 3885 | 3885 | bool filled = false; |
| 3886 | 3886 | int first_xattr_slot; |
| 3887 | 3887 | |
| 3888 | − ret = btrfs_init_file_extent_tree(inode); | |
| 3889 | − if (ret) | |
| 3890 | − goto out; | |
| 3891 | − | |
| 3892 | 3888 | ret = btrfs_fill_inode(inode, &rdev); |
| 3893 | 3889 | if (!ret) |
| 3894 | 3890 | filled = true; |
| @@ -3920,8 +3916,6 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path · 25 unmodified lines | ||
| 3920 | 3916 | i_uid_write(vfs_inode, btrfs_inode_uid(leaf, inode_item)); |
| 3921 | 3917 | i_gid_write(vfs_inode, btrfs_inode_gid(leaf, inode_item)); |
| 3922 | 3918 | btrfs_i_size_write(inode, btrfs_inode_size(leaf, inode_item)); |
| 3923 | − btrfs_inode_set_file_extent_range(inode, 0, | |
| 3924 | − round_up(i_size_read(vfs_inode), fs_info->sectorsize)); | |
| 3925 | 3919 | |
| 3926 | 3920 | inode_set_atime(vfs_inode, btrfs_timespec_sec(leaf, &inode_item->atime), |
| 3927 | 3921 | btrfs_timespec_nsec(leaf, &inode_item->atime)); |
| @@ -3953,6 +3947,11 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path · 25 unmodified lines | ||
| 3953 | 3947 | btrfs_set_inode_mapping_order(inode); |
| 3954 | 3948 | |
| 3955 | 3949 | cache_index: |
| 3950 | + ret = btrfs_init_file_extent_tree(inode); | |
| 3951 | + if (ret) | |
| 3952 | + goto out; | |
| 3953 | + btrfs_inode_set_file_extent_range(inode, 0, | |
| 3954 | + round_up(i_size_read(vfs_inode), fs_info->sectorsize)); | |
| 3956 | 3955 | /* |
| 3957 | 3956 | * If we were modified in the current generation and evicted from memory |
| 3958 | 3957 | * and then re-read we need to do a full sync since we don't have any |
| @@ -1964,7 +1964,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, · 1963 unmodified lines | ||
| 1964 | 1964 | |
| 1965 | 1965 | search_key.objectid = log_key.objectid; |
| 1966 | 1966 | search_key.type = BTRFS_INODE_EXTREF_KEY; |
| 1967 | − search_key.offset = key->objectid; | |
| 1967 | + search_key.offset = btrfs_extref_hash(key->objectid, name.name, name.len); | |
| 1968 | 1968 | ret = backref_in_log(root->log_root, &search_key, key->objectid, &name); |
| 1969 | 1969 | if (ret < 0) { |
| 1970 | 1970 | goto out; |
| @@ -2582,9 +2582,9 @@ again: · 2581 unmodified lines | ||
| 2582 | 2582 | spin_lock(&space_info->lock); |
| 2583 | 2583 | space_info->total_bytes -= bg->length; |
| 2584 | 2584 | space_info->disk_total -= bg->length * factor; |
| 2585 | + space_info->disk_total -= bg->zone_unusable; | |
| 2585 | 2586 | /* There is no allocation ever happened. */ |
| 2586 | 2587 | ASSERT(bg->used == 0); |
| 2587 | − ASSERT(bg->zone_unusable == 0); | |
| 2588 | 2588 | /* No super block in a block group on the zoned setup. */ |
| 2589 | 2589 | ASSERT(bg->bytes_super == 0); |
| 2590 | 2590 | spin_unlock(&space_info->lock); |
| @@ -1264,7 +1264,9 @@ static inline int move_dirty_folio_in_page_array(struct address_space *mapping, · 1263 unmodified lines | ||
| 1264 | 1264 | 0, |
| 1265 | 1265 | gfp_flags); |
| 1266 | 1266 | if (IS_ERR(pages[index])) { |
| 1267 | − if (PTR_ERR(pages[index]) == -EINVAL) { | |
| 1267 | + int err = PTR_ERR(pages[index]); | |
| 1268 | + | |
| 1269 | + if (err == -EINVAL) { | |
| 1268 | 1270 | pr_err_client(cl, "inode->i_blkbits=%hhu\n", |
| 1269 | 1271 | inode->i_blkbits); |
| 1270 | 1272 | } |
| @@ -1273,7 +1275,7 @@ static inline int move_dirty_folio_in_page_array(struct address_space *mapping, · 2 unmodified lines | ||
| 1273 | 1275 | BUG_ON(ceph_wbc->locked_pages == 0); |
| 1274 | 1276 | |
| 1275 | 1277 | pages[index] = NULL; |
| 1276 | − return PTR_ERR(pages[index]); | |
| 1278 | + return err; | |
| 1277 | 1279 | } |
| 1278 | 1280 | } else { |
| 1279 | 1281 | pages[index] = &folio->page; |
| @@ -1687,6 +1689,7 @@ get_more_pages: · 407 unmodified lines | ||
| 1687 | 1689 | |
| 1688 | 1690 | process_folio_batch: |
| 1689 | 1691 | rc = ceph_process_folio_batch(mapping, wbc, &ceph_wbc); |
| 1692 | + ceph_shift_unused_folios_left(&ceph_wbc.fbatch); | |
| 1690 | 1693 | if (rc) |
| 1691 | 1694 | goto release_folios; |
| 1692 | 1695 | |
| @@ -1695,8 +1698,6 @@ process_folio_batch: · 2 unmodified lines | ||
| 1695 | 1698 | goto release_folios; |
| 1696 | 1699 | |
| 1697 | 1700 | if (ceph_wbc.processed_in_fbatch) { |
| 1698 | − ceph_shift_unused_folios_left(&ceph_wbc.fbatch); | |
| 1699 | − | |
| 1700 | 1701 | if (folio_batch_count(&ceph_wbc.fbatch) == 0 && |
| 1701 | 1702 | ceph_wbc.locked_pages < ceph_wbc.max_pages) { |
| 1702 | 1703 | doutc(cl, "reached end fbatch, trying for more\n"); |
| @@ -55,8 +55,6 @@ static int mdsc_show(struct seq_file *s, void *p) · 54 unmodified lines | ||
| 55 | 55 | struct ceph_mds_client *mdsc = fsc->mdsc; |
| 56 | 56 | struct ceph_mds_request *req; |
| 57 | 57 | struct rb_node *rp; |
| 58 | − int pathlen = 0; | |
| 59 | − u64 pathbase; | |
| 60 | 58 | char *path; |
| 61 | 59 | |
| 62 | 60 | mutex_lock(&mdsc->mutex); |
| @@ -81,8 +79,8 @@ static int mdsc_show(struct seq_file *s, void *p) · 18 unmodified lines | ||
| 81 | 79 | if (req->r_inode) { |
| 82 | 80 | seq_printf(s, " #%llx", ceph_ino(req->r_inode)); |
| 83 | 81 | } else if (req->r_dentry) { |
| 84 | − path = ceph_mdsc_build_path(mdsc, req->r_dentry, &pathlen, | |
| 85 | − &pathbase, 0); | |
| 82 | + struct ceph_path_info path_info; | |
| 83 | + path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0); | |
| 86 | 84 | if (IS_ERR(path)) |
| 87 | 85 | path = NULL; |
| 88 | 86 | spin_lock(&req->r_dentry->d_lock); |
| @@ -91,7 +89,7 @@ static int mdsc_show(struct seq_file *s, void *p) · 2 unmodified lines | ||
| 91 | 89 | req->r_dentry, |
| 92 | 90 | path ? path : ""); |
| 93 | 91 | spin_unlock(&req->r_dentry->d_lock); |
| 94 | − ceph_mdsc_free_path(path, pathlen); | |
| 92 | + ceph_mdsc_free_path_info(&path_info); | |
| 95 | 93 | } else if (req->r_path1) { |
| 96 | 94 | seq_printf(s, " #%llx/%s", req->r_ino1.ino, |
| 97 | 95 | req->r_path1); |
| @@ -100,8 +98,8 @@ static int mdsc_show(struct seq_file *s, void *p) · 2 unmodified lines | ||
| 100 | 98 | } |
| 101 | 99 | |
| 102 | 100 | if (req->r_old_dentry) { |
| 103 | − path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &pathlen, | |
| 104 | − &pathbase, 0); | |
| 101 | + struct ceph_path_info path_info; | |
| 102 | + path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0); | |
| 105 | 103 | if (IS_ERR(path)) |
| 106 | 104 | path = NULL; |
| 107 | 105 | spin_lock(&req->r_old_dentry->d_lock); |
| @@ -111,7 +109,7 @@ static int mdsc_show(struct seq_file *s, void *p) · 3 unmodified lines | ||
| 111 | 109 | req->r_old_dentry, |
| 112 | 110 | path ? path : ""); |
| 113 | 111 | spin_unlock(&req->r_old_dentry->d_lock); |
| 114 | − ceph_mdsc_free_path(path, pathlen); | |
| 112 | + ceph_mdsc_free_path_info(&path_info); | |
| 115 | 113 | } else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) { |
| 116 | 114 | if (req->r_ino2.ino) |
| 117 | 115 | seq_printf(s, " #%llx/%s", req->r_ino2.ino, |
| @@ -1271,10 +1271,8 @@ static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc, · 1270 unmodified lines | ||
| 1271 | 1271 | |
| 1272 | 1272 | /* If op failed, mark everyone involved for errors */ |
| 1273 | 1273 | if (result) { |
| 1274 | − int pathlen = 0; | |
| 1275 | − u64 base = 0; | |
| 1276 | − char *path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, | |
| 1277 | − &base, 0); | |
| 1274 | + struct ceph_path_info path_info = {0}; | |
| 1275 | + char *path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0); | |
| 1278 | 1276 | |
| 1279 | 1277 | /* mark error on parent + clear complete */ |
| 1280 | 1278 | mapping_set_error(req->r_parent->i_mapping, result); |
| @@ -1288,8 +1286,8 @@ static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc, · 7 unmodified lines | ||
| 1288 | 1286 | mapping_set_error(req->r_old_inode->i_mapping, result); |
| 1289 | 1287 | |
| 1290 | 1288 | pr_warn_client(cl, "failure path=(%llx)%s result=%d!\n", |
| 1291 | − base, IS_ERR(path) ? "<<bad>>" : path, result); | |
| 1292 | − ceph_mdsc_free_path(path, pathlen); | |
| 1289 | + path_info.vino.ino, IS_ERR(path) ? "<<bad>>" : path, result); | |
| 1290 | + ceph_mdsc_free_path_info(&path_info); | |
| 1293 | 1291 | } |
| 1294 | 1292 | out: |
| 1295 | 1293 | iput(req->r_old_inode); |
| @@ -1347,8 +1345,6 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry) · 51 unmodified lines | ||
| 1347 | 1345 | int err = -EROFS; |
| 1348 | 1346 | int op; |
| 1349 | 1347 | char *path; |
| 1350 | − int pathlen; | |
| 1351 | − u64 pathbase; | |
| 1352 | 1348 | |
| 1353 | 1349 | if (ceph_snap(dir) == CEPH_SNAPDIR) { |
| 1354 | 1350 | /* rmdir .snap/foo is RMSNAP */ |
| @@ -1367,14 +1363,15 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry) · 12 unmodified lines | ||
| 1367 | 1363 | if (!dn) { |
| 1368 | 1364 | try_async = false; |
| 1369 | 1365 | } else { |
| 1370 | − path = ceph_mdsc_build_path(mdsc, dn, &pathlen, &pathbase, 0); | |
| 1366 | + struct ceph_path_info path_info; | |
| 1367 | + path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0); | |
| 1371 | 1368 | if (IS_ERR(path)) { |
| 1372 | 1369 | try_async = false; |
| 1373 | 1370 | err = 0; |
| 1374 | 1371 | } else { |
| 1375 | 1372 | err = ceph_mds_check_access(mdsc, path, MAY_WRITE); |
| 1376 | 1373 | } |
| 1377 | − ceph_mdsc_free_path(path, pathlen); | |
| 1374 | + ceph_mdsc_free_path_info(&path_info); | |
| 1378 | 1375 | dput(dn); |
| 1379 | 1376 | |
| 1380 | 1377 | /* For none EACCES cases will let the MDS do the mds auth check */ |
| @@ -368,8 +368,6 @@ int ceph_open(struct inode *inode, struct file *file) · 367 unmodified lines | ||
| 368 | 368 | int flags, fmode, wanted; |
| 369 | 369 | struct dentry *dentry; |
| 370 | 370 | char *path; |
| 371 | − int pathlen; | |
| 372 | − u64 pathbase; | |
| 373 | 371 | bool do_sync = false; |
| 374 | 372 | int mask = MAY_READ; |
| 375 | 373 | |
| @@ -399,14 +397,15 @@ int ceph_open(struct inode *inode, struct file *file) · 23 unmodified lines | ||
| 399 | 397 | if (!dentry) { |
| 400 | 398 | do_sync = true; |
| 401 | 399 | } else { |
| 402 | − path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0); | |
| 400 | + struct ceph_path_info path_info; | |
| 401 | + path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0); | |
| 403 | 402 | if (IS_ERR(path)) { |
| 404 | 403 | do_sync = true; |
| 405 | 404 | err = 0; |
| 406 | 405 | } else { |
| 407 | 406 | err = ceph_mds_check_access(mdsc, path, mask); |
| 408 | 407 | } |
| 409 | − ceph_mdsc_free_path(path, pathlen); | |
| 408 | + ceph_mdsc_free_path_info(&path_info); | |
| 410 | 409 | dput(dentry); |
| 411 | 410 | |
| 412 | 411 | /* For none EACCES cases will let the MDS do the mds auth check */ |
| @@ -614,15 +613,13 @@ static void ceph_async_create_cb(struct ceph_mds_client *mdsc, · 201 unmodified lines | ||
| 614 | 613 | mapping_set_error(req->r_parent->i_mapping, result); |
| 615 | 614 | |
| 616 | 615 | if (result) { |
| 617 | − int pathlen = 0; | |
| 618 | − u64 base = 0; | |
| 619 | − char *path = ceph_mdsc_build_path(mdsc, req->r_dentry, &pathlen, | |
| 620 | − &base, 0); | |
| 616 | + struct ceph_path_info path_info = {0}; | |
| 617 | + char *path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0); | |
| 621 | 618 | |
| 622 | 619 | pr_warn_client(cl, |
| 623 | 620 | "async create failure path=(%llx)%s result=%d!\n", |
| 624 | − base, IS_ERR(path) ? "<<bad>>" : path, result); | |
| 625 | − ceph_mdsc_free_path(path, pathlen); | |
| 621 | + path_info.vino.ino, IS_ERR(path) ? "<<bad>>" : path, result); | |
| 622 | + ceph_mdsc_free_path_info(&path_info); | |
| 626 | 623 | |
| 627 | 624 | ceph_dir_clear_complete(req->r_parent); |
| 628 | 625 | if (!d_unhashed(dentry)) |
| @@ -791,8 +788,6 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, · 162 unmodified lines | ||
| 791 | 788 | int mask; |
| 792 | 789 | int err; |
| 793 | 790 | char *path; |
| 794 | − int pathlen; | |
| 795 | − u64 pathbase; | |
| 796 | 791 | |
| 797 | 792 | doutc(cl, "%p %llx.%llx dentry %p '%pd' %s flags %d mode 0%o\n", |
| 798 | 793 | dir, ceph_vinop(dir), dentry, dentry, |
| @@ -814,7 +809,8 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, · 15 unmodified lines | ||
| 814 | 809 | if (!dn) { |
| 815 | 810 | try_async = false; |
| 816 | 811 | } else { |
| 817 | − path = ceph_mdsc_build_path(mdsc, dn, &pathlen, &pathbase, 0); | |
| 812 | + struct ceph_path_info path_info; | |
| 813 | + path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0); | |
| 818 | 814 | if (IS_ERR(path)) { |
| 819 | 815 | try_async = false; |
| 820 | 816 | err = 0; |
| @@ -826,7 +822,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, · 5 unmodified lines | ||
| 826 | 822 | mask |= MAY_WRITE; |
| 827 | 823 | err = ceph_mds_check_access(mdsc, path, mask); |
| 828 | 824 | } |
| 829 | − ceph_mdsc_free_path(path, pathlen); | |
| 825 | + ceph_mdsc_free_path_info(&path_info); | |
| 830 | 826 | dput(dn); |
| 831 | 827 | |
| 832 | 828 | /* For none EACCES cases will let the MDS do the mds auth check */ |
| @@ -55,6 +55,52 @@ static int ceph_set_ino_cb(struct inode *inode, void *data) · 54 unmodified lines | ||
| 55 | 55 | return 0; |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | +/* | |
| 59 | + * Check if the parent inode matches the vino from directory reply info | |
| 60 | + */ | |
| 61 | +static inline bool ceph_vino_matches_parent(struct inode *parent, | |
| 62 | + struct ceph_vino vino) | |
| 63 | +{ | |
| 64 | + return ceph_ino(parent) == vino.ino && ceph_snap(parent) == vino.snap; | |
| 65 | +} | |
| 66 | + | |
| 67 | +/* | |
| 68 | + * Validate that the directory inode referenced by @req->r_parent matches the | |
| 69 | + * inode number and snapshot id contained in the reply's directory record. If | |
| 70 | + * they do not match – which can theoretically happen if the parent dentry was | |
| 71 | + * moved between the time the request was issued and the reply arrived – fall | |
| 72 | + * back to looking up the correct inode in the inode cache. | |
| 73 | + * | |
| 74 | + * A reference is *always* returned. Callers that receive a different inode | |
| 75 | + * than the original @parent are responsible for dropping the extra reference | |
| 76 | + * once the reply has been processed. | |
| 77 | + */ | |
| 78 | +static struct inode *ceph_get_reply_dir(struct super_block *sb, | |
| 79 | + struct inode *parent, | |
| 80 | + struct ceph_mds_reply_info_parsed *rinfo) | |
| 81 | +{ | |
| 82 | + struct ceph_vino vino; | |
| 83 | + | |
| 84 | + if (unlikely(!rinfo->diri.in)) | |
| 85 | + return parent; /* nothing to compare against */ | |
| 86 | + | |
| 87 | + /* If we didn't have a cached parent inode to begin with, just bail out. */ | |
| 88 | + if (!parent) | |
| 89 | + return NULL; | |
| 90 | + | |
| 91 | + vino.ino = le64_to_cpu(rinfo->diri.in->ino); | |
| 92 | + vino.snap = le64_to_cpu(rinfo->diri.in->snapid); | |
| 93 | + | |
| 94 | + if (likely(ceph_vino_matches_parent(parent, vino))) | |
| 95 | + return parent; /* matches – use the original reference */ | |
| 96 | + | |
| 97 | + /* Mismatch – this should be rare. Emit a WARN and obtain the correct inode. */ | |
| 98 | + WARN_ONCE(1, "ceph: reply dir mismatch (parent valid %llx.%llx reply %llx.%llx)\n", | |
| 99 | + ceph_ino(parent), ceph_snap(parent), vino.ino, vino.snap); | |
| 100 | + | |
| 101 | + return ceph_get_inode(sb, vino, NULL); | |
| 102 | +} | |
| 103 | + | |
| 58 | 104 | /** |
| 59 | 105 | * ceph_new_inode - allocate a new inode in advance of an expected create |
| 60 | 106 | * @dir: parent directory for new inode |
| @@ -1523,6 +1569,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) · 1462 unmodified lines | ||
| 1523 | 1569 | struct ceph_vino tvino, dvino; |
| 1524 | 1570 | struct ceph_fs_client *fsc = ceph_sb_to_fs_client(sb); |
| 1525 | 1571 | struct ceph_client *cl = fsc->client; |
| 1572 | + struct inode *parent_dir = NULL; | |
| 1526 | 1573 | int err = 0; |
| 1527 | 1574 | |
| 1528 | 1575 | doutc(cl, "%p is_dentry %d is_target %d\n", req, |
| @@ -1536,10 +1583,17 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) · 7 unmodified lines | ||
| 1536 | 1583 | } |
| 1537 | 1584 | |
| 1538 | 1585 | if (rinfo->head->is_dentry) { |
| 1539 | − struct inode *dir = req->r_parent; | |
| 1540 | − | |
| 1541 | − if (dir) { | |
| 1542 | − err = ceph_fill_inode(dir, NULL, &rinfo->diri, | |
| 1586 | + /* | |
| 1587 | + * r_parent may be stale, in cases when R_PARENT_LOCKED is not set, | |
| 1588 | + * so we need to get the correct inode | |
| 1589 | + */ | |
| 1590 | + parent_dir = ceph_get_reply_dir(sb, req->r_parent, rinfo); | |
| 1591 | + if (unlikely(IS_ERR(parent_dir))) { | |
| 1592 | + err = PTR_ERR(parent_dir); | |
| 1593 | + goto done; | |
| 1594 | + } | |
| 1595 | + if (parent_dir) { | |
| 1596 | + err = ceph_fill_inode(parent_dir, NULL, &rinfo->diri, | |
| 1543 | 1597 | rinfo->dirfrag, session, -1, |
| 1544 | 1598 | &req->r_caps_reservation); |
| 1545 | 1599 | if (err < 0) |
| @@ -1548,14 +1602,14 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) · 2 unmodified lines | ||
| 1548 | 1602 | WARN_ON_ONCE(1); |
| 1549 | 1603 | } |
| 1550 | 1604 | |
| 1551 | − if (dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME && | |
| 1605 | + if (parent_dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME && | |
| 1552 | 1606 | test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) && |
| 1553 | 1607 | !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) { |
| 1554 | 1608 | bool is_nokey = false; |
| 1555 | 1609 | struct qstr dname; |
| 1556 | 1610 | struct dentry *dn, *parent; |
| 1557 | 1611 | struct fscrypt_str oname = FSTR_INIT(NULL, 0); |
| 1558 | − struct ceph_fname fname = { .dir = dir, | |
| 1612 | + struct ceph_fname fname = { .dir = parent_dir, | |
| 1559 | 1613 | .name = rinfo->dname, |
| 1560 | 1614 | .ctext = rinfo->altname, |
| 1561 | 1615 | .name_len = rinfo->dname_len, |
| @@ -1564,10 +1618,10 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) · 2 unmodified lines | ||
| 1564 | 1618 | BUG_ON(!rinfo->head->is_target); |
| 1565 | 1619 | BUG_ON(req->r_dentry); |
| 1566 | 1620 | |
| 1567 | − parent = d_find_any_alias(dir); | |
| 1621 | + parent = d_find_any_alias(parent_dir); | |
| 1568 | 1622 | BUG_ON(!parent); |
| 1569 | 1623 | |
| 1570 | − err = ceph_fname_alloc_buffer(dir, &oname); | |
| 1624 | + err = ceph_fname_alloc_buffer(parent_dir, &oname); | |
| 1571 | 1625 | if (err < 0) { |
| 1572 | 1626 | dput(parent); |
| 1573 | 1627 | goto done; |
| @@ -1576,7 +1630,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req) · 2 unmodified lines | ||
| 1576 | 1630 | err = ceph_fname_to_usr(&fname, NULL, &oname, &is_nokey); |
| 1577 | 1631 | if (err < 0) { |
| 1578 | 1632 | dput(parent); |
| 1579 | − ceph_fname_free_buffer(dir, &oname); | |
| 1633 | + ceph_fname_free_buffer(parent_dir, &oname); | |
| 1580 | 1634 | goto done; |
| 1581 | 1635 | } |
| 1582 | 1636 | dname.name = oname.name; |
| @@ -1595,7 +1649,7 @@ retry_lookup: · 12 unmodified lines | ||
| 1595 | 1649 | dname.len, dname.name, dn); |
| 1596 | 1650 | if (!dn) { |
| 1597 | 1651 | dput(parent); |
| 1598 | − ceph_fname_free_buffer(dir, &oname); | |
| 1652 | + ceph_fname_free_buffer(parent_dir, &oname); | |
| 1599 | 1653 | err = -ENOMEM; |
| 1600 | 1654 | goto done; |
| 1601 | 1655 | } |
| @@ -1610,12 +1664,12 @@ retry_lookup: · 8 unmodified lines | ||
| 1610 | 1664 | ceph_snap(d_inode(dn)) != tvino.snap)) { |
| 1611 | 1665 | doutc(cl, " dn %p points to wrong inode %p\n", |
| 1612 | 1666 | dn, d_inode(dn)); |
| 1613 | − ceph_dir_clear_ordered(dir); | |
| 1667 | + ceph_dir_clear_ordered(parent_dir); | |
| 1614 | 1668 | d_delete(dn); |
| 1615 | 1669 | dput(dn); |
| 1616 | 1670 | goto retry_lookup; |
| 1617 | 1671 | } |
| 1618 | − ceph_fname_free_buffer(dir, &oname); | |
| 1672 | + ceph_fname_free_buffer(parent_dir, &oname); | |
| 1619 | 1673 | |
| 1620 | 1674 | req->r_dentry = dn; |
| 1621 | 1675 | dput(parent); |
| @@ -1794,6 +1848,9 @@ retry_lookup: · 172 unmodified lines | ||
| 1794 | 1848 | &dvino, ptvino); |
| 1795 | 1849 | } |
| 1796 | 1850 | done: |
| 1851 | + /* Drop extra ref from ceph_get_reply_dir() if it returned a new inode */ | |
| 1852 | + if (unlikely(!IS_ERR_OR_NULL(parent_dir) && parent_dir != req->r_parent)) | |
| 1853 | + iput(parent_dir); | |
| 1797 | 1854 | doutc(cl, "done err=%d\n", err); |
| 1798 | 1855 | return err; |
| 1799 | 1856 | } |
| @@ -2487,22 +2544,21 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode, · 687 unmodified lines | ||
| 2487 | 2544 | int truncate_retry = 20; /* The RMW will take around 50ms */ |
| 2488 | 2545 | struct dentry *dentry; |
| 2489 | 2546 | char *path; |
| 2490 | − int pathlen; | |
| 2491 | − u64 pathbase; | |
| 2492 | 2547 | bool do_sync = false; |
| 2493 | 2548 | |
| 2494 | 2549 | dentry = d_find_alias(inode); |
| 2495 | 2550 | if (!dentry) { |
| 2496 | 2551 | do_sync = true; |
| 2497 | 2552 | } else { |
| 2498 | − path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0); | |
| 2553 | + struct ceph_path_info path_info; | |
| 2554 | + path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0); | |
| 2499 | 2555 | if (IS_ERR(path)) { |
| 2500 | 2556 | do_sync = true; |
| 2501 | 2557 | err = 0; |
| 2502 | 2558 | } else { |
| 2503 | 2559 | err = ceph_mds_check_access(mdsc, path, MAY_WRITE); |
| 2504 | 2560 | } |
| 2505 | − ceph_mdsc_free_path(path, pathlen); | |
| 2561 | + ceph_mdsc_free_path_info(&path_info); | |
| 2506 | 2562 | dput(dentry); |
| 2507 | 2563 | |
| 2508 | 2564 | /* For none EACCES cases will let the MDS do the mds auth check */ |
| @@ -2681,8 +2681,7 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen) · 2680 unmodified lines | ||
| 2681 | 2681 | * ceph_mdsc_build_path - build a path string to a given dentry |
| 2682 | 2682 | * @mdsc: mds client |
| 2683 | 2683 | * @dentry: dentry to which path should be built |
| 2684 | − * @plen: returned length of string | |
| 2685 | − * @pbase: returned base inode number | |
| 2684 | + * @path_info: output path, length, base ino+snap, and freepath ownership flag | |
| 2686 | 2685 | * @for_wire: is this path going to be sent to the MDS? |
| 2687 | 2686 | * |
| 2688 | 2687 | * Build a string that represents the path to the dentry. This is mostly called |
| @@ -2700,7 +2699,7 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen) · 11 unmodified lines | ||
| 2700 | 2699 | * foo/.snap/bar -> foo//bar |
| 2701 | 2700 | */ |
| 2702 | 2701 | char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry, |
| 2703 | − int *plen, u64 *pbase, int for_wire) | |
| 2702 | + struct ceph_path_info *path_info, int for_wire) | |
| 2704 | 2703 | { |
| 2705 | 2704 | struct ceph_client *cl = mdsc->fsc->client; |
| 2706 | 2705 | struct dentry *cur; |
| @@ -2810,16 +2809,28 @@ retry: · 103 unmodified lines | ||
| 2810 | 2809 | return ERR_PTR(-ENAMETOOLONG); |
| 2811 | 2810 | } |
| 2812 | 2811 | |
| 2813 | − *pbase = base; | |
| 2814 | − *plen = PATH_MAX - 1 - pos; | |
| 2812 | + /* Initialize the output structure */ | |
| 2813 | + memset(path_info, 0, sizeof(*path_info)); | |
| 2814 | + | |
| 2815 | + path_info->vino.ino = base; | |
| 2816 | + path_info->pathlen = PATH_MAX - 1 - pos; | |
| 2817 | + path_info->path = path + pos; | |
| 2818 | + path_info->freepath = true; | |
| 2819 | + | |
| 2820 | + /* Set snap from dentry if available */ | |
| 2821 | + if (d_inode(dentry)) | |
| 2822 | + path_info->vino.snap = ceph_snap(d_inode(dentry)); | |
| 2823 | + else | |
| 2824 | + path_info->vino.snap = CEPH_NOSNAP; | |
| 2825 | + | |
| 2815 | 2826 | doutc(cl, "on %p %d built %llx '%.*s'\n", dentry, d_count(dentry), |
| 2816 | − base, *plen, path + pos); | |
| 2827 | + base, PATH_MAX - 1 - pos, path + pos); | |
| 2817 | 2828 | return path + pos; |
| 2818 | 2829 | } |
| 2819 | 2830 | |
| 2820 | 2831 | static int build_dentry_path(struct ceph_mds_client *mdsc, struct dentry *dentry, |
| 2821 | − struct inode *dir, const char **ppath, int *ppathlen, | |
| 2822 | − u64 *pino, bool *pfreepath, bool parent_locked) | |
| 2832 | + struct inode *dir, struct ceph_path_info *path_info, | |
| 2833 | + bool parent_locked) | |
| 2823 | 2834 | { |
| 2824 | 2835 | char *path; |
| 2825 | 2836 | |
| @@ -2828,41 +2839,47 @@ static int build_dentry_path(struct ceph_mds_client *mdsc, struct dentry *dentry · 2 unmodified lines | ||
| 2828 | 2839 | dir = d_inode_rcu(dentry->d_parent); |
| 2829 | 2840 | if (dir && parent_locked && ceph_snap(dir) == CEPH_NOSNAP && |
| 2830 | 2841 | !IS_ENCRYPTED(dir)) { |
| 2831 | − *pino = ceph_ino(dir); | |
| 2842 | + path_info->vino.ino = ceph_ino(dir); | |
| 2843 | + path_info->vino.snap = ceph_snap(dir); | |
| 2832 | 2844 | rcu_read_unlock(); |
| 2833 | − *ppath = dentry->d_name.name; | |
| 2834 | − *ppathlen = dentry->d_name.len; | |
| 2845 | + path_info->path = dentry->d_name.name; | |
| 2846 | + path_info->pathlen = dentry->d_name.len; | |
| 2847 | + path_info->freepath = false; | |
| 2835 | 2848 | return 0; |
| 2836 | 2849 | } |
| 2837 | 2850 | rcu_read_unlock(); |
| 2838 | − path = ceph_mdsc_build_path(mdsc, dentry, ppathlen, pino, 1); | |
| 2851 | + path = ceph_mdsc_build_path(mdsc, dentry, path_info, 1); | |
| 2839 | 2852 | if (IS_ERR(path)) |
| 2840 | 2853 | return PTR_ERR(path); |
| 2841 | − *ppath = path; | |
| 2842 | − *pfreepath = true; | |
| 2854 | + /* | |
| 2855 | + * ceph_mdsc_build_path already fills path_info, including snap handling. | |
| 2856 | + */ | |
| 2843 | 2857 | return 0; |
| 2844 | 2858 | } |
| 2845 | 2859 | |
| 2846 | −static int build_inode_path(struct inode *inode, | |
| 2847 | − const char **ppath, int *ppathlen, u64 *pino, | |
| 2848 | − bool *pfreepath) | |
| 2860 | +static int build_inode_path(struct inode *inode, struct ceph_path_info *path_info) | |
| 2849 | 2861 | { |
| 2850 | 2862 | struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb); |
| 2851 | 2863 | struct dentry *dentry; |
| 2852 | 2864 | char *path; |
| 2853 | 2865 | |
| 2854 | 2866 | if (ceph_snap(inode) == CEPH_NOSNAP) { |
| 2855 | − *pino = ceph_ino(inode); | |
| 2856 | − *ppathlen = 0; | |
| 2867 | + path_info->vino.ino = ceph_ino(inode); | |
| 2868 | + path_info->vino.snap = ceph_snap(inode); | |
| 2869 | + path_info->pathlen = 0; | |
| 2870 | + path_info->freepath = false; | |
| 2857 | 2871 | return 0; |
| 2858 | 2872 | } |
| 2859 | 2873 | dentry = d_find_alias(inode); |
| 2860 | − path = ceph_mdsc_build_path(mdsc, dentry, ppathlen, pino, 1); | |
| 2874 | + path = ceph_mdsc_build_path(mdsc, dentry, path_info, 1); | |
| 2861 | 2875 | dput(dentry); |
| 2862 | 2876 | if (IS_ERR(path)) |
| 2863 | 2877 | return PTR_ERR(path); |
| 2864 | − *ppath = path; | |
| 2865 | − *pfreepath = true; | |
| 2878 | + /* | |
| 2879 | + * ceph_mdsc_build_path already fills path_info, including snap from dentry. | |
| 2880 | + * Override with inode's snap since that's what this function is for. | |
| 2881 | + */ | |
| 2882 | + path_info->vino.snap = ceph_snap(inode); | |
| 2866 | 2883 | return 0; |
| 2867 | 2884 | } |
| 2868 | 2885 | |
| @@ -2872,26 +2889,32 @@ static int build_inode_path(struct inode *inode, · 3 unmodified lines | ||
| 2872 | 2889 | */ |
| 2873 | 2890 | static int set_request_path_attr(struct ceph_mds_client *mdsc, struct inode *rinode, |
| 2874 | 2891 | struct dentry *rdentry, struct inode *rdiri, |
| 2875 | − const char *rpath, u64 rino, const char **ppath, | |
| 2876 | − int *pathlen, u64 *ino, bool *freepath, | |
| 2892 | + const char *rpath, u64 rino, | |
| 2893 | + struct ceph_path_info *path_info, | |
| 2877 | 2894 | bool parent_locked) |
| 2878 | 2895 | { |
| 2879 | 2896 | struct ceph_client *cl = mdsc->fsc->client; |
| 2880 | 2897 | int r = 0; |
| 2881 | 2898 | |
| 2899 | + /* Initialize the output structure */ | |
| 2900 | + memset(path_info, 0, sizeof(*path_info)); | |
| 2901 | + | |
| 2882 | 2902 | if (rinode) { |
| 2883 | − r = build_inode_path(rinode, ppath, pathlen, ino, freepath); | |
| 2903 | + r = build_inode_path(rinode, path_info); | |
| 2884 | 2904 | doutc(cl, " inode %p %llx.%llx\n", rinode, ceph_ino(rinode), |
| 2885 | 2905 | ceph_snap(rinode)); |
| 2886 | 2906 | } else if (rdentry) { |
| 2887 | − r = build_dentry_path(mdsc, rdentry, rdiri, ppath, pathlen, ino, | |
| 2888 | − freepath, parent_locked); | |
| 2889 | − doutc(cl, " dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen, *ppath); | |
| 2907 | + r = build_dentry_path(mdsc, rdentry, rdiri, path_info, parent_locked); | |
| 2908 | + doutc(cl, " dentry %p %llx/%.*s\n", rdentry, path_info->vino.ino, | |
| 2909 | + path_info->pathlen, path_info->path); | |
| 2890 | 2910 | } else if (rpath || rino) { |
| 2891 | − *ino = rino; | |
| 2892 | − *ppath = rpath; | |
| 2893 | − *pathlen = rpath ? strlen(rpath) : 0; | |
| 2894 | − doutc(cl, " path %.*s\n", *pathlen, rpath); | |
| 2911 | + path_info->vino.ino = rino; | |
| 2912 | + path_info->vino.snap = CEPH_NOSNAP; | |
| 2913 | + path_info->path = rpath; | |
| 2914 | + path_info->pathlen = rpath ? strlen(rpath) : 0; | |
| 2915 | + path_info->freepath = false; | |
| 2916 | + | |
| 2917 | + doutc(cl, " path %.*s\n", path_info->pathlen, rpath); | |
| 2895 | 2918 | } |
| 2896 | 2919 | |
| 2897 | 2920 | return r; |
| @@ -2968,11 +2991,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 70 unmodified lines | ||
| 2968 | 2991 | struct ceph_client *cl = mdsc->fsc->client; |
| 2969 | 2992 | struct ceph_msg *msg; |
| 2970 | 2993 | struct ceph_mds_request_head_legacy *lhead; |
| 2971 | − const char *path1 = NULL; | |
| 2972 | − const char *path2 = NULL; | |
| 2973 | − u64 ino1 = 0, ino2 = 0; | |
| 2974 | − int pathlen1 = 0, pathlen2 = 0; | |
| 2975 | − bool freepath1 = false, freepath2 = false; | |
| 2994 | + struct ceph_path_info path_info1 = {0}; | |
| 2995 | + struct ceph_path_info path_info2 = {0}; | |
| 2976 | 2996 | struct dentry *old_dentry = NULL; |
| 2977 | 2997 | int len; |
| 2978 | 2998 | u16 releases; |
| @@ -2982,25 +3002,49 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 3 unmodified lines | ||
| 2982 | 3002 | u16 request_head_version = mds_supported_head_version(session); |
| 2983 | 3003 | kuid_t caller_fsuid = req->r_cred->fsuid; |
| 2984 | 3004 | kgid_t caller_fsgid = req->r_cred->fsgid; |
| 3005 | + bool parent_locked = test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); | |
| 2985 | 3006 | |
| 2986 | 3007 | ret = set_request_path_attr(mdsc, req->r_inode, req->r_dentry, |
| 2987 | − req->r_parent, req->r_path1, req->r_ino1.ino, | |
| 2988 | − &path1, &pathlen1, &ino1, &freepath1, | |
| 2989 | − test_bit(CEPH_MDS_R_PARENT_LOCKED, | |
| 2990 | − &req->r_req_flags)); | |
| 3008 | + req->r_parent, req->r_path1, req->r_ino1.ino, | |
| 3009 | + &path_info1, parent_locked); | |
| 2991 | 3010 | if (ret < 0) { |
| 2992 | 3011 | msg = ERR_PTR(ret); |
| 2993 | 3012 | goto out; |
| 2994 | 3013 | } |
| 2995 | 3014 | |
| 3015 | + /* | |
| 3016 | + * When the parent directory's i_rwsem is *not* locked, req->r_parent may | |
| 3017 | + * have become stale (e.g. after a concurrent rename) between the time the | |
| 3018 | + * dentry was looked up and now. If we detect that the stored r_parent | |
| 3019 | + * does not match the inode number we just encoded for the request, switch | |
| 3020 | + * to the correct inode so that the MDS receives a valid parent reference. | |
| 3021 | + */ | |
| 3022 | + if (!parent_locked && req->r_parent && path_info1.vino.ino && | |
| 3023 | + ceph_ino(req->r_parent) != path_info1.vino.ino) { | |
| 3024 | + struct inode *old_parent = req->r_parent; | |
| 3025 | + struct inode *correct_dir = ceph_get_inode(mdsc->fsc->sb, path_info1.vino, NULL); | |
| 3026 | + if (!IS_ERR(correct_dir)) { | |
| 3027 | + WARN_ONCE(1, "ceph: r_parent mismatch (had %llx wanted %llx) - updating\n", | |
| 3028 | + ceph_ino(old_parent), path_info1.vino.ino); | |
| 3029 | + /* | |
| 3030 | + * Transfer CEPH_CAP_PIN from the old parent to the new one. | |
| 3031 | + * The pin was taken earlier in ceph_mdsc_submit_request(). | |
| 3032 | + */ | |
| 3033 | + ceph_put_cap_refs(ceph_inode(old_parent), CEPH_CAP_PIN); | |
| 3034 | + iput(old_parent); | |
| 3035 | + req->r_parent = correct_dir; | |
| 3036 | + ceph_get_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN); | |
| 3037 | + } | |
| 3038 | + } | |
| 3039 | + | |
| 2996 | 3040 | /* If r_old_dentry is set, then assume that its parent is locked */ |
| 2997 | 3041 | if (req->r_old_dentry && |
| 2998 | 3042 | !(req->r_old_dentry->d_flags & DCACHE_DISCONNECTED)) |
| 2999 | 3043 | old_dentry = req->r_old_dentry; |
| 3000 | 3044 | ret = set_request_path_attr(mdsc, NULL, old_dentry, |
| 3001 | − req->r_old_dentry_dir, | |
| 3002 | − req->r_path2, req->r_ino2.ino, | |
| 3003 | − &path2, &pathlen2, &ino2, &freepath2, true); | |
| 3045 | + req->r_old_dentry_dir, | |
| 3046 | + req->r_path2, req->r_ino2.ino, | |
| 3047 | + &path_info2, true); | |
| 3004 | 3048 | if (ret < 0) { |
| 3005 | 3049 | msg = ERR_PTR(ret); |
| 3006 | 3050 | goto out_free1; |
| @@ -3031,7 +3075,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 24 unmodified lines | ||
| 3031 | 3075 | |
| 3032 | 3076 | /* filepaths */ |
| 3033 | 3077 | len += 2 * (1 + sizeof(u32) + sizeof(u64)); |
| 3034 | − len += pathlen1 + pathlen2; | |
| 3078 | + len += path_info1.pathlen + path_info2.pathlen; | |
| 3035 | 3079 | |
| 3036 | 3080 | /* cap releases */ |
| 3037 | 3081 | len += sizeof(struct ceph_mds_request_release) * |
| @@ -3039,9 +3083,9 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 1 unmodified line | ||
| 3039 | 3083 | !!req->r_old_inode_drop + !!req->r_old_dentry_drop); |
| 3040 | 3084 | |
| 3041 | 3085 | if (req->r_dentry_drop) |
| 3042 | − len += pathlen1; | |
| 3086 | + len += path_info1.pathlen; | |
| 3043 | 3087 | if (req->r_old_dentry_drop) |
| 3044 | − len += pathlen2; | |
| 3088 | + len += path_info2.pathlen; | |
| 3045 | 3089 | |
| 3046 | 3090 | /* MClientRequest tail */ |
| 3047 | 3091 | |
| @@ -3154,8 +3198,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 106 unmodified lines | ||
| 3154 | 3198 | lhead->ino = cpu_to_le64(req->r_deleg_ino); |
| 3155 | 3199 | lhead->args = req->r_args; |
| 3156 | 3200 | |
| 3157 | − ceph_encode_filepath(&p, end, ino1, path1); | |
| 3158 | − ceph_encode_filepath(&p, end, ino2, path2); | |
| 3201 | + ceph_encode_filepath(&p, end, path_info1.vino.ino, path_info1.path); | |
| 3202 | + ceph_encode_filepath(&p, end, path_info2.vino.ino, path_info2.path); | |
| 3159 | 3203 | |
| 3160 | 3204 | /* make note of release offset, in case we need to replay */ |
| 3161 | 3205 | req->r_request_release_offset = p - msg->front.iov_base; |
| @@ -3218,11 +3262,9 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session, · 56 unmodified lines | ||
| 3218 | 3262 | msg->hdr.data_off = cpu_to_le16(0); |
| 3219 | 3263 | |
| 3220 | 3264 | out_free2: |
| 3221 | − if (freepath2) | |
| 3222 | − ceph_mdsc_free_path((char *)path2, pathlen2); | |
| 3265 | + ceph_mdsc_free_path_info(&path_info2); | |
| 3223 | 3266 | out_free1: |
| 3224 | − if (freepath1) | |
| 3225 | − ceph_mdsc_free_path((char *)path1, pathlen1); | |
| 3267 | + ceph_mdsc_free_path_info(&path_info1); | |
| 3226 | 3268 | out: |
| 3227 | 3269 | return msg; |
| 3228 | 3270 | out_err: |
| @@ -4579,24 +4621,20 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg) · 1350 unmodified lines | ||
| 4579 | 4621 | struct ceph_pagelist *pagelist = recon_state->pagelist; |
| 4580 | 4622 | struct dentry *dentry; |
| 4581 | 4623 | struct ceph_cap *cap; |
| 4582 | − char *path; | |
| 4583 | − int pathlen = 0, err; | |
| 4584 | − u64 pathbase; | |
| 4624 | + struct ceph_path_info path_info = {0}; | |
| 4625 | + int err; | |
| 4585 | 4626 | u64 snap_follows; |
| 4586 | 4627 | |
| 4587 | 4628 | dentry = d_find_primary(inode); |
| 4588 | 4629 | if (dentry) { |
| 4589 | 4630 | /* set pathbase to parent dir when msg_version >= 2 */ |
| 4590 | − path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, | |
| 4631 | + char *path = ceph_mdsc_build_path(mdsc, dentry, &path_info, | |
| 4591 | 4632 | recon_state->msg_version >= 2); |
| 4592 | 4633 | dput(dentry); |
| 4593 | 4634 | if (IS_ERR(path)) { |
| 4594 | 4635 | err = PTR_ERR(path); |
| 4595 | 4636 | goto out_err; |
| 4596 | 4637 | } |
| 4597 | − } else { | |
| 4598 | − path = NULL; | |
| 4599 | − pathbase = 0; | |
| 4600 | 4638 | } |
| 4601 | 4639 | |
| 4602 | 4640 | spin_lock(&ci->i_ceph_lock); |
| @@ -4629,7 +4667,7 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg) · 26 unmodified lines | ||
| 4629 | 4667 | rec.v2.wanted = cpu_to_le32(__ceph_caps_wanted(ci)); |
| 4630 | 4668 | rec.v2.issued = cpu_to_le32(cap->issued); |
| 4631 | 4669 | rec.v2.snaprealm = cpu_to_le64(ci->i_snap_realm->ino); |
| 4632 | − rec.v2.pathbase = cpu_to_le64(pathbase); | |
| 4670 | + rec.v2.pathbase = cpu_to_le64(path_info.vino.ino); | |
| 4633 | 4671 | rec.v2.flock_len = (__force __le32) |
| 4634 | 4672 | ((ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) ? 0 : 1); |
| 4635 | 4673 | } else { |
| @@ -4644,7 +4682,7 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg) · 8 unmodified lines | ||
| 4644 | 4682 | ts = inode_get_atime(inode); |
| 4645 | 4683 | ceph_encode_timespec64(&rec.v1.atime, &ts); |
| 4646 | 4684 | rec.v1.snaprealm = cpu_to_le64(ci->i_snap_realm->ino); |
| 4647 | − rec.v1.pathbase = cpu_to_le64(pathbase); | |
| 4685 | + rec.v1.pathbase = cpu_to_le64(path_info.vino.ino); | |
| 4648 | 4686 | } |
| 4649 | 4687 | |
| 4650 | 4688 | if (list_empty(&ci->i_cap_snaps)) { |
| @@ -4706,7 +4744,7 @@ encode_again: · 55 unmodified lines | ||
| 4706 | 4744 | sizeof(struct ceph_filelock); |
| 4707 | 4745 | rec.v2.flock_len = cpu_to_le32(struct_len); |
| 4708 | 4746 | |
| 4709 | − struct_len += sizeof(u32) + pathlen + sizeof(rec.v2); | |
| 4747 | + struct_len += sizeof(u32) + path_info.pathlen + sizeof(rec.v2); | |
| 4710 | 4748 | |
| 4711 | 4749 | if (struct_v >= 2) |
| 4712 | 4750 | struct_len += sizeof(u64); /* snap_follows */ |
| @@ -4730,7 +4768,7 @@ encode_again: · 17 unmodified lines | ||
| 4730 | 4768 | ceph_pagelist_encode_8(pagelist, 1); |
| 4731 | 4769 | ceph_pagelist_encode_32(pagelist, struct_len); |
| 4732 | 4770 | } |
| 4733 | − ceph_pagelist_encode_string(pagelist, path, pathlen); | |
| 4771 | + ceph_pagelist_encode_string(pagelist, (char *)path_info.path, path_info.pathlen); | |
| 4734 | 4772 | ceph_pagelist_append(pagelist, &rec, sizeof(rec.v2)); |
| 4735 | 4773 | ceph_locks_to_pagelist(flocks, pagelist, |
| 4736 | 4774 | num_fcntl_locks, num_flock_locks); |
| @@ -4741,17 +4779,17 @@ out_freeflocks: · 4 unmodified lines | ||
| 4741 | 4779 | } else { |
| 4742 | 4780 | err = ceph_pagelist_reserve(pagelist, |
| 4743 | 4781 | sizeof(u64) + sizeof(u32) + |
| 4744 | − pathlen + sizeof(rec.v1)); | |
| 4782 | + path_info.pathlen + sizeof(rec.v1)); | |
| 4745 | 4783 | if (err) |
| 4746 | 4784 | goto out_err; |
| 4747 | 4785 | |
| 4748 | 4786 | ceph_pagelist_encode_64(pagelist, ceph_ino(inode)); |
| 4749 | − ceph_pagelist_encode_string(pagelist, path, pathlen); | |
| 4787 | + ceph_pagelist_encode_string(pagelist, (char *)path_info.path, path_info.pathlen); | |
| 4750 | 4788 | ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1)); |
| 4751 | 4789 | } |
| 4752 | 4790 | |
| 4753 | 4791 | out_err: |
| 4754 | − ceph_mdsc_free_path(path, pathlen); | |
| 4792 | + ceph_mdsc_free_path_info(&path_info); | |
| 4755 | 4793 | if (!err) |
| 4756 | 4794 | recon_state->nr_caps++; |
| 4757 | 4795 | return err; |
| @@ -617,14 +617,24 @@ extern int ceph_mds_check_access(struct ceph_mds_client *mdsc, char *tpath, · 616 unmodified lines | ||
| 617 | 617 | |
| 618 | 618 | extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc); |
| 619 | 619 | |
| 620 | −static inline void ceph_mdsc_free_path(char *path, int len) | |
| 620 | +/* | |
| 621 | + * Structure to group path-related output parameters for build_*_path functions | |
| 622 | + */ | |
| 623 | +struct ceph_path_info { | |
| 624 | + const char *path; | |
| 625 | + int pathlen; | |
| 626 | + struct ceph_vino vino; | |
| 627 | + bool freepath; | |
| 628 | +}; | |
| 629 | + | |
| 630 | +static inline void ceph_mdsc_free_path_info(const struct ceph_path_info *path_info) | |
| 621 | 631 | { |
| 622 | − if (!IS_ERR_OR_NULL(path)) | |
| 623 | − __putname(path - (PATH_MAX - 1 - len)); | |
| 632 | + if (path_info && path_info->freepath && !IS_ERR_OR_NULL(path_info->path)) | |
| 633 | + __putname((char *)path_info->path - (PATH_MAX - 1 - path_info->pathlen)); | |
| 624 | 634 | } |
| 625 | 635 | |
| 626 | 636 | extern char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, |
| 627 | − struct dentry *dentry, int *plen, u64 *base, | |
| 637 | + struct dentry *dentry, struct ceph_path_info *path_info, | |
| 628 | 638 | int for_wire); |
| 629 | 639 | |
| 630 | 640 | extern void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry); |
| @@ -12,10 +12,12 @@ · 11 unmodified lines | ||
| 12 | 12 | /* to allow for x86 boot sectors and other oddities. */ |
| 13 | 13 | #define EROFS_SUPER_OFFSET 1024 |
| 14 | 14 | |
| 15 | −#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001 | |
| 16 | −#define EROFS_FEATURE_COMPAT_MTIME 0x00000002 | |
| 17 | −#define EROFS_FEATURE_COMPAT_XATTR_FILTER 0x00000004 | |
| 15 | +#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001 | |
| 16 | +#define EROFS_FEATURE_COMPAT_MTIME 0x00000002 | |
| 17 | +#define EROFS_FEATURE_COMPAT_XATTR_FILTER 0x00000004 | |
| 18 | 18 | #define EROFS_FEATURE_COMPAT_SHARED_EA_IN_METABOX 0x00000008 |
| 19 | +#define EROFS_FEATURE_COMPAT_PLAIN_XATTR_PFX 0x00000010 | |
| 20 | + | |
| 19 | 21 | |
| 20 | 22 | /* |
| 21 | 23 | * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should |
| @@ -234,6 +234,7 @@ EROFS_FEATURE_FUNCS(metabox, incompat, INCOMPAT_METABOX) · 233 unmodified lines | ||
| 234 | 234 | EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) |
| 235 | 235 | EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER) |
| 236 | 236 | EROFS_FEATURE_FUNCS(shared_ea_in_metabox, compat, COMPAT_SHARED_EA_IN_METABOX) |
| 237 | +EROFS_FEATURE_FUNCS(plain_xattr_pfx, compat, COMPAT_PLAIN_XATTR_PFX) | |
| 237 | 238 | |
| 238 | 239 | static inline u64 erofs_nid_to_ino64(struct erofs_sb_info *sbi, erofs_nid_t nid) |
| 239 | 240 | { |
| @@ -1018,10 +1018,22 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root) · 1017 unmodified lines | ||
| 1018 | 1018 | return 0; |
| 1019 | 1019 | } |
| 1020 | 1020 | |
| 1021 | +static void erofs_evict_inode(struct inode *inode) | |
| 1022 | +{ | |
| 1023 | +#ifdef CONFIG_FS_DAX | |
| 1024 | + if (IS_DAX(inode)) | |
| 1025 | + dax_break_layout_final(inode); | |
| 1026 | +#endif | |
| 1027 | + | |
| 1028 | + truncate_inode_pages_final(&inode->i_data); | |
| 1029 | + clear_inode(inode); | |
| 1030 | +} | |
| 1031 | + | |
| 1021 | 1032 | const struct super_operations erofs_sops = { |
| 1022 | 1033 | .put_super = erofs_put_super, |
| 1023 | 1034 | .alloc_inode = erofs_alloc_inode, |
| 1024 | 1035 | .free_inode = erofs_free_inode, |
| 1036 | + .evict_inode = erofs_evict_inode, | |
| 1025 | 1037 | .statfs = erofs_statfs, |
| 1026 | 1038 | .show_options = erofs_show_options, |
| 1027 | 1039 | }; |
| @@ -482,6 +482,7 @@ int erofs_xattr_prefixes_init(struct super_block *sb) · 481 unmodified lines | ||
| 482 | 482 | erofs_off_t pos = (erofs_off_t)sbi->xattr_prefix_start << 2; |
| 483 | 483 | struct erofs_xattr_prefix_item *pfs; |
| 484 | 484 | int ret = 0, i, len; |
| 485 | + bool plain = erofs_sb_has_plain_xattr_pfx(sbi); | |
| 485 | 486 | |
| 486 | 487 | if (!sbi->xattr_prefix_count) |
| 487 | 488 | return 0; |
| @@ -490,9 +491,15 @@ int erofs_xattr_prefixes_init(struct super_block *sb) · 2 unmodified lines | ||
| 490 | 491 | if (!pfs) |
| 491 | 492 | return -ENOMEM; |
| 492 | 493 | |
| 493 | − if (sbi->packed_inode) | |
| 494 | − buf.mapping = sbi->packed_inode->i_mapping; | |
| 495 | − else | |
| 494 | + if (!plain) { | |
| 495 | + if (erofs_sb_has_metabox(sbi)) | |
| 496 | + (void)erofs_init_metabuf(&buf, sb, true); | |
| 497 | + else if (sbi->packed_inode) | |
| 498 | + buf.mapping = sbi->packed_inode->i_mapping; | |
| 499 | + else | |
| 500 | + plain = true; | |
| 501 | + } | |
| 502 | + if (plain) | |
| 496 | 503 | (void)erofs_init_metabuf(&buf, sb, false); |
| 497 | 504 | |
| 498 | 505 | for (i = 0; i < sbi->xattr_prefix_count; i++) { |
| @@ -394,10 +394,10 @@ static int z_erofs_map_blocks_fo(struct inode *inode, · 393 unmodified lines | ||
| 394 | 394 | .map = map, |
| 395 | 395 | .in_mbox = erofs_inode_in_metabox(inode), |
| 396 | 396 | }; |
| 397 | − int err = 0; | |
| 398 | − unsigned int endoff, afmt; | |
| 397 | + unsigned int endoff; | |
| 399 | 398 | unsigned long initial_lcn; |
| 400 | 399 | unsigned long long ofs, end; |
| 400 | + int err; | |
| 401 | 401 | |
| 402 | 402 | ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? inode->i_size - 1 : map->m_la; |
| 403 | 403 | if (fragment && !(flags & EROFS_GET_BLOCKS_FINDTAIL) && |
| @@ -482,20 +482,15 @@ static int z_erofs_map_blocks_fo(struct inode *inode, · 78 unmodified lines | ||
| 482 | 482 | err = -EFSCORRUPTED; |
| 483 | 483 | goto unmap_out; |
| 484 | 484 | } |
| 485 | − afmt = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER ? | |
| 486 | − Z_EROFS_COMPRESSION_INTERLACED : | |
| 487 | − Z_EROFS_COMPRESSION_SHIFTED; | |
| 485 | + if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) | |
| 486 | + map->m_algorithmformat = Z_EROFS_COMPRESSION_INTERLACED; | |
| 487 | + else | |
| 488 | + map->m_algorithmformat = Z_EROFS_COMPRESSION_SHIFTED; | |
| 489 | + } else if (m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2) { | |
| 490 | + map->m_algorithmformat = vi->z_algorithmtype[1]; | |
| 488 | 491 | } else { |
| 489 | − afmt = m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2 ? | |
| 490 | − vi->z_algorithmtype[1] : vi->z_algorithmtype[0]; | |
| 491 | − if (!(EROFS_I_SB(inode)->available_compr_algs & (1 << afmt))) { | |
| 492 | − erofs_err(sb, "inconsistent algorithmtype %u for nid %llu", | |
| 493 | − afmt, vi->nid); | |
| 494 | − err = -EFSCORRUPTED; | |
| 495 | − goto unmap_out; | |
| 496 | − } | |
| 492 | + map->m_algorithmformat = vi->z_algorithmtype[0]; | |
| 497 | 493 | } |
| 498 | − map->m_algorithmformat = afmt; | |
| 499 | 494 | |
| 500 | 495 | if ((flags & EROFS_GET_BLOCKS_FIEMAP) || |
| 501 | 496 | ((flags & EROFS_GET_BLOCKS_READMORE) && |
| @@ -626,9 +621,9 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map) · 124 unmodified lines | ||
| 626 | 621 | { |
| 627 | 622 | struct erofs_inode *const vi = EROFS_I(inode); |
| 628 | 623 | struct super_block *const sb = inode->i_sb; |
| 629 | − int err, headnr; | |
| 630 | − erofs_off_t pos; | |
| 631 | 624 | struct z_erofs_map_header *h; |
| 625 | + erofs_off_t pos; | |
| 626 | + int err = 0; | |
| 632 | 627 | |
| 633 | 628 | if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) { |
| 634 | 629 | /* |
| @@ -642,7 +637,6 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map) · 7 unmodified lines | ||
| 642 | 637 | if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_Z_BIT, TASK_KILLABLE)) |
| 643 | 638 | return -ERESTARTSYS; |
| 644 | 639 | |
| 645 | − err = 0; | |
| 646 | 640 | if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) |
| 647 | 641 | goto out_unlock; |
| 648 | 642 | |
| @@ -679,15 +673,6 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map) · 30 unmodified lines | ||
| 679 | 673 | else if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) |
| 680 | 674 | vi->z_idata_size = le16_to_cpu(h->h_idata_size); |
| 681 | 675 | |
| 682 | − headnr = 0; | |
| 683 | − if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX || | |
| 684 | − vi->z_algorithmtype[++headnr] >= Z_EROFS_COMPRESSION_MAX) { | |
| 685 | − erofs_err(sb, "unknown HEAD%u format %u for nid %llu, please upgrade kernel", | |
| 686 | − headnr + 1, vi->z_algorithmtype[headnr], vi->nid); | |
| 687 | − err = -EOPNOTSUPP; | |
| 688 | − goto out_unlock; | |
| 689 | − } | |
| 690 | − | |
| 691 | 676 | if (!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && |
| 692 | 677 | vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | |
| 693 | 678 | Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { |
| @@ -726,6 +711,30 @@ out_unlock: · 32 unmodified lines | ||
| 726 | 711 | return err; |
| 727 | 712 | } |
| 728 | 713 | |
| 714 | +static int z_erofs_map_sanity_check(struct inode *inode, | |
| 715 | + struct erofs_map_blocks *map) | |
| 716 | +{ | |
| 717 | + struct erofs_sb_info *sbi = EROFS_I_SB(inode); | |
| 718 | + | |
| 719 | + if (!(map->m_flags & EROFS_MAP_ENCODED)) | |
| 720 | + return 0; | |
| 721 | + if (unlikely(map->m_algorithmformat >= Z_EROFS_COMPRESSION_RUNTIME_MAX)) { | |
| 722 | + erofs_err(inode->i_sb, "unknown algorithm %d @ pos %llu for nid %llu, please upgrade kernel", | |
| 723 | + map->m_algorithmformat, map->m_la, EROFS_I(inode)->nid); | |
| 724 | + return -EOPNOTSUPP; | |
| 725 | + } | |
| 726 | + if (unlikely(map->m_algorithmformat < Z_EROFS_COMPRESSION_MAX && | |
| 727 | + !(sbi->available_compr_algs & (1 << map->m_algorithmformat)))) { | |
| 728 | + erofs_err(inode->i_sb, "inconsistent algorithmtype %u for nid %llu", | |
| 729 | + map->m_algorithmformat, EROFS_I(inode)->nid); | |
| 730 | + return -EFSCORRUPTED; | |
| 731 | + } | |
| 732 | + if (unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE || | |
| 733 | + map->m_llen > Z_EROFS_PCLUSTER_MAX_DSIZE)) | |
| 734 | + return -EOPNOTSUPP; | |
| 735 | + return 0; | |
| 736 | +} | |
| 737 | + | |
| 729 | 738 | int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, |
| 730 | 739 | int flags) |
| 731 | 740 | { |
| @@ -746,10 +755,8 @@ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, · 14 unmodified lines | ||
| 746 | 755 | else |
| 747 | 756 | err = z_erofs_map_blocks_fo(inode, map, flags); |
| 748 | 757 | } |
| 749 | − if (!err && (map->m_flags & EROFS_MAP_ENCODED) && | |
| 750 | − unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE || | |
| 751 | − map->m_llen > Z_EROFS_PCLUSTER_MAX_DSIZE)) | |
| 752 | − err = -EOPNOTSUPP; | |
| 758 | + if (!err) | |
| 759 | + err = z_erofs_map_sanity_check(inode, map); | |
| 753 | 760 | if (err) |
| 754 | 761 | map->m_llen = 0; |
| 755 | 762 | } |
| @@ -70,6 +70,24 @@ static struct kernfs_open_node *of_on(struct kernfs_open_file *of) · 69 unmodified lines | ||
| 70 | 70 | !list_empty(&of->list)); |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | +/* Get active reference to kernfs node for an open file */ | |
| 74 | +static struct kernfs_open_file *kernfs_get_active_of(struct kernfs_open_file *of) | |
| 75 | +{ | |
| 76 | + /* Skip if file was already released */ | |
| 77 | + if (unlikely(of->released)) | |
| 78 | + return NULL; | |
| 79 | + | |
| 80 | + if (!kernfs_get_active(of->kn)) | |
| 81 | + return NULL; | |
| 82 | + | |
| 83 | + return of; | |
| 84 | +} | |
| 85 | + | |
| 86 | +static void kernfs_put_active_of(struct kernfs_open_file *of) | |
| 87 | +{ | |
| 88 | + return kernfs_put_active(of->kn); | |
| 89 | +} | |
| 90 | + | |
| 73 | 91 | /** |
| 74 | 92 | * kernfs_deref_open_node_locked - Get kernfs_open_node corresponding to @kn |
| 75 | 93 | * |
| @@ -139,7 +157,7 @@ static void kernfs_seq_stop_active(struct seq_file *sf, void *v) · 63 unmodified lines | ||
| 139 | 157 | |
| 140 | 158 | if (ops->seq_stop) |
| 141 | 159 | ops->seq_stop(sf, v); |
| 142 | − kernfs_put_active(of->kn); | |
| 160 | + kernfs_put_active_of(of); | |
| 143 | 161 | } |
| 144 | 162 | |
| 145 | 163 | static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) |
| @@ -152,7 +170,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) · 6 unmodified lines | ||
| 152 | 170 | * the ops aren't called concurrently for the same open file. |
| 153 | 171 | */ |
| 154 | 172 | mutex_lock(&of->mutex); |
| 155 | − if (!kernfs_get_active(of->kn)) | |
| 173 | + if (!kernfs_get_active_of(of)) | |
| 156 | 174 | return ERR_PTR(-ENODEV); |
| 157 | 175 | |
| 158 | 176 | ops = kernfs_ops(of->kn); |
| @@ -238,7 +256,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) · 79 unmodified lines | ||
| 238 | 256 | * the ops aren't called concurrently for the same open file. |
| 239 | 257 | */ |
| 240 | 258 | mutex_lock(&of->mutex); |
| 241 | − if (!kernfs_get_active(of->kn)) { | |
| 259 | + if (!kernfs_get_active_of(of)) { | |
| 242 | 260 | len = -ENODEV; |
| 243 | 261 | mutex_unlock(&of->mutex); |
| 244 | 262 | goto out_free; |
| @@ -252,7 +270,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) · 7 unmodified lines | ||
| 252 | 270 | else |
| 253 | 271 | len = -EINVAL; |
| 254 | 272 | |
| 255 | − kernfs_put_active(of->kn); | |
| 273 | + kernfs_put_active_of(of); | |
| 256 | 274 | mutex_unlock(&of->mutex); |
| 257 | 275 | |
| 258 | 276 | if (len < 0) |
| @@ -323,7 +341,7 @@ static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter) · 64 unmodified lines | ||
| 323 | 341 | * the ops aren't called concurrently for the same open file. |
| 324 | 342 | */ |
| 325 | 343 | mutex_lock(&of->mutex); |
| 326 | − if (!kernfs_get_active(of->kn)) { | |
| 344 | + if (!kernfs_get_active_of(of)) { | |
| 327 | 345 | mutex_unlock(&of->mutex); |
| 328 | 346 | len = -ENODEV; |
| 329 | 347 | goto out_free; |
| @@ -335,7 +353,7 @@ static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter) · 5 unmodified lines | ||
| 335 | 353 | else |
| 336 | 354 | len = -EINVAL; |
| 337 | 355 | |
| 338 | − kernfs_put_active(of->kn); | |
| 356 | + kernfs_put_active_of(of); | |
| 339 | 357 | mutex_unlock(&of->mutex); |
| 340 | 358 | |
| 341 | 359 | if (len > 0) |
| @@ -357,13 +375,13 @@ static void kernfs_vma_open(struct vm_area_struct *vma) · 15 unmodified lines | ||
| 357 | 375 | if (!of->vm_ops) |
| 358 | 376 | return; |
| 359 | 377 | |
| 360 | − if (!kernfs_get_active(of->kn)) | |
| 378 | + if (!kernfs_get_active_of(of)) | |
| 361 | 379 | return; |
| 362 | 380 | |
| 363 | 381 | if (of->vm_ops->open) |
| 364 | 382 | of->vm_ops->open(vma); |
| 365 | 383 | |
| 366 | − kernfs_put_active(of->kn); | |
| 384 | + kernfs_put_active_of(of); | |
| 367 | 385 | } |
| 368 | 386 | |
| 369 | 387 | static vm_fault_t kernfs_vma_fault(struct vm_fault *vmf) |
| @@ -375,14 +393,14 @@ static vm_fault_t kernfs_vma_fault(struct vm_fault *vmf) · 5 unmodified lines | ||
| 375 | 393 | if (!of->vm_ops) |
| 376 | 394 | return VM_FAULT_SIGBUS; |
| 377 | 395 | |
| 378 | − if (!kernfs_get_active(of->kn)) | |
| 396 | + if (!kernfs_get_active_of(of)) | |
| 379 | 397 | return VM_FAULT_SIGBUS; |
| 380 | 398 | |
| 381 | 399 | ret = VM_FAULT_SIGBUS; |
| 382 | 400 | if (of->vm_ops->fault) |
| 383 | 401 | ret = of->vm_ops->fault(vmf); |
| 384 | 402 | |
| 385 | − kernfs_put_active(of->kn); | |
| 403 | + kernfs_put_active_of(of); | |
| 386 | 404 | return ret; |
| 387 | 405 | } |
| 388 | 406 | |
| @@ -395,7 +413,7 @@ static vm_fault_t kernfs_vma_page_mkwrite(struct vm_fault *vmf) · 6 unmodified lines | ||
| 395 | 413 | if (!of->vm_ops) |
| 396 | 414 | return VM_FAULT_SIGBUS; |
| 397 | 415 | |
| 398 | − if (!kernfs_get_active(of->kn)) | |
| 416 | + if (!kernfs_get_active_of(of)) | |
| 399 | 417 | return VM_FAULT_SIGBUS; |
| 400 | 418 | |
| 401 | 419 | ret = 0; |
| @@ -404,7 +422,7 @@ static vm_fault_t kernfs_vma_page_mkwrite(struct vm_fault *vmf) · 2 unmodified lines | ||
| 404 | 422 | else |
| 405 | 423 | file_update_time(file); |
| 406 | 424 | |
| 407 | − kernfs_put_active(of->kn); | |
| 425 | + kernfs_put_active_of(of); | |
| 408 | 426 | return ret; |
| 409 | 427 | } |
| 410 | 428 | |
| @@ -418,14 +436,14 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, · 7 unmodified lines | ||
| 418 | 436 | if (!of->vm_ops) |
| 419 | 437 | return -EINVAL; |
| 420 | 438 | |
| 421 | − if (!kernfs_get_active(of->kn)) | |
| 439 | + if (!kernfs_get_active_of(of)) | |
| 422 | 440 | return -EINVAL; |
| 423 | 441 | |
| 424 | 442 | ret = -EINVAL; |
| 425 | 443 | if (of->vm_ops->access) |
| 426 | 444 | ret = of->vm_ops->access(vma, addr, buf, len, write); |
| 427 | 445 | |
| 428 | − kernfs_put_active(of->kn); | |
| 446 | + kernfs_put_active_of(of); | |
| 429 | 447 | return ret; |
| 430 | 448 | } |
| 431 | 449 | |
| @@ -455,7 +473,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma) · 23 unmodified lines | ||
| 455 | 473 | mutex_lock(&of->mutex); |
| 456 | 474 | |
| 457 | 475 | rc = -ENODEV; |
| 458 | − if (!kernfs_get_active(of->kn)) | |
| 476 | + if (!kernfs_get_active_of(of)) | |
| 459 | 477 | goto out_unlock; |
| 460 | 478 | |
| 461 | 479 | ops = kernfs_ops(of->kn); |
| @@ -490,7 +508,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma) · 28 unmodified lines | ||
| 490 | 508 | } |
| 491 | 509 | vma->vm_ops = &kernfs_vm_ops; |
| 492 | 510 | out_put: |
| 493 | − kernfs_put_active(of->kn); | |
| 511 | + kernfs_put_active_of(of); | |
| 494 | 512 | out_unlock: |
| 495 | 513 | mutex_unlock(&of->mutex); |
| 496 | 514 | |
| @@ -852,7 +870,7 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait) · 355 unmodified lines | ||
| 852 | 870 | struct kernfs_node *kn = kernfs_dentry_node(filp->f_path.dentry); |
| 853 | 871 | __poll_t ret; |
| 854 | 872 | |
| 855 | − if (!kernfs_get_active(kn)) | |
| 873 | + if (!kernfs_get_active_of(of)) | |
| 856 | 874 | return DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI; |
| 857 | 875 | |
| 858 | 876 | if (kn->attr.ops->poll) |
| @@ -860,7 +878,7 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait) · 1 unmodified line | ||
| 860 | 878 | else |
| 861 | 879 | ret = kernfs_generic_poll(of, wait); |
| 862 | 880 | |
| 863 | − kernfs_put_active(kn); | |
| 881 | + kernfs_put_active_of(of); | |
| 864 | 882 | return ret; |
| 865 | 883 | } |
| 866 | 884 | |
| @@ -875,7 +893,7 @@ static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence) · 8 unmodified lines | ||
| 875 | 893 | * the ops aren't called concurrently for the same open file. |
| 876 | 894 | */ |
| 877 | 895 | mutex_lock(&of->mutex); |
| 878 | − if (!kernfs_get_active(of->kn)) { | |
| 896 | + if (!kernfs_get_active_of(of)) { | |
| 879 | 897 | mutex_unlock(&of->mutex); |
| 880 | 898 | return -ENODEV; |
| 881 | 899 | } |
| @@ -886,7 +904,7 @@ static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence) · 4 unmodified lines | ||
| 886 | 904 | else |
| 887 | 905 | ret = generic_file_llseek(file, offset, whence); |
| 888 | 906 | |
| 889 | − kernfs_put_active(of->kn); | |
| 907 | + kernfs_put_active_of(of); | |
| 890 | 908 | mutex_unlock(&of->mutex); |
| 891 | 909 | return ret; |
| 892 | 910 | } |
| @@ -1075,7 +1075,7 @@ void nilfs_sysfs_delete_device_group(struct the_nilfs *nilfs) · 1074 unmodified lines | ||
| 1075 | 1075 | ************************************************************************/ |
| 1076 | 1076 | |
| 1077 | 1077 | static ssize_t nilfs_feature_revision_show(struct kobject *kobj, |
| 1078 | − struct attribute *attr, char *buf) | |
| 1078 | + struct kobj_attribute *attr, char *buf) | |
| 1079 | 1079 | { |
| 1080 | 1080 | return sysfs_emit(buf, "%d.%d\n", |
| 1081 | 1081 | NILFS_CURRENT_REV, NILFS_MINOR_REV); |
| @@ -1087,7 +1087,7 @@ static const char features_readme_str[] = · 5 unmodified lines | ||
| 1087 | 1087 | "(1) revision\n\tshow current revision of NILFS file system driver.\n"; |
| 1088 | 1088 | |
| 1089 | 1089 | static ssize_t nilfs_feature_README_show(struct kobject *kobj, |
| 1090 | − struct attribute *attr, | |
| 1090 | + struct kobj_attribute *attr, | |
| 1091 | 1091 | char *buf) |
| 1092 | 1092 | { |
| 1093 | 1093 | return sysfs_emit(buf, features_readme_str); |
| @@ -50,16 +50,16 @@ struct nilfs_sysfs_dev_subgroups { · 49 unmodified lines | ||
| 50 | 50 | struct completion sg_segments_kobj_unregister; |
| 51 | 51 | }; |
| 52 | 52 | |
| 53 | −#define NILFS_COMMON_ATTR_STRUCT(name) \ | |
| 53 | +#define NILFS_KOBJ_ATTR_STRUCT(name) \ | |
| 54 | 54 | struct nilfs_##name##_attr { \ |
| 55 | 55 | struct attribute attr; \ |
| 56 | − ssize_t (*show)(struct kobject *, struct attribute *, \ | |
| 56 | + ssize_t (*show)(struct kobject *, struct kobj_attribute *, \ | |
| 57 | 57 | char *); \ |
| 58 | − ssize_t (*store)(struct kobject *, struct attribute *, \ | |
| 58 | + ssize_t (*store)(struct kobject *, struct kobj_attribute *, \ | |
| 59 | 59 | const char *, size_t); \ |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | −NILFS_COMMON_ATTR_STRUCT(feature); | |
| 62 | +NILFS_KOBJ_ATTR_STRUCT(feature); | |
| 63 | 63 | |
| 64 | 64 | #define NILFS_DEV_ATTR_STRUCT(name) \ |
| 65 | 65 | struct nilfs_##name##_attr { \ |
| @@ -625,11 +625,11 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg) · 624 unmodified lines | ||
| 625 | 625 | */ |
| 626 | 626 | list_for_each_entry(d, &r->mon_domains, hdr.list) { |
| 627 | 627 | if (d->ci_id == domid) { |
| 628 | − rr.ci_id = d->ci_id; | |
| 629 | 628 | cpu = cpumask_any(&d->hdr.cpu_mask); |
| 630 | 629 | ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE); |
| 631 | 630 | if (!ci) |
| 632 | 631 | continue; |
| 632 | + rr.ci = ci; | |
| 633 | 633 | mon_event_read(&rr, r, NULL, rdtgrp, |
| 634 | 634 | &ci->shared_cpu_map, evtid, false); |
| 635 | 635 | goto checkresult; |
| @@ -98,7 +98,7 @@ struct mon_data { · 97 unmodified lines | ||
| 98 | 98 | * domains in @r sharing L3 @ci.id |
| 99 | 99 | * @evtid: Which monitor event to read. |
| 100 | 100 | * @first: Initialize MBM counter when true. |
| 101 | − * @ci_id: Cacheinfo id for L3. Only set when @d is NULL. Used when summing domains. | |
| 101 | + * @ci: Cacheinfo for L3. Only set when @d is NULL. Used when summing domains. | |
| 102 | 102 | * @err: Error encountered when reading counter. |
| 103 | 103 | * @val: Returned value of event counter. If @rgrp is a parent resource group, |
| 104 | 104 | * @val includes the sum of event counts from its child resource groups. |
| @@ -112,7 +112,7 @@ struct rmid_read { · 7 unmodified lines | ||
| 112 | 112 | struct rdt_mon_domain *d; |
| 113 | 113 | enum resctrl_event_id evtid; |
| 114 | 114 | bool first; |
| 115 | − unsigned int ci_id; | |
| 115 | + struct cacheinfo *ci; | |
| 116 | 116 | int err; |
| 117 | 117 | u64 val; |
| 118 | 118 | void *arch_mon_ctx; |
| @@ -361,7 +361,6 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr) · 360 unmodified lines | ||
| 361 | 361 | { |
| 362 | 362 | int cpu = smp_processor_id(); |
| 363 | 363 | struct rdt_mon_domain *d; |
| 364 | − struct cacheinfo *ci; | |
| 365 | 364 | struct mbm_state *m; |
| 366 | 365 | int err, ret; |
| 367 | 366 | u64 tval = 0; |
| @@ -389,8 +388,7 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr) · 21 unmodified lines | ||
| 389 | 388 | } |
| 390 | 389 | |
| 391 | 390 | /* Summing domains that share a cache, must be on a CPU for that cache. */ |
| 392 | − ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE); | |
| 393 | − if (!ci || ci->id != rr->ci_id) | |
| 391 | + if (!cpumask_test_cpu(cpu, &rr->ci->shared_cpu_map)) | |
| 394 | 392 | return -EINVAL; |
| 395 | 393 | |
| 396 | 394 | /* |
| @@ -402,7 +400,7 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr) · 5 unmodified lines | ||
| 402 | 400 | */ |
| 403 | 401 | ret = -EINVAL; |
| 404 | 402 | list_for_each_entry(d, &rr->r->mon_domains, hdr.list) { |
| 405 | − if (d->ci_id != rr->ci_id) | |
| 403 | + if (d->ci_id != rr->ci->id) | |
| 406 | 404 | continue; |
| 407 | 405 | err = resctrl_arch_rmid_read(rr->r, d, closid, rmid, |
| 408 | 406 | rr->evtid, &tval, rr->arch_mon_ctx); |
| @@ -87,7 +87,7 @@ · 86 unmodified lines | ||
| 87 | 87 | #define SMB_INTERFACE_POLL_INTERVAL 600 |
| 88 | 88 | |
| 89 | 89 | /* maximum number of PDUs in one compound */ |
| 90 | −#define MAX_COMPOUND 7 | |
| 90 | +#define MAX_COMPOUND 10 | |
| 91 | 91 | |
| 92 | 92 | /* |
| 93 | 93 | * Default number of credits to keep available for SMB3. |
| @@ -1882,9 +1882,12 @@ static inline bool is_replayable_error(int error) · 1788 unmodified lines | ||
| 1882 | 1882 | |
| 1883 | 1883 | |
| 1884 | 1884 | /* cifs_get_writable_file() flags */ |
| 1885 | −#define FIND_WR_ANY 0 | |
| 1886 | −#define FIND_WR_FSUID_ONLY 1 | |
| 1887 | −#define FIND_WR_WITH_DELETE 2 | |
| 1885 | +enum cifs_writable_file_flags { | |
| 1886 | + FIND_WR_ANY = 0U, | |
| 1887 | + FIND_WR_FSUID_ONLY = (1U << 0), | |
| 1888 | + FIND_WR_WITH_DELETE = (1U << 1), | |
| 1889 | + FIND_WR_NO_PENDING_DELETE = (1U << 2), | |
| 1890 | +}; | |
| 1888 | 1891 | |
| 1889 | 1892 | #define MID_FREE 0 |
| 1890 | 1893 | #define MID_REQUEST_ALLOCATED 1 |
| @@ -2343,6 +2346,8 @@ struct smb2_compound_vars { · 452 unmodified lines | ||
| 2343 | 2346 | struct kvec qi_iov; |
| 2344 | 2347 | struct kvec io_iov[SMB2_IOCTL_IOV_SIZE]; |
| 2345 | 2348 | struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE]; |
| 2349 | + struct kvec unlink_iov[SMB2_SET_INFO_IOV_SIZE]; | |
| 2350 | + struct kvec rename_iov[SMB2_SET_INFO_IOV_SIZE]; | |
| 2346 | 2351 | struct kvec close_iov; |
| 2347 | 2352 | struct smb2_file_rename_info_hdr rename_info; |
| 2348 | 2353 | struct smb2_file_link_info_hdr link_info; |
| @@ -998,7 +998,10 @@ int cifs_open(struct inode *inode, struct file *file) · 997 unmodified lines | ||
| 998 | 998 | |
| 999 | 999 | /* Get the cached handle as SMB2 close is deferred */ |
| 1000 | 1000 | if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) { |
| 1001 | − rc = cifs_get_writable_path(tcon, full_path, FIND_WR_FSUID_ONLY, &cfile); | |
| 1001 | + rc = cifs_get_writable_path(tcon, full_path, | |
| 1002 | + FIND_WR_FSUID_ONLY | | |
| 1003 | + FIND_WR_NO_PENDING_DELETE, | |
| 1004 | + &cfile); | |
| 1002 | 1005 | } else { |
| 1003 | 1006 | rc = cifs_get_readable_path(tcon, full_path, &cfile); |
| 1004 | 1007 | } |
| @@ -2530,6 +2533,9 @@ refind_writable: · 1525 unmodified lines | ||
| 2530 | 2533 | continue; |
| 2531 | 2534 | if (with_delete && !(open_file->fid.access & DELETE)) |
| 2532 | 2535 | continue; |
| 2536 | + if ((flags & FIND_WR_NO_PENDING_DELETE) && | |
| 2537 | + open_file->status_file_deleted) | |
| 2538 | + continue; | |
| 2533 | 2539 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
| 2534 | 2540 | if (!open_file->invalidHandle) { |
| 2535 | 2541 | /* found a good writable file */ |
| @@ -2647,6 +2653,16 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, · 111 unmodified lines | ||
| 2647 | 2653 | spin_unlock(&tcon->open_file_lock); |
| 2648 | 2654 | free_dentry_path(page); |
| 2649 | 2655 | *ret_file = find_readable_file(cinode, 0); |
| 2656 | + if (*ret_file) { | |
| 2657 | + spin_lock(&cinode->open_file_lock); | |
| 2658 | + if ((*ret_file)->status_file_deleted) { | |
| 2659 | + spin_unlock(&cinode->open_file_lock); | |
| 2660 | + cifsFileInfo_put(*ret_file); | |
| 2661 | + *ret_file = NULL; | |
| 2662 | + } else { | |
| 2663 | + spin_unlock(&cinode->open_file_lock); | |
| 2664 | + } | |
| 2665 | + } | |
| 2650 | 2666 | return *ret_file ? 0 : -ENOENT; |
| 2651 | 2667 | } |
| 2652 | 2668 | |
| @@ -1931,7 +1931,7 @@ cifs_drop_nlink(struct inode *inode) · 1930 unmodified lines | ||
| 1931 | 1931 | * but will return the EACCES to the caller. Note that the VFS does not call |
| 1932 | 1932 | * unlink on negative dentries currently. |
| 1933 | 1933 | */ |
| 1934 | −int cifs_unlink(struct inode *dir, struct dentry *dentry) | |
| 1934 | +static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyrename) | |
| 1935 | 1935 | { |
| 1936 | 1936 | int rc = 0; |
| 1937 | 1937 | unsigned int xid; |
| @@ -2003,7 +2003,11 @@ retry_std_delete: · 65 unmodified lines | ||
| 2003 | 2003 | goto psx_del_no_retry; |
| 2004 | 2004 | } |
| 2005 | 2005 | |
| 2006 | − rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry); | |
| 2006 | + if (sillyrename || (server->vals->protocol_id > SMB10_PROT_ID && | |
| 2007 | + d_is_positive(dentry) && d_count(dentry) > 2)) | |
| 2008 | + rc = -EBUSY; | |
| 2009 | + else | |
| 2010 | + rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry); | |
| 2007 | 2011 | |
| 2008 | 2012 | psx_del_no_retry: |
| 2009 | 2013 | if (!rc) { |
| @@ -2071,6 +2075,11 @@ unlink_out: · 61 unmodified lines | ||
| 2071 | 2075 | return rc; |
| 2072 | 2076 | } |
| 2073 | 2077 | |
| 2078 | +int cifs_unlink(struct inode *dir, struct dentry *dentry) | |
| 2079 | +{ | |
| 2080 | + return __cifs_unlink(dir, dentry, false); | |
| 2081 | +} | |
| 2082 | + | |
| 2074 | 2083 | static int |
| 2075 | 2084 | cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, |
| 2076 | 2085 | const char *full_path, struct cifs_sb_info *cifs_sb, |
| @@ -2358,14 +2367,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) · 281 unmodified lines | ||
| 2358 | 2367 | rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb); |
| 2359 | 2368 | cifs_put_tlink(tlink); |
| 2360 | 2369 | |
| 2370 | + cifsInode = CIFS_I(d_inode(direntry)); | |
| 2371 | + | |
| 2361 | 2372 | if (!rc) { |
| 2373 | + set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags); | |
| 2362 | 2374 | spin_lock(&d_inode(direntry)->i_lock); |
| 2363 | 2375 | i_size_write(d_inode(direntry), 0); |
| 2364 | 2376 | clear_nlink(d_inode(direntry)); |
| 2365 | 2377 | spin_unlock(&d_inode(direntry)->i_lock); |
| 2366 | 2378 | } |
| 2367 | 2379 | |
| 2368 | − cifsInode = CIFS_I(d_inode(direntry)); | |
| 2369 | 2380 | /* force revalidate to go get info when needed */ |
| 2370 | 2381 | cifsInode->time = 0; |
| 2371 | 2382 | |
| @@ -2458,8 +2469,11 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, · 86 unmodified lines | ||
| 2458 | 2469 | } |
| 2459 | 2470 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
| 2460 | 2471 | do_rename_exit: |
| 2461 | − if (rc == 0) | |
| 2472 | + if (rc == 0) { | |
| 2462 | 2473 | d_move(from_dentry, to_dentry); |
| 2474 | + /* Force a new lookup */ | |
| 2475 | + d_drop(from_dentry); | |
| 2476 | + } | |
| 2463 | 2477 | cifs_put_tlink(tlink); |
| 2464 | 2478 | return rc; |
| 2465 | 2479 | } |
| @@ -2470,6 +2484,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, · 4 unmodified lines | ||
| 2470 | 2484 | struct dentry *target_dentry, unsigned int flags) |
| 2471 | 2485 | { |
| 2472 | 2486 | const char *from_name, *to_name; |
| 2487 | + struct TCP_Server_Info *server; | |
| 2473 | 2488 | void *page1, *page2; |
| 2474 | 2489 | struct cifs_sb_info *cifs_sb; |
| 2475 | 2490 | struct tcon_link *tlink; |
| @@ -2505,6 +2520,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, · 29 unmodified lines | ||
| 2505 | 2520 | if (IS_ERR(tlink)) |
| 2506 | 2521 | return PTR_ERR(tlink); |
| 2507 | 2522 | tcon = tlink_tcon(tlink); |
| 2523 | + server = tcon->ses->server; | |
| 2508 | 2524 | |
| 2509 | 2525 | page1 = alloc_dentry_path(); |
| 2510 | 2526 | page2 = alloc_dentry_path(); |
| @@ -2591,19 +2607,53 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, · 80 unmodified lines | ||
| 2591 | 2607 | |
| 2592 | 2608 | unlink_target: |
| 2593 | 2609 | #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ |
| 2594 | − | |
| 2595 | − /* Try unlinking the target dentry if it's not negative */ | |
| 2596 | − if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) { | |
| 2597 | − if (d_is_dir(target_dentry)) | |
| 2598 | − tmprc = cifs_rmdir(target_dir, target_dentry); | |
| 2599 | − else | |
| 2600 | − tmprc = cifs_unlink(target_dir, target_dentry); | |
| 2601 | − if (tmprc) | |
| 2602 | − goto cifs_rename_exit; | |
| 2603 | − rc = cifs_do_rename(xid, source_dentry, from_name, | |
| 2604 | − target_dentry, to_name); | |
| 2605 | − if (!rc) | |
| 2606 | − rehash = false; | |
| 2610 | + if (d_really_is_positive(target_dentry)) { | |
| 2611 | + if (!rc) { | |
| 2612 | + struct inode *inode = d_inode(target_dentry); | |
| 2613 | + /* | |
| 2614 | + * Samba and ksmbd servers allow renaming a target | |
| 2615 | + * directory that is open, so make sure to update | |
| 2616 | + * ->i_nlink and then mark it as delete pending. | |
| 2617 | + */ | |
| 2618 | + if (S_ISDIR(inode->i_mode)) { | |
| 2619 | + drop_cached_dir_by_name(xid, tcon, to_name, cifs_sb); | |
| 2620 | + spin_lock(&inode->i_lock); | |
| 2621 | + i_size_write(inode, 0); | |
| 2622 | + clear_nlink(inode); | |
| 2623 | + spin_unlock(&inode->i_lock); | |
| 2624 | + set_bit(CIFS_INO_DELETE_PENDING, &CIFS_I(inode)->flags); | |
| 2625 | + CIFS_I(inode)->time = 0; /* force reval */ | |
| 2626 | + inode_set_ctime_current(inode); | |
| 2627 | + inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); | |
| 2628 | + } | |
| 2629 | + } else if (rc == -EACCES || rc == -EEXIST) { | |
| 2630 | + /* | |
| 2631 | + * Rename failed, possibly due to a busy target. | |
| 2632 | + * Retry it by unliking the target first. | |
| 2633 | + */ | |
| 2634 | + if (d_is_dir(target_dentry)) { | |
| 2635 | + tmprc = cifs_rmdir(target_dir, target_dentry); | |
| 2636 | + } else { | |
| 2637 | + tmprc = __cifs_unlink(target_dir, target_dentry, | |
| 2638 | + server->vals->protocol_id > SMB10_PROT_ID); | |
| 2639 | + } | |
| 2640 | + if (tmprc) { | |
| 2641 | + /* | |
| 2642 | + * Some servers will return STATUS_ACCESS_DENIED | |
| 2643 | + * or STATUS_DIRECTORY_NOT_EMPTY when failing to | |
| 2644 | + * rename a non-empty directory. Make sure to | |
| 2645 | + * propagate the appropriate error back to | |
| 2646 | + * userspace. | |
| 2647 | + */ | |
| 2648 | + if (tmprc == -EEXIST || tmprc == -ENOTEMPTY) | |
| 2649 | + rc = tmprc; | |
| 2650 | + goto cifs_rename_exit; | |
| 2651 | + } | |
| 2652 | + rc = cifs_do_rename(xid, source_dentry, from_name, | |
| 2653 | + target_dentry, to_name); | |
| 2654 | + if (!rc) | |
| 2655 | + rehash = false; | |
| 2656 | + } | |
| 2607 | 2657 | } |
| 2608 | 2658 | |
| 2609 | 2659 | /* force revalidate to go get info when needed */ |
| @@ -2629,6 +2679,8 @@ cifs_dentry_needs_reval(struct dentry *dentry) · 19 unmodified lines | ||
| 2629 | 2679 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
| 2630 | 2680 | struct cached_fid *cfid = NULL; |
| 2631 | 2681 | |
| 2682 | + if (test_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags)) | |
| 2683 | + return false; | |
| 2632 | 2684 | if (cifs_i->time == 0) |
| 2633 | 2685 | return true; |
| 2634 | 2686 | |
| @@ -30,10 +30,9 @@ enum smb2_compound_ops { · 29 unmodified lines | ||
| 30 | 30 | SMB2_OP_QUERY_DIR, |
| 31 | 31 | SMB2_OP_MKDIR, |
| 32 | 32 | SMB2_OP_RENAME, |
| 33 | − SMB2_OP_DELETE, | |
| 34 | 33 | SMB2_OP_HARDLINK, |
| 35 | 34 | SMB2_OP_SET_EOF, |
| 36 | − SMB2_OP_RMDIR, | |
| 35 | + SMB2_OP_UNLINK, | |
| 37 | 36 | SMB2_OP_POSIX_QUERY_INFO, |
| 38 | 37 | SMB2_OP_SET_REPARSE, |
| 39 | 38 | SMB2_OP_GET_REPARSE, |
| @@ -346,9 +346,6 @@ replay_again: · 345 unmodified lines | ||
| 346 | 346 | trace_smb3_posix_query_info_compound_enter(xid, tcon->tid, |
| 347 | 347 | ses->Suid, full_path); |
| 348 | 348 | break; |
| 349 | − case SMB2_OP_DELETE: | |
| 350 | − trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path); | |
| 351 | − break; | |
| 352 | 349 | case SMB2_OP_MKDIR: |
| 353 | 350 | /* |
| 354 | 351 | * Directories are created through parameters in the |
| @@ -356,23 +353,40 @@ replay_again: · 1 unmodified line | ||
| 356 | 353 | */ |
| 357 | 354 | trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path); |
| 358 | 355 | break; |
| 359 | − case SMB2_OP_RMDIR: | |
| 360 | − rqst[num_rqst].rq_iov = &vars->si_iov[0]; | |
| 356 | + case SMB2_OP_UNLINK: | |
| 357 | + rqst[num_rqst].rq_iov = vars->unlink_iov; | |
| 361 | 358 | rqst[num_rqst].rq_nvec = 1; |
| 362 | 359 | |
| 363 | 360 | size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */ |
| 364 | 361 | data[0] = &delete_pending[0]; |
| 365 | 362 | |
| 366 | − rc = SMB2_set_info_init(tcon, server, | |
| 367 | − &rqst[num_rqst], COMPOUND_FID, | |
| 368 | − COMPOUND_FID, current->tgid, | |
| 369 | − FILE_DISPOSITION_INFORMATION, | |
| 370 | − SMB2_O_INFO_FILE, 0, data, size); | |
| 371 | − if (rc) | |
| 363 | + if (cfile) { | |
| 364 | + rc = SMB2_set_info_init(tcon, server, | |
| 365 | + &rqst[num_rqst], | |
| 366 | + cfile->fid.persistent_fid, | |
| 367 | + cfile->fid.volatile_fid, | |
| 368 | + current->tgid, | |
| 369 | + FILE_DISPOSITION_INFORMATION, | |
| 370 | + SMB2_O_INFO_FILE, 0, | |
| 371 | + data, size); | |
| 372 | + } else { | |
| 373 | + rc = SMB2_set_info_init(tcon, server, | |
| 374 | + &rqst[num_rqst], | |
| 375 | + COMPOUND_FID, | |
| 376 | + COMPOUND_FID, | |
| 377 | + current->tgid, | |
| 378 | + FILE_DISPOSITION_INFORMATION, | |
| 379 | + SMB2_O_INFO_FILE, 0, | |
| 380 | + data, size); | |
| 381 | + } | |
| 382 | + if (!rc && (!cfile || num_rqst > 1)) { | |
| 383 | + smb2_set_next_command(tcon, &rqst[num_rqst]); | |
| 384 | + smb2_set_related(&rqst[num_rqst]); | |
| 385 | + } else if (rc) { | |
| 372 | 386 | goto finished; |
| 373 | − smb2_set_next_command(tcon, &rqst[num_rqst]); | |
| 374 | − smb2_set_related(&rqst[num_rqst++]); | |
| 375 | − trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path); | |
| 387 | + } | |
| 388 | + num_rqst++; | |
| 389 | + trace_smb3_unlink_enter(xid, tcon->tid, ses->Suid, full_path); | |
| 376 | 390 | break; |
| 377 | 391 | case SMB2_OP_SET_EOF: |
| 378 | 392 | rqst[num_rqst].rq_iov = &vars->si_iov[0]; |
| @@ -442,7 +456,7 @@ replay_again: · 63 unmodified lines | ||
| 442 | 456 | ses->Suid, full_path); |
| 443 | 457 | break; |
| 444 | 458 | case SMB2_OP_RENAME: |
| 445 | − rqst[num_rqst].rq_iov = &vars->si_iov[0]; | |
| 459 | + rqst[num_rqst].rq_iov = vars->rename_iov; | |
| 446 | 460 | rqst[num_rqst].rq_nvec = 2; |
| 447 | 461 | |
| 448 | 462 | len = in_iov[i].iov_len; |
| @@ -732,19 +746,6 @@ finished: · 283 unmodified lines | ||
| 732 | 746 | trace_smb3_posix_query_info_compound_done(xid, tcon->tid, |
| 733 | 747 | ses->Suid); |
| 734 | 748 | break; |
| 735 | − case SMB2_OP_DELETE: | |
| 736 | − if (rc) | |
| 737 | − trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc); | |
| 738 | − else { | |
| 739 | − /* | |
| 740 | − * If dentry (hence, inode) is NULL, lease break is going to | |
| 741 | − * take care of degrading leases on handles for deleted files. | |
| 742 | − */ | |
| 743 | − if (inode) | |
| 744 | − cifs_mark_open_handles_for_deleted_file(inode, full_path); | |
| 745 | − trace_smb3_delete_done(xid, tcon->tid, ses->Suid); | |
| 746 | − } | |
| 747 | − break; | |
| 748 | 749 | case SMB2_OP_MKDIR: |
| 749 | 750 | if (rc) |
| 750 | 751 | trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc); |
| @@ -765,11 +766,11 @@ finished: · 14 unmodified lines | ||
| 765 | 766 | trace_smb3_rename_done(xid, tcon->tid, ses->Suid); |
| 766 | 767 | SMB2_set_info_free(&rqst[num_rqst++]); |
| 767 | 768 | break; |
| 768 | − case SMB2_OP_RMDIR: | |
| 769 | − if (rc) | |
| 770 | − trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc); | |
| 769 | + case SMB2_OP_UNLINK: | |
| 770 | + if (!rc) | |
| 771 | + trace_smb3_unlink_done(xid, tcon->tid, ses->Suid); | |
| 771 | 772 | else |
| 772 | − trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid); | |
| 773 | + trace_smb3_unlink_err(xid, tcon->tid, ses->Suid, rc); | |
| 773 | 774 | SMB2_set_info_free(&rqst[num_rqst++]); |
| 774 | 775 | break; |
| 775 | 776 | case SMB2_OP_SET_EOF: |
| @@ -1166,7 +1167,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, · 390 unmodified lines | ||
| 1166 | 1167 | FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE); |
| 1167 | 1168 | return smb2_compound_op(xid, tcon, cifs_sb, |
| 1168 | 1169 | name, &oparms, NULL, |
| 1169 | − &(int){SMB2_OP_RMDIR}, 1, | |
| 1170 | + &(int){SMB2_OP_UNLINK}, 1, | |
| 1170 | 1171 | NULL, NULL, NULL, NULL); |
| 1171 | 1172 | } |
| 1172 | 1173 | |
| @@ -1175,20 +1176,29 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, · 2 unmodified lines | ||
| 1175 | 1176 | struct cifs_sb_info *cifs_sb, struct dentry *dentry) |
| 1176 | 1177 | { |
| 1177 | 1178 | struct cifs_open_parms oparms; |
| 1179 | + struct inode *inode = NULL; | |
| 1180 | + int rc; | |
| 1178 | 1181 | |
| 1179 | − oparms = CIFS_OPARMS(cifs_sb, tcon, name, | |
| 1180 | − DELETE, FILE_OPEN, | |
| 1181 | − CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, | |
| 1182 | − ACL_NO_MODE); | |
| 1183 | − int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms, | |
| 1184 | − NULL, &(int){SMB2_OP_DELETE}, 1, | |
| 1185 | − NULL, NULL, NULL, dentry); | |
| 1182 | + if (dentry) | |
| 1183 | + inode = d_inode(dentry); | |
| 1184 | + | |
| 1185 | + oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE, | |
| 1186 | + FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE); | |
| 1187 | + rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms, | |
| 1188 | + NULL, &(int){SMB2_OP_UNLINK}, | |
| 1189 | + 1, NULL, NULL, NULL, dentry); | |
| 1186 | 1190 | if (rc == -EINVAL) { |
| 1187 | 1191 | cifs_dbg(FYI, "invalid lease key, resending request without lease"); |
| 1188 | 1192 | rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms, |
| 1189 | − NULL, &(int){SMB2_OP_DELETE}, 1, | |
| 1190 | − NULL, NULL, NULL, NULL); | |
| 1193 | + NULL, &(int){SMB2_OP_UNLINK}, | |
| 1194 | + 1, NULL, NULL, NULL, NULL); | |
| 1191 | 1195 | } |
| 1196 | + /* | |
| 1197 | + * If dentry (hence, inode) is NULL, lease break is going to | |
| 1198 | + * take care of degrading leases on handles for deleted files. | |
| 1199 | + */ | |
| 1200 | + if (!rc && inode) | |
| 1201 | + cifs_mark_open_handles_for_deleted_file(inode, name); | |
| 1192 | 1202 | return rc; |
| 1193 | 1203 | } |
| 1194 | 1204 | |
| @@ -1441,3 +1451,113 @@ out: · 246 unmodified lines | ||
| 1441 | 1451 | cifs_free_open_info(&data); |
| 1442 | 1452 | return rc; |
| 1443 | 1453 | } |
| 1454 | + | |
| 1455 | +static inline __le16 *utf16_smb2_path(struct cifs_sb_info *cifs_sb, | |
| 1456 | + const char *name, size_t namelen) | |
| 1457 | +{ | |
| 1458 | + int len; | |
| 1459 | + | |
| 1460 | + if (*name == '\\' || | |
| 1461 | + (cifs_sb_master_tlink(cifs_sb) && | |
| 1462 | + cifs_sb_master_tcon(cifs_sb)->posix_extensions && *name == '/')) | |
| 1463 | + name++; | |
| 1464 | + return cifs_strndup_to_utf16(name, namelen, &len, | |
| 1465 | + cifs_sb->local_nls, | |
| 1466 | + cifs_remap(cifs_sb)); | |
| 1467 | +} | |
| 1468 | + | |
| 1469 | +int smb2_rename_pending_delete(const char *full_path, | |
| 1470 | + struct dentry *dentry, | |
| 1471 | + const unsigned int xid) | |
| 1472 | +{ | |
| 1473 | + struct cifs_sb_info *cifs_sb = CIFS_SB(d_inode(dentry)->i_sb); | |
| 1474 | + struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry)); | |
| 1475 | + __le16 *utf16_path __free(kfree) = NULL; | |
| 1476 | + __u32 co = file_create_options(dentry); | |
| 1477 | + int cmds[] = { | |
| 1478 | + SMB2_OP_SET_INFO, | |
| 1479 | + SMB2_OP_RENAME, | |
| 1480 | + SMB2_OP_UNLINK, | |
| 1481 | + }; | |
| 1482 | + const int num_cmds = ARRAY_SIZE(cmds); | |
| 1483 | + char *to_name __free(kfree) = NULL; | |
| 1484 | + __u32 attrs = cinode->cifsAttrs; | |
| 1485 | + struct cifs_open_parms oparms; | |
| 1486 | + static atomic_t sillycounter; | |
| 1487 | + struct cifsFileInfo *cfile; | |
| 1488 | + struct tcon_link *tlink; | |
| 1489 | + struct cifs_tcon *tcon; | |
| 1490 | + struct kvec iov[2]; | |
| 1491 | + const char *ppath; | |
| 1492 | + void *page; | |
| 1493 | + size_t len; | |
| 1494 | + int rc; | |
| 1495 | + | |
| 1496 | + tlink = cifs_sb_tlink(cifs_sb); | |
| 1497 | + if (IS_ERR(tlink)) | |
| 1498 | + return PTR_ERR(tlink); | |
| 1499 | + tcon = tlink_tcon(tlink); | |
| 1500 | + | |
| 1501 | + page = alloc_dentry_path(); | |
| 1502 | + | |
| 1503 | + ppath = build_path_from_dentry(dentry->d_parent, page); | |
| 1504 | + if (IS_ERR(ppath)) { | |
| 1505 | + rc = PTR_ERR(ppath); | |
| 1506 | + goto out; | |
| 1507 | + } | |
| 1508 | + | |
| 1509 | + len = strlen(ppath) + strlen("/.__smb1234") + 1; | |
| 1510 | + to_name = kmalloc(len, GFP_KERNEL); | |
| 1511 | + if (!to_name) { | |
| 1512 | + rc = -ENOMEM; | |
| 1513 | + goto out; | |
| 1514 | + } | |
| 1515 | + | |
| 1516 | + scnprintf(to_name, len, "%s%c.__smb%04X", ppath, CIFS_DIR_SEP(cifs_sb), | |
| 1517 | + atomic_inc_return(&sillycounter) & 0xffff); | |
| 1518 | + | |
| 1519 | + utf16_path = utf16_smb2_path(cifs_sb, to_name, len); | |
| 1520 | + if (!utf16_path) { | |
| 1521 | + rc = -ENOMEM; | |
| 1522 | + goto out; | |
| 1523 | + } | |
| 1524 | + | |
| 1525 | + drop_cached_dir_by_name(xid, tcon, full_path, cifs_sb); | |
| 1526 | + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, | |
| 1527 | + DELETE | FILE_WRITE_ATTRIBUTES, | |
| 1528 | + FILE_OPEN, co, ACL_NO_MODE); | |
| 1529 | + | |
| 1530 | + attrs &= ~ATTR_READONLY; | |
| 1531 | + if (!attrs) | |
| 1532 | + attrs = ATTR_NORMAL; | |
| 1533 | + if (d_inode(dentry)->i_nlink <= 1) | |
| 1534 | + attrs |= ATTR_HIDDEN; | |
| 1535 | + iov[0].iov_base = &(FILE_BASIC_INFO) { | |
| 1536 | + .Attributes = cpu_to_le32(attrs), | |
| 1537 | + }; | |
| 1538 | + iov[0].iov_len = sizeof(FILE_BASIC_INFO); | |
| 1539 | + iov[1].iov_base = utf16_path; | |
| 1540 | + iov[1].iov_len = sizeof(*utf16_path) * UniStrlen((wchar_t *)utf16_path); | |
| 1541 | + | |
| 1542 | + cifs_get_writable_path(tcon, full_path, FIND_WR_WITH_DELETE, &cfile); | |
| 1543 | + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov, | |
| 1544 | + cmds, num_cmds, cfile, NULL, NULL, dentry); | |
| 1545 | + if (rc == -EINVAL) { | |
| 1546 | + cifs_dbg(FYI, "invalid lease key, resending request without lease\n"); | |
| 1547 | + cifs_get_writable_path(tcon, full_path, | |
| 1548 | + FIND_WR_WITH_DELETE, &cfile); | |
| 1549 | + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov, | |
| 1550 | + cmds, num_cmds, cfile, NULL, NULL, NULL); | |
| 1551 | + } | |
| 1552 | + if (!rc) { | |
| 1553 | + set_bit(CIFS_INO_DELETE_PENDING, &cinode->flags); | |
| 1554 | + } else { | |
| 1555 | + cifs_tcon_dbg(FYI, "%s: failed to rename '%s' to '%s': %d\n", | |
| 1556 | + __func__, full_path, to_name, rc); | |
| 1557 | + rc = -EIO; | |
| 1558 | + } | |
| 1559 | +out: | |
| 1560 | + cifs_put_tlink(tlink); | |
| 1561 | + free_dentry_path(page); | |
| 1562 | + return rc; | |
| 1563 | +} | |
| @@ -2640,13 +2640,35 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) · 2639 unmodified lines | ||
| 2640 | 2640 | } |
| 2641 | 2641 | |
| 2642 | 2642 | /* SMB headers in a compound are 8 byte aligned. */ |
| 2643 | − if (!IS_ALIGNED(len, 8)) { | |
| 2644 | − num_padding = 8 - (len & 7); | |
| 2643 | + if (IS_ALIGNED(len, 8)) | |
| 2644 | + goto out; | |
| 2645 | + | |
| 2646 | + num_padding = 8 - (len & 7); | |
| 2647 | + if (smb3_encryption_required(tcon)) { | |
| 2648 | + int i; | |
| 2649 | + | |
| 2650 | + /* | |
| 2651 | + * Flatten request into a single buffer with required padding as | |
| 2652 | + * the encryption layer can't handle the padding iovs. | |
| 2653 | + */ | |
| 2654 | + for (i = 1; i < rqst->rq_nvec; i++) { | |
| 2655 | + memcpy(rqst->rq_iov[0].iov_base + | |
| 2656 | + rqst->rq_iov[0].iov_len, | |
| 2657 | + rqst->rq_iov[i].iov_base, | |
| 2658 | + rqst->rq_iov[i].iov_len); | |
| 2659 | + rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len; | |
| 2660 | + } | |
| 2661 | + memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len, | |
| 2662 | + 0, num_padding); | |
| 2663 | + rqst->rq_iov[0].iov_len += num_padding; | |
| 2664 | + rqst->rq_nvec = 1; | |
| 2665 | + } else { | |
| 2645 | 2666 | rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; |
| 2646 | 2667 | rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding; |
| 2647 | 2668 | rqst->rq_nvec++; |
| 2648 | − len += num_padding; | |
| 2649 | 2669 | } |
| 2670 | + len += num_padding; | |
| 2671 | +out: | |
| 2650 | 2672 | shdr->NextCommand = cpu_to_le32(len); |
| 2651 | 2673 | } |
| 2652 | 2674 | |
| @@ -5376,6 +5398,7 @@ struct smb_version_operations smb20_operations = { · 2723 unmodified lines | ||
| 5376 | 5398 | .llseek = smb3_llseek, |
| 5377 | 5399 | .is_status_io_timeout = smb2_is_status_io_timeout, |
| 5378 | 5400 | .is_network_name_deleted = smb2_is_network_name_deleted, |
| 5401 | + .rename_pending_delete = smb2_rename_pending_delete, | |
| 5379 | 5402 | }; |
| 5380 | 5403 | #endif /* CIFS_ALLOW_INSECURE_LEGACY */ |
| 5381 | 5404 | |
| @@ -5481,6 +5504,7 @@ struct smb_version_operations smb21_operations = { · 99 unmodified lines | ||
| 5481 | 5504 | .llseek = smb3_llseek, |
| 5482 | 5505 | .is_status_io_timeout = smb2_is_status_io_timeout, |
| 5483 | 5506 | .is_network_name_deleted = smb2_is_network_name_deleted, |
| 5507 | + .rename_pending_delete = smb2_rename_pending_delete, | |
| 5484 | 5508 | }; |
| 5485 | 5509 | |
| 5486 | 5510 | struct smb_version_operations smb30_operations = { |
| @@ -5597,6 +5621,7 @@ struct smb_version_operations smb30_operations = { · 110 unmodified lines | ||
| 5597 | 5621 | .llseek = smb3_llseek, |
| 5598 | 5622 | .is_status_io_timeout = smb2_is_status_io_timeout, |
| 5599 | 5623 | .is_network_name_deleted = smb2_is_network_name_deleted, |
| 5624 | + .rename_pending_delete = smb2_rename_pending_delete, | |
| 5600 | 5625 | }; |
| 5601 | 5626 | |
| 5602 | 5627 | struct smb_version_operations smb311_operations = { |
| @@ -5713,6 +5738,7 @@ struct smb_version_operations smb311_operations = { · 110 unmodified lines | ||
| 5713 | 5738 | .llseek = smb3_llseek, |
| 5714 | 5739 | .is_status_io_timeout = smb2_is_status_io_timeout, |
| 5715 | 5740 | .is_network_name_deleted = smb2_is_network_name_deleted, |
| 5741 | + .rename_pending_delete = smb2_rename_pending_delete, | |
| 5716 | 5742 | }; |
| 5717 | 5743 | |
| 5718 | 5744 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
| @@ -317,5 +317,8 @@ int posix_info_sid_size(const void *beg, const void *end); · 316 unmodified lines | ||
| 317 | 317 | int smb2_make_nfs_node(unsigned int xid, struct inode *inode, |
| 318 | 318 | struct dentry *dentry, struct cifs_tcon *tcon, |
| 319 | 319 | const char *full_path, umode_t mode, dev_t dev); |
| 320 | +int smb2_rename_pending_delete(const char *full_path, | |
| 321 | + struct dentry *dentry, | |
| 322 | + const unsigned int xid); | |
| 320 | 323 | |
| 321 | 324 | #endif /* _SMB2PROTO_H */ |
| @@ -669,13 +669,12 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_info_compound_enter); · 668 unmodified lines | ||
| 669 | 669 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(posix_query_info_compound_enter); |
| 670 | 670 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(hardlink_enter); |
| 671 | 671 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter); |
| 672 | −DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter); | |
| 672 | +DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(unlink_enter); | |
| 673 | 673 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter); |
| 674 | 674 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter); |
| 675 | 675 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter); |
| 676 | 676 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter); |
| 677 | 677 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_wsl_ea_compound_enter); |
| 678 | −DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter); | |
| 679 | 678 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter); |
| 680 | 679 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter); |
| 681 | 680 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mknod_enter); |
| @@ -710,13 +709,12 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_info_compound_done); · 28 unmodified lines | ||
| 710 | 709 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(posix_query_info_compound_done); |
| 711 | 710 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(hardlink_done); |
| 712 | 711 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done); |
| 713 | −DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done); | |
| 712 | +DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(unlink_done); | |
| 714 | 713 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done); |
| 715 | 714 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done); |
| 716 | 715 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_reparse_compound_done); |
| 717 | 716 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(get_reparse_compound_done); |
| 718 | 717 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_wsl_ea_compound_done); |
| 719 | −DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done); | |
| 720 | 718 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done); |
| 721 | 719 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done); |
| 722 | 720 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mknod_done); |
| @@ -756,14 +754,13 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_info_compound_err); · 33 unmodified lines | ||
| 756 | 754 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(posix_query_info_compound_err); |
| 757 | 755 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(hardlink_err); |
| 758 | 756 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err); |
| 759 | −DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err); | |
| 757 | +DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(unlink_err); | |
| 760 | 758 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err); |
| 761 | 759 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err); |
| 762 | 760 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_reparse_compound_err); |
| 763 | 761 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(get_reparse_compound_err); |
| 764 | 762 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_wsl_ea_compound_err); |
| 765 | 763 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err); |
| 766 | −DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err); | |
| 767 | 764 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err); |
| 768 | 765 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mknod_err); |
| 769 | 766 | |
| @@ -554,7 +554,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) · 553 unmodified lines | ||
| 554 | 554 | case SMB_DIRECT_MSG_DATA_TRANSFER: { |
| 555 | 555 | struct smb_direct_data_transfer *data_transfer = |
| 556 | 556 | (struct smb_direct_data_transfer *)recvmsg->packet; |
| 557 | − unsigned int data_length; | |
| 557 | + u32 remaining_data_length, data_offset, data_length; | |
| 558 | 558 | int avail_recvmsg_count, receive_credits; |
| 559 | 559 | |
| 560 | 560 | if (wc->byte_len < |
| @@ -564,15 +564,25 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) · 3 unmodified lines | ||
| 564 | 564 | return; |
| 565 | 565 | } |
| 566 | 566 | |
| 567 | + remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length); | |
| 567 | 568 | data_length = le32_to_cpu(data_transfer->data_length); |
| 568 | − if (data_length) { | |
| 569 | − if (wc->byte_len < sizeof(struct smb_direct_data_transfer) + | |
| 570 | − (u64)data_length) { | |
| 571 | − put_recvmsg(t, recvmsg); | |
| 572 | − smb_direct_disconnect_rdma_connection(t); | |
| 573 | − return; | |
| 574 | − } | |
| 569 | + data_offset = le32_to_cpu(data_transfer->data_offset); | |
| 570 | + if (wc->byte_len < data_offset || | |
| 571 | + wc->byte_len < (u64)data_offset + data_length) { | |
| 572 | + put_recvmsg(t, recvmsg); | |
| 573 | + smb_direct_disconnect_rdma_connection(t); | |
| 574 | + return; | |
| 575 | + } | |
| 576 | + if (remaining_data_length > t->max_fragmented_recv_size || | |
| 577 | + data_length > t->max_fragmented_recv_size || | |
| 578 | + (u64)remaining_data_length + (u64)data_length > | |
| 579 | + (u64)t->max_fragmented_recv_size) { | |
| 580 | + put_recvmsg(t, recvmsg); | |
| 581 | + smb_direct_disconnect_rdma_connection(t); | |
| 582 | + return; | |
| 583 | + } | |
| 575 | 584 | |
| 585 | + if (data_length) { | |
| 576 | 586 | if (t->full_packet_received) |
| 577 | 587 | recvmsg->first_segment = true; |
| 578 | 588 | |
| @@ -1209,78 +1219,130 @@ static int smb_direct_writev(struct ksmbd_transport *t, · 630 unmodified lines | ||
| 1209 | 1219 | bool need_invalidate, unsigned int remote_key) |
| 1210 | 1220 | { |
| 1211 | 1221 | struct smb_direct_transport *st = smb_trans_direct_transfort(t); |
| 1212 | − int remaining_data_length; | |
| 1213 | − int start, i, j; | |
| 1214 | − int max_iov_size = st->max_send_size - | |
| 1222 | + size_t remaining_data_length; | |
| 1223 | + size_t iov_idx; | |
| 1224 | + size_t iov_ofs; | |
| 1225 | + size_t max_iov_size = st->max_send_size - | |
| 1215 | 1226 | sizeof(struct smb_direct_data_transfer); |
| 1216 | 1227 | int ret; |
| 1217 | − struct kvec vec; | |
| 1218 | 1228 | struct smb_direct_send_ctx send_ctx; |
| 1229 | + int error = 0; | |
| 1219 | 1230 | |
| 1220 | 1231 | if (st->status != SMB_DIRECT_CS_CONNECTED) |
| 1221 | 1232 | return -ENOTCONN; |
| 1222 | 1233 | |
| 1223 | 1234 | //FIXME: skip RFC1002 header.. |
| 1235 | + if (WARN_ON_ONCE(niovs <= 1 || iov[0].iov_len != 4)) | |
| 1236 | + return -EINVAL; | |
| 1224 | 1237 | buflen -= 4; |
| 1238 | + iov_idx = 1; | |
| 1239 | + iov_ofs = 0; | |
| 1225 | 1240 | |
| 1226 | 1241 | remaining_data_length = buflen; |
| 1227 | 1242 | ksmbd_debug(RDMA, "Sending smb (RDMA): smb_len=%u\n", buflen); |
| 1228 | 1243 | |
| 1229 | 1244 | smb_direct_send_ctx_init(st, &send_ctx, need_invalidate, remote_key); |
| 1230 | − start = i = 1; | |
| 1231 | − buflen = 0; | |
| 1232 | − while (true) { | |
| 1233 | − buflen += iov[i].iov_len; | |
| 1234 | − if (buflen > max_iov_size) { | |
| 1235 | − if (i > start) { | |
| 1236 | − remaining_data_length -= | |
| 1237 | − (buflen - iov[i].iov_len); | |
| 1238 | − ret = smb_direct_post_send_data(st, &send_ctx, | |
| 1239 | − &iov[start], i - start, | |
| 1240 | − remaining_data_length); | |
| 1241 | − if (ret) | |
| 1245 | + while (remaining_data_length) { | |
| 1246 | + struct kvec vecs[SMB_DIRECT_MAX_SEND_SGES - 1]; /* minus smbdirect hdr */ | |
| 1247 | + size_t possible_bytes = max_iov_size; | |
| 1248 | + size_t possible_vecs; | |
| 1249 | + size_t bytes = 0; | |
| 1250 | + size_t nvecs = 0; | |
| 1251 | + | |
| 1252 | + /* | |
| 1253 | + * For the last message remaining_data_length should be | |
| 1254 | + * have been 0 already! | |
| 1255 | + */ | |
| 1256 | + if (WARN_ON_ONCE(iov_idx >= niovs)) { | |
| 1257 | + error = -EINVAL; | |
| 1258 | + goto done; | |
| 1259 | + } | |
| 1260 | + | |
| 1261 | + /* | |
| 1262 | + * We have 2 factors which limit the arguments we pass | |
| 1263 | + * to smb_direct_post_send_data(): | |
| 1264 | + * | |
| 1265 | + * 1. The number of supported sges for the send, | |
| 1266 | + * while one is reserved for the smbdirect header. | |
| 1267 | + * And we currently need one SGE per page. | |
| 1268 | + * 2. The number of negotiated payload bytes per send. | |
| 1269 | + */ | |
| 1270 | + possible_vecs = min_t(size_t, ARRAY_SIZE(vecs), niovs - iov_idx); | |
| 1271 | + | |
| 1272 | + while (iov_idx < niovs && possible_vecs && possible_bytes) { | |
| 1273 | + struct kvec *v = &vecs[nvecs]; | |
| 1274 | + int page_count; | |
| 1275 | + | |
| 1276 | + v->iov_base = ((u8 *)iov[iov_idx].iov_base) + iov_ofs; | |
| 1277 | + v->iov_len = min_t(size_t, | |
| 1278 | + iov[iov_idx].iov_len - iov_ofs, | |
| 1279 | + possible_bytes); | |
| 1280 | + page_count = get_buf_page_count(v->iov_base, v->iov_len); | |
| 1281 | + if (page_count > possible_vecs) { | |
| 1282 | + /* | |
| 1283 | + * If the number of pages in the buffer | |
| 1284 | + * is to much (because we currently require | |
| 1285 | + * one SGE per page), we need to limit the | |
| 1286 | + * length. | |
| 1287 | + * | |
| 1288 | + * We know possible_vecs is at least 1, | |
| 1289 | + * so we always keep the first page. | |
| 1290 | + * | |
| 1291 | + * We need to calculate the number extra | |
| 1292 | + * pages (epages) we can also keep. | |
| 1293 | + * | |
| 1294 | + * We calculate the number of bytes in the | |
| 1295 | + * first page (fplen), this should never be | |
| 1296 | + * larger than v->iov_len because page_count is | |
| 1297 | + * at least 2, but adding a limitation feels | |
| 1298 | + * better. | |
| 1299 | + * | |
| 1300 | + * Then we calculate the number of bytes (elen) | |
| 1301 | + * we can keep for the extra pages. | |
| 1302 | + */ | |
| 1303 | + size_t epages = possible_vecs - 1; | |
| 1304 | + size_t fpofs = offset_in_page(v->iov_base); | |
| 1305 | + size_t fplen = min_t(size_t, PAGE_SIZE - fpofs, v->iov_len); | |
| 1306 | + size_t elen = min_t(size_t, v->iov_len - fplen, epages*PAGE_SIZE); | |
| 1307 | + | |
| 1308 | + v->iov_len = fplen + elen; | |
| 1309 | + page_count = get_buf_page_count(v->iov_base, v->iov_len); | |
| 1310 | + if (WARN_ON_ONCE(page_count > possible_vecs)) { | |
| 1311 | + /* | |
| 1312 | + * Something went wrong in the above | |
| 1313 | + * logic... | |
| 1314 | + */ | |
| 1315 | + error = -EINVAL; | |
| 1242 | 1316 | goto done; |
| 1243 | − } else { | |
| 1244 | − /* iov[start] is too big, break it */ | |
| 1245 | − int nvec = (buflen + max_iov_size - 1) / | |
| 1246 | − max_iov_size; | |
| 1247 | − | |
| 1248 | − for (j = 0; j < nvec; j++) { | |
| 1249 | − vec.iov_base = | |
| 1250 | − (char *)iov[start].iov_base + | |
| 1251 | − j * max_iov_size; | |
| 1252 | − vec.iov_len = | |
| 1253 | − min_t(int, max_iov_size, | |
| 1254 | − buflen - max_iov_size * j); | |
| 1255 | − remaining_data_length -= vec.iov_len; | |
| 1256 | − ret = smb_direct_post_send_data(st, &send_ctx, &vec, 1, | |
| 1257 | − remaining_data_length); | |
| 1258 | − if (ret) | |
| 1259 | − goto done; | |
| 1260 | 1317 | } |
| 1261 | − i++; | |
| 1262 | − if (i == niovs) | |
| 1263 | − break; | |
| 1264 | 1318 | } |
| 1265 | − start = i; | |
| 1266 | − buflen = 0; | |
| 1267 | − } else { | |
| 1268 | − i++; | |
| 1269 | − if (i == niovs) { | |
| 1270 | − /* send out all remaining vecs */ | |
| 1271 | − remaining_data_length -= buflen; | |
| 1272 | − ret = smb_direct_post_send_data(st, &send_ctx, | |
| 1273 | − &iov[start], i - start, | |
| 1274 | − remaining_data_length); | |
| 1275 | − if (ret) | |
| 1276 | − goto done; | |
| 1277 | − break; | |
| 1319 | + possible_vecs -= page_count; | |
| 1320 | + nvecs += 1; | |
| 1321 | + possible_bytes -= v->iov_len; | |
| 1322 | + bytes += v->iov_len; | |
| 1323 | + | |
| 1324 | + iov_ofs += v->iov_len; | |
| 1325 | + if (iov_ofs >= iov[iov_idx].iov_len) { | |
| 1326 | + iov_idx += 1; | |
| 1327 | + iov_ofs = 0; | |
| 1278 | 1328 | } |
| 1279 | 1329 | } |
| 1330 | + | |
| 1331 | + remaining_data_length -= bytes; | |
| 1332 | + | |
| 1333 | + ret = smb_direct_post_send_data(st, &send_ctx, | |
| 1334 | + vecs, nvecs, | |
| 1335 | + remaining_data_length); | |
| 1336 | + if (unlikely(ret)) { | |
| 1337 | + error = ret; | |
| 1338 | + goto done; | |
| 1339 | + } | |
| 1280 | 1340 | } |
| 1281 | 1341 | |
| 1282 | 1342 | done: |
| 1283 | 1343 | ret = smb_direct_flush_send_list(st, &send_ctx, true); |
| 1344 | + if (unlikely(!ret && error)) | |
| 1345 | + ret = error; | |
| 1284 | 1346 | |
| 1285 | 1347 | /* |
| 1286 | 1348 | * As an optimization, we don't wait for individual I/O to finish |
| @@ -1744,6 +1806,11 @@ static int smb_direct_init_params(struct smb_direct_transport *t, · 457 unmodified lines | ||
| 1744 | 1806 | return -EINVAL; |
| 1745 | 1807 | } |
| 1746 | 1808 | |
| 1809 | + if (device->attrs.max_send_sge < SMB_DIRECT_MAX_SEND_SGES) { | |
| 1810 | + pr_err("warning: device max_send_sge = %d too small\n", | |
| 1811 | + device->attrs.max_send_sge); | |
| 1812 | + return -EINVAL; | |
| 1813 | + } | |
| 1747 | 1814 | if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { |
| 1748 | 1815 | pr_err("warning: device max_recv_sge = %d too small\n", |
| 1749 | 1816 | device->attrs.max_recv_sge); |
| @@ -1767,7 +1834,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, · 17 unmodified lines | ||
| 1767 | 1834 | |
| 1768 | 1835 | cap->max_send_wr = max_send_wrs; |
| 1769 | 1836 | cap->max_recv_wr = t->recv_credit_max; |
| 1770 | − cap->max_send_sge = max_sge_per_wr; | |
| 1837 | + cap->max_send_sge = SMB_DIRECT_MAX_SEND_SGES; | |
| 1771 | 1838 | cap->max_recv_sge = SMB_DIRECT_MAX_RECV_SGES; |
| 1772 | 1839 | cap->max_inline_data = 0; |
| 1773 | 1840 | cap->max_rdma_ctxs = t->max_rw_credits; |
| @@ -8,8 +8,8 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <linux/bits.h> |
| 9 | 9 | #include <linux/kvm.h> |
| 10 | 10 | #include <linux/irqreturn.h> |
| 11 | −#include <linux/kref.h> | |
| 12 | 11 | #include <linux/mutex.h> |
| 12 | +#include <linux/refcount.h> | |
| 13 | 13 | #include <linux/spinlock.h> |
| 14 | 14 | #include <linux/static_key.h> |
| 15 | 15 | #include <linux/types.h> |
| @@ -139,10 +139,13 @@ struct vgic_irq { · 123 unmodified lines | ||
| 139 | 139 | bool pending_latch; /* The pending latch state used to calculate |
| 140 | 140 | * the pending state for both level |
| 141 | 141 | * and edge triggered IRQs. */ |
| 142 | − bool active; /* not used for LPIs */ | |
| 142 | + bool active; | |
| 143 | + bool pending_release; /* Used for LPIs only, unreferenced IRQ | |
| 144 | + * pending a release */ | |
| 145 | + | |
| 143 | 146 | bool enabled; |
| 144 | 147 | bool hw; /* Tied to HW IRQ */ |
| 145 | − struct kref refcount; /* Used for LPIs */ | |
| 148 | + refcount_t refcount; /* Used for LPIs */ | |
| 146 | 149 | u32 hwintid; /* HW INTID number */ |
| 147 | 150 | unsigned int host_irq; /* linux irq corresponding to hwintid */ |
| 148 | 151 | union { |
| @@ -636,6 +636,7 @@ struct damon_operations { · 635 unmodified lines | ||
| 636 | 636 | * @data: Data that will be passed to @fn. |
| 637 | 637 | * @repeat: Repeat invocations. |
| 638 | 638 | * @return_code: Return code from @fn invocation. |
| 639 | + * @dealloc_on_cancel: De-allocate when canceled. | |
| 639 | 640 | * |
| 640 | 641 | * Control damon_call(), which requests specific kdamond to invoke a given |
| 641 | 642 | * function. Refer to damon_call() for more details. |
| @@ -645,6 +646,7 @@ struct damon_call_control { · 3 unmodified lines | ||
| 645 | 646 | void *data; |
| 646 | 647 | bool repeat; |
| 647 | 648 | int return_code; |
| 649 | + bool dealloc_on_cancel; | |
| 648 | 650 | /* private: internal use only */ |
| 649 | 651 | /* informs if the kdamond finished handling of the request */ |
| 650 | 652 | struct completion completion; |
| @@ -665,6 +665,7 @@ struct mlx5e_resources { · 664 unmodified lines | ||
| 665 | 665 | bool tisn_valid; |
| 666 | 666 | } hw_objs; |
| 667 | 667 | struct net_device *uplink_netdev; |
| 668 | + netdevice_tracker tracker; | |
| 668 | 669 | struct mutex uplink_netdev_lock; |
| 669 | 670 | struct mlx5_crypto_dek_priv *dek_priv; |
| 670 | 671 | }; |
| @@ -385,6 +385,16 @@ void folio_add_lru_vma(struct folio *, struct vm_area_struct *); · 384 unmodified lines | ||
| 385 | 385 | void mark_page_accessed(struct page *); |
| 386 | 386 | void folio_mark_accessed(struct folio *); |
| 387 | 387 | |
| 388 | +static inline bool folio_may_be_lru_cached(struct folio *folio) | |
| 389 | +{ | |
| 390 | + /* | |
| 391 | + * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting. | |
| 392 | + * Holding small numbers of low-order mTHP folios in per-CPU LRU cache | |
| 393 | + * will be sensible, but nobody has implemented and tested that yet. | |
| 394 | + */ | |
| 395 | + return !folio_test_large(folio); | |
| 396 | +} | |
| 397 | + | |
| 388 | 398 | extern atomic_t lru_disable_count; |
| 389 | 399 | |
| 390 | 400 | static inline bool lru_cache_disabled(void) |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | #define __NET_DST_METADATA_H 1 |
| 4 | 4 | |
| 5 | 5 | #include <linux/skbuff.h> |
| 6 | +#include <net/ip.h> | |
| 6 | 7 | #include <net/ip_tunnels.h> |
| 7 | 8 | #include <net/macsec.h> |
| 8 | 9 | #include <net/dst.h> |
| @@ -220,9 +221,15 @@ static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb, · 211 unmodified lines | ||
| 220 | 221 | int md_size) |
| 221 | 222 | { |
| 222 | 223 | const struct iphdr *iph = ip_hdr(skb); |
| 224 | + struct metadata_dst *tun_dst; | |
| 225 | + | |
| 226 | + tun_dst = __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl, | |
| 227 | + 0, flags, tunnel_id, md_size); | |
| 223 | 228 | |
| 224 | − return __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl, | |
| 225 | − 0, flags, tunnel_id, md_size); | |
| 229 | + if (tun_dst && (iph->frag_off & htons(IP_DF))) | |
| 230 | + __set_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, | |
| 231 | + tun_dst->u.tun_info.key.tun_flags); | |
| 232 | + return tun_dst; | |
| 226 | 233 | } |
| 227 | 234 | |
| 228 | 235 | static inline struct metadata_dst *__ipv6_tun_set_dst(const struct in6_addr *saddr, |
| @@ -2067,6 +2067,9 @@ static inline void sk_set_socket(struct sock *sk, struct socket *sock) · 2066 unmodified lines | ||
| 2067 | 2067 | if (sock) { |
| 2068 | 2068 | WRITE_ONCE(sk->sk_uid, SOCK_INODE(sock)->i_uid); |
| 2069 | 2069 | WRITE_ONCE(sk->sk_ino, SOCK_INODE(sock)->i_ino); |
| 2070 | + } else { | |
| 2071 | + /* Note: sk_uid is unchanged. */ | |
| 2072 | + WRITE_ONCE(sk->sk_ino, 0); | |
| 2070 | 2073 | } |
| 2071 | 2074 | } |
| 2072 | 2075 | |
| @@ -2088,8 +2091,6 @@ static inline void sock_orphan(struct sock *sk) · 15 unmodified lines | ||
| 2088 | 2091 | sock_set_flag(sk, SOCK_DEAD); |
| 2089 | 2092 | sk_set_socket(sk, NULL); |
| 2090 | 2093 | sk->sk_wq = NULL; |
| 2091 | − /* Note: sk_uid is unchanged. */ | |
| 2092 | − WRITE_ONCE(sk->sk_ino, 0); | |
| 2093 | 2094 | write_unlock_bh(&sk->sk_callback_lock); |
| 2094 | 2095 | } |
| 2095 | 2096 | |
| @@ -31,6 +31,8 @@ · 30 unmodified lines | ||
| 31 | 31 | #define MPTCP_INFO_FLAG_FALLBACK _BITUL(0) |
| 32 | 32 | #define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED _BITUL(1) |
| 33 | 33 | |
| 34 | +#define MPTCP_PM_EV_FLAG_DENY_JOIN_ID0 _BITUL(0) | |
| 35 | + | |
| 34 | 36 | #define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0) |
| 35 | 37 | #define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1) |
| 36 | 38 | #define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) |
| @@ -16,10 +16,10 @@ · 15 unmodified lines | ||
| 16 | 16 | * good time to allocate memory and send ADD_ADDR if needed. Depending on the |
| 17 | 17 | * traffic-patterns it can take a long time until the MPTCP_EVENT_ESTABLISHED |
| 18 | 18 | * is sent. Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, |
| 19 | − * sport, dport, server-side. | |
| 19 | + * sport, dport, server-side, [flags]. | |
| 20 | 20 | * @MPTCP_EVENT_ESTABLISHED: A MPTCP connection is established (can start new |
| 21 | 21 | * subflows). Attributes: token, family, saddr4 | saddr6, daddr4 | daddr6, |
| 22 | − * sport, dport, server-side. | |
| 22 | + * sport, dport, server-side, [flags]. | |
| 23 | 23 | * @MPTCP_EVENT_CLOSED: A MPTCP connection has stopped. Attribute: token. |
| 24 | 24 | * @MPTCP_EVENT_ANNOUNCED: A new address has been announced by the peer. |
| 25 | 25 | * Attributes: token, rem_id, family, daddr4 | daddr6 [, dport]. |
| @@ -126,8 +126,31 @@ DEFINE_PERCPU_RWSEM(cgroup_threadgroup_rwsem); · 125 unmodified lines | ||
| 126 | 126 | * of concurrent destructions. Use a separate workqueue so that cgroup |
| 127 | 127 | * destruction work items don't end up filling up max_active of system_wq |
| 128 | 128 | * which may lead to deadlock. |
| 129 | + * | |
| 130 | + * A cgroup destruction should enqueue work sequentially to: | |
| 131 | + * cgroup_offline_wq: use for css offline work | |
| 132 | + * cgroup_release_wq: use for css release work | |
| 133 | + * cgroup_free_wq: use for free work | |
| 134 | + * | |
| 135 | + * Rationale for using separate workqueues: | |
| 136 | + * The cgroup root free work may depend on completion of other css offline | |
| 137 | + * operations. If all tasks were enqueued to a single workqueue, this could | |
| 138 | + * create a deadlock scenario where: | |
| 139 | + * - Free work waits for other css offline work to complete. | |
| 140 | + * - But other css offline work is queued after free work in the same queue. | |
| 141 | + * | |
| 142 | + * Example deadlock scenario with single workqueue (cgroup_destroy_wq): | |
| 143 | + * 1. umount net_prio | |
| 144 | + * 2. net_prio root destruction enqueues work to cgroup_destroy_wq (CPUx) | |
| 145 | + * 3. perf_event CSS A offline enqueues work to same cgroup_destroy_wq (CPUx) | |
| 146 | + * 4. net_prio cgroup_destroy_root->cgroup_lock_and_drain_offline. | |
| 147 | + * 5. net_prio root destruction blocks waiting for perf_event CSS A offline, | |
| 148 | + * which can never complete as it's behind in the same queue and | |
| 149 | + * workqueue's max_active is 1. | |
| 129 | 150 | */ |
| 130 | −static struct workqueue_struct *cgroup_destroy_wq; | |
| 151 | +static struct workqueue_struct *cgroup_offline_wq; | |
| 152 | +static struct workqueue_struct *cgroup_release_wq; | |
| 153 | +static struct workqueue_struct *cgroup_free_wq; | |
| 131 | 154 | |
| 132 | 155 | /* generate an array of cgroup subsystem pointers */ |
| 133 | 156 | #define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys, |
| @@ -4159,6 +4182,7 @@ static void cgroup_file_release(struct kernfs_open_file *of) · 4025 unmodified lines | ||
| 4159 | 4182 | cft->release(of); |
| 4160 | 4183 | put_cgroup_ns(ctx->ns); |
| 4161 | 4184 | kfree(ctx); |
| 4185 | + of->priv = NULL; | |
| 4162 | 4186 | } |
| 4163 | 4187 | |
| 4164 | 4188 | static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, |
| @@ -5558,7 +5582,7 @@ static void css_release_work_fn(struct work_struct *work) · 1393 unmodified lines | ||
| 5558 | 5582 | cgroup_unlock(); |
| 5559 | 5583 | |
| 5560 | 5584 | INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn); |
| 5561 | − queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork); | |
| 5585 | + queue_rcu_work(cgroup_free_wq, &css->destroy_rwork); | |
| 5562 | 5586 | } |
| 5563 | 5587 | |
| 5564 | 5588 | static void css_release(struct percpu_ref *ref) |
| @@ -5567,7 +5591,7 @@ static void css_release(struct percpu_ref *ref) · 2 unmodified lines | ||
| 5567 | 5591 | container_of(ref, struct cgroup_subsys_state, refcnt); |
| 5568 | 5592 | |
| 5569 | 5593 | INIT_WORK(&css->destroy_work, css_release_work_fn); |
| 5570 | − queue_work(cgroup_destroy_wq, &css->destroy_work); | |
| 5594 | + queue_work(cgroup_release_wq, &css->destroy_work); | |
| 5571 | 5595 | } |
| 5572 | 5596 | |
| 5573 | 5597 | static void init_and_link_css(struct cgroup_subsys_state *css, |
| @@ -5701,7 +5725,7 @@ err_list_del: · 127 unmodified lines | ||
| 5701 | 5725 | list_del_rcu(&css->sibling); |
| 5702 | 5726 | err_free_css: |
| 5703 | 5727 | INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn); |
| 5704 | − queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork); | |
| 5728 | + queue_rcu_work(cgroup_free_wq, &css->destroy_rwork); | |
| 5705 | 5729 | return ERR_PTR(err); |
| 5706 | 5730 | } |
| 5707 | 5731 | |
| @@ -5939,7 +5963,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref) · 231 unmodified lines | ||
| 5939 | 5963 | |
| 5940 | 5964 | if (atomic_dec_and_test(&css->online_cnt)) { |
| 5941 | 5965 | INIT_WORK(&css->destroy_work, css_killed_work_fn); |
| 5942 | − queue_work(cgroup_destroy_wq, &css->destroy_work); | |
| 5966 | + queue_work(cgroup_offline_wq, &css->destroy_work); | |
| 5943 | 5967 | } |
| 5944 | 5968 | } |
| 5945 | 5969 | |
| @@ -6325,8 +6349,14 @@ static int __init cgroup_wq_init(void) · 379 unmodified lines | ||
| 6325 | 6349 | * We would prefer to do this in cgroup_init() above, but that |
| 6326 | 6350 | * is called before init_workqueues(): so leave this until after. |
| 6327 | 6351 | */ |
| 6328 | − cgroup_destroy_wq = alloc_workqueue("cgroup_destroy", 0, 1); | |
| 6329 | − BUG_ON(!cgroup_destroy_wq); | |
| 6352 | + cgroup_offline_wq = alloc_workqueue("cgroup_offline", 0, 1); | |
| 6353 | + BUG_ON(!cgroup_offline_wq); | |
| 6354 | + | |
| 6355 | + cgroup_release_wq = alloc_workqueue("cgroup_release", 0, 1); | |
| 6356 | + BUG_ON(!cgroup_release_wq); | |
| 6357 | + | |
| 6358 | + cgroup_free_wq = alloc_workqueue("cgroup_free", 0, 1); | |
| 6359 | + BUG_ON(!cgroup_free_wq); | |
| 6330 | 6360 | return 0; |
| 6331 | 6361 | } |
| 6332 | 6362 | core_initcall(cgroup_wq_init); |
| @@ -9551,7 +9551,7 @@ static unsigned long tg_weight(struct task_group *tg) · 9550 unmodified lines | ||
| 9551 | 9551 | #ifdef CONFIG_FAIR_GROUP_SCHED |
| 9552 | 9552 | return scale_load_down(tg->shares); |
| 9553 | 9553 | #else |
| 9554 | − return sched_weight_from_cgroup(tg->scx_weight); | |
| 9554 | + return sched_weight_from_cgroup(tg->scx.weight); | |
| 9555 | 9555 | #endif |
| 9556 | 9556 | } |
| 9557 | 9557 | |
| @@ -6788,12 +6788,8 @@ __bpf_kfunc u32 scx_bpf_reenqueue_local(void) · 6787 unmodified lines | ||
| 6788 | 6788 | * CPUs disagree, they use %ENQUEUE_RESTORE which is bypassed to |
| 6789 | 6789 | * the current local DSQ for running tasks and thus are not |
| 6790 | 6790 | * visible to the BPF scheduler. |
| 6791 | − * | |
| 6792 | − * Also skip re-enqueueing tasks that can only run on this | |
| 6793 | − * CPU, as they would just be re-added to the same local | |
| 6794 | − * DSQ without any benefit. | |
| 6795 | 6791 | */ |
| 6796 | − if (p->migration_pending || is_migration_disabled(p) || p->nr_cpus_allowed == 1) | |
| 6792 | + if (p->migration_pending) | |
| 6797 | 6793 | continue; |
| 6798 | 6794 | |
| 6799 | 6795 | dispatch_dequeue(rq, p); |
| @@ -787,10 +787,10 @@ static void retrigger_next_event(void *arg) · 786 unmodified lines | ||
| 787 | 787 | * of the next expiring timer is enough. The return from the SMP |
| 788 | 788 | * function call will take care of the reprogramming in case the |
| 789 | 789 | * CPU was in a NOHZ idle sleep. |
| 790 | + * | |
| 791 | + * In periodic low resolution mode, the next softirq expiration | |
| 792 | + * must also be updated. | |
| 790 | 793 | */ |
| 791 | − if (!hrtimer_hres_active(base) && !tick_nohz_active) | |
| 792 | − return; | |
| 793 | − | |
| 794 | 794 | raw_spin_lock(&base->lock); |
| 795 | 795 | hrtimer_update_base(base); |
| 796 | 796 | if (hrtimer_hres_active(base)) |
| @@ -2295,11 +2295,6 @@ int hrtimers_cpu_dying(unsigned int dying_cpu) · 1498 unmodified lines | ||
| 2295 | 2295 | &new_base->clock_base[i]); |
| 2296 | 2296 | } |
| 2297 | 2297 | |
| 2298 | − /* | |
| 2299 | − * The migration might have changed the first expiring softirq | |
| 2300 | − * timer on this CPU. Update it. | |
| 2301 | − */ | |
| 2302 | − __hrtimer_get_next_event(new_base, HRTIMER_ACTIVE_SOFT); | |
| 2303 | 2298 | /* Tell the other CPU to retrigger the next event */ |
| 2304 | 2299 | smp_call_function_single(ncpu, retrigger_next_event, NULL, 0); |
| 2305 | 2300 | |
| @@ -908,6 +908,8 @@ static int trace_kprobe_create_internal(int argc, const char *argv[], · 907 unmodified lines | ||
| 908 | 908 | return -EINVAL; |
| 909 | 909 | } |
| 910 | 910 | buf = kmemdup(&argv[0][1], len + 1, GFP_KERNEL); |
| 911 | + if (!buf) | |
| 912 | + return -ENOMEM; | |
| 911 | 913 | buf[len] = '\0'; |
| 912 | 914 | ret = kstrtouint(buf, 0, &maxactive); |
| 913 | 915 | if (ret || !maxactive) { |
| @@ -2479,10 +2479,14 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel) · 2478 unmodified lines | ||
| 2479 | 2479 | mutex_lock(&ctx->call_controls_lock); |
| 2480 | 2480 | list_del(&control->list); |
| 2481 | 2481 | mutex_unlock(&ctx->call_controls_lock); |
| 2482 | − if (!control->repeat) | |
| 2482 | + if (!control->repeat) { | |
| 2483 | 2483 | complete(&control->completion); |
| 2484 | − else | |
| 2484 | + } else if (control->canceled && control->dealloc_on_cancel) { | |
| 2485 | + kfree(control); | |
| 2486 | + continue; | |
| 2487 | + } else { | |
| 2485 | 2488 | list_add(&control->list, &repeat_controls); |
| 2489 | + } | |
| 2486 | 2490 | } |
| 2487 | 2491 | control = list_first_entry_or_null(&repeat_controls, |
| 2488 | 2492 | struct damon_call_control, list); |
| @@ -1534,14 +1534,10 @@ static int damon_sysfs_repeat_call_fn(void *data) · 1533 unmodified lines | ||
| 1534 | 1534 | return 0; |
| 1535 | 1535 | } |
| 1536 | 1536 | |
| 1537 | −static struct damon_call_control damon_sysfs_repeat_call_control = { | |
| 1538 | − .fn = damon_sysfs_repeat_call_fn, | |
| 1539 | − .repeat = true, | |
| 1540 | −}; | |
| 1541 | − | |
| 1542 | 1537 | static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond) |
| 1543 | 1538 | { |
| 1544 | 1539 | struct damon_ctx *ctx; |
| 1540 | + struct damon_call_control *repeat_call_control; | |
| 1545 | 1541 | int err; |
| 1546 | 1542 | |
| 1547 | 1543 | if (damon_sysfs_kdamond_running(kdamond)) |
| @@ -1554,18 +1550,29 @@ static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond) · 6 unmodified lines | ||
| 1554 | 1550 | damon_destroy_ctx(kdamond->damon_ctx); |
| 1555 | 1551 | kdamond->damon_ctx = NULL; |
| 1556 | 1552 | |
| 1553 | + repeat_call_control = kmalloc(sizeof(*repeat_call_control), | |
| 1554 | + GFP_KERNEL); | |
| 1555 | + if (!repeat_call_control) | |
| 1556 | + return -ENOMEM; | |
| 1557 | + | |
| 1557 | 1558 | ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]); |
| 1558 | − if (IS_ERR(ctx)) | |
| 1559 | + if (IS_ERR(ctx)) { | |
| 1560 | + kfree(repeat_call_control); | |
| 1559 | 1561 | return PTR_ERR(ctx); |
| 1562 | + } | |
| 1560 | 1563 | err = damon_start(&ctx, 1, false); |
| 1561 | 1564 | if (err) { |
| 1565 | + kfree(repeat_call_control); | |
| 1562 | 1566 | damon_destroy_ctx(ctx); |
| 1563 | 1567 | return err; |
| 1564 | 1568 | } |
| 1565 | 1569 | kdamond->damon_ctx = ctx; |
| 1566 | 1570 | |
| 1567 | − damon_sysfs_repeat_call_control.data = kdamond; | |
| 1568 | − damon_call(ctx, &damon_sysfs_repeat_call_control); | |
| 1571 | + repeat_call_control->fn = damon_sysfs_repeat_call_fn; | |
| 1572 | + repeat_call_control->data = kdamond; | |
| 1573 | + repeat_call_control->repeat = true; | |
| 1574 | + repeat_call_control->dealloc_on_cancel = true; | |
| 1575 | + damon_call(ctx, repeat_call_control); | |
| 1569 | 1576 | return err; |
| 1570 | 1577 | } |
| 1571 | 1578 | |
| @@ -2287,8 +2287,8 @@ static unsigned long collect_longterm_unpinnable_folios( · 2286 unmodified lines | ||
| 2287 | 2287 | struct pages_or_folios *pofs) |
| 2288 | 2288 | { |
| 2289 | 2289 | unsigned long collected = 0; |
| 2290 | − bool drain_allow = true; | |
| 2291 | 2290 | struct folio *folio; |
| 2291 | + int drained = 0; | |
| 2292 | 2292 | long i = 0; |
| 2293 | 2293 | |
| 2294 | 2294 | for (folio = pofs_get_folio(pofs, i); folio; |
| @@ -2307,9 +2307,17 @@ static unsigned long collect_longterm_unpinnable_folios( · 12 unmodified lines | ||
| 2307 | 2307 | continue; |
| 2308 | 2308 | } |
| 2309 | 2309 | |
| 2310 | − if (!folio_test_lru(folio) && drain_allow) { | |
| 2310 | + if (drained == 0 && folio_may_be_lru_cached(folio) && | |
| 2311 | + folio_ref_count(folio) != | |
| 2312 | + folio_expected_ref_count(folio) + 1) { | |
| 2313 | + lru_add_drain(); | |
| 2314 | + drained = 1; | |
| 2315 | + } | |
| 2316 | + if (drained == 1 && folio_may_be_lru_cached(folio) && | |
| 2317 | + folio_ref_count(folio) != | |
| 2318 | + folio_expected_ref_count(folio) + 1) { | |
| 2311 | 2319 | lru_add_drain_all(); |
| 2312 | − drain_allow = false; | |
| 2320 | + drained = 2; | |
| 2313 | 2321 | } |
| 2314 | 2322 | |
| 2315 | 2323 | if (!folio_isolate_lru(folio)) |
| @@ -255,7 +255,7 @@ void mlock_folio(struct folio *folio) · 254 unmodified lines | ||
| 255 | 255 | |
| 256 | 256 | folio_get(folio); |
| 257 | 257 | if (!folio_batch_add(fbatch, mlock_lru(folio)) || |
| 258 | − folio_test_large(folio) || lru_cache_disabled()) | |
| 258 | + !folio_may_be_lru_cached(folio) || lru_cache_disabled()) | |
| 259 | 259 | mlock_folio_batch(fbatch); |
| 260 | 260 | local_unlock(&mlock_fbatch.lock); |
| 261 | 261 | } |
| @@ -278,7 +278,7 @@ void mlock_new_folio(struct folio *folio) · 16 unmodified lines | ||
| 278 | 278 | |
| 279 | 279 | folio_get(folio); |
| 280 | 280 | if (!folio_batch_add(fbatch, mlock_new(folio)) || |
| 281 | − folio_test_large(folio) || lru_cache_disabled()) | |
| 281 | + !folio_may_be_lru_cached(folio) || lru_cache_disabled()) | |
| 282 | 282 | mlock_folio_batch(fbatch); |
| 283 | 283 | local_unlock(&mlock_fbatch.lock); |
| 284 | 284 | } |
| @@ -299,7 +299,7 @@ void munlock_folio(struct folio *folio) · 14 unmodified lines | ||
| 299 | 299 | */ |
| 300 | 300 | folio_get(folio); |
| 301 | 301 | if (!folio_batch_add(fbatch, folio) || |
| 302 | − folio_test_large(folio) || lru_cache_disabled()) | |
| 302 | + !folio_may_be_lru_cached(folio) || lru_cache_disabled()) | |
| 303 | 303 | mlock_folio_batch(fbatch); |
| 304 | 304 | local_unlock(&mlock_fbatch.lock); |
| 305 | 305 | } |
| @@ -164,6 +164,10 @@ static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn) · 163 unmodified lines | ||
| 164 | 164 | for (i = 0; i < folio_batch_count(fbatch); i++) { |
| 165 | 165 | struct folio *folio = fbatch->folios[i]; |
| 166 | 166 | |
| 167 | + /* block memcg migration while the folio moves between lru */ | |
| 168 | + if (move_fn != lru_add && !folio_test_clear_lru(folio)) | |
| 169 | + continue; | |
| 170 | + | |
| 167 | 171 | folio_lruvec_relock_irqsave(folio, &lruvec, &flags); |
| 168 | 172 | move_fn(lruvec, folio); |
| 169 | 173 | |
| @@ -176,14 +180,10 @@ static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn) · 6 unmodified lines | ||
| 176 | 180 | } |
| 177 | 181 | |
| 178 | 182 | static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch, |
| 179 | − struct folio *folio, move_fn_t move_fn, | |
| 180 | − bool on_lru, bool disable_irq) | |
| 183 | + struct folio *folio, move_fn_t move_fn, bool disable_irq) | |
| 181 | 184 | { |
| 182 | 185 | unsigned long flags; |
| 183 | 186 | |
| 184 | − if (on_lru && !folio_test_clear_lru(folio)) | |
| 185 | − return; | |
| 186 | − | |
| 187 | 187 | folio_get(folio); |
| 188 | 188 | |
| 189 | 189 | if (disable_irq) |
| @@ -191,8 +191,8 @@ static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch, · 1 unmodified line | ||
| 191 | 191 | else |
| 192 | 192 | local_lock(&cpu_fbatches.lock); |
| 193 | 193 | |
| 194 | − if (!folio_batch_add(this_cpu_ptr(fbatch), folio) || folio_test_large(folio) || | |
| 195 | − lru_cache_disabled()) | |
| 194 | + if (!folio_batch_add(this_cpu_ptr(fbatch), folio) || | |
| 195 | + !folio_may_be_lru_cached(folio) || lru_cache_disabled()) | |
| 196 | 196 | folio_batch_move_lru(this_cpu_ptr(fbatch), move_fn); |
| 197 | 197 | |
| 198 | 198 | if (disable_irq) |
| @@ -201,13 +201,13 @@ static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch, · 2 unmodified lines | ||
| 201 | 201 | local_unlock(&cpu_fbatches.lock); |
| 202 | 202 | } |
| 203 | 203 | |
| 204 | −#define folio_batch_add_and_move(folio, op, on_lru) \ | |
| 205 | − __folio_batch_add_and_move( \ | |
| 206 | − &cpu_fbatches.op, \ | |
| 207 | − folio, \ | |
| 208 | − op, \ | |
| 209 | − on_lru, \ | |
| 210 | − offsetof(struct cpu_fbatches, op) >= offsetof(struct cpu_fbatches, lock_irq) \ | |
| 204 | +#define folio_batch_add_and_move(folio, op) \ | |
| 205 | + __folio_batch_add_and_move( \ | |
| 206 | + &cpu_fbatches.op, \ | |
| 207 | + folio, \ | |
| 208 | + op, \ | |
| 209 | + offsetof(struct cpu_fbatches, op) >= \ | |
| 210 | + offsetof(struct cpu_fbatches, lock_irq) \ | |
| 211 | 211 | ) |
| 212 | 212 | |
| 213 | 213 | static void lru_move_tail(struct lruvec *lruvec, struct folio *folio) |
| @@ -231,10 +231,10 @@ static void lru_move_tail(struct lruvec *lruvec, struct folio *folio) · 17 unmodified lines | ||
| 231 | 231 | void folio_rotate_reclaimable(struct folio *folio) |
| 232 | 232 | { |
| 233 | 233 | if (folio_test_locked(folio) || folio_test_dirty(folio) || |
| 234 | − folio_test_unevictable(folio)) | |
| 234 | + folio_test_unevictable(folio) || !folio_test_lru(folio)) | |
| 235 | 235 | return; |
| 236 | 236 | |
| 237 | − folio_batch_add_and_move(folio, lru_move_tail, true); | |
| 237 | + folio_batch_add_and_move(folio, lru_move_tail); | |
| 238 | 238 | } |
| 239 | 239 | |
| 240 | 240 | void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file, |
| @@ -328,10 +328,11 @@ static void folio_activate_drain(int cpu) · 87 unmodified lines | ||
| 328 | 328 | |
| 329 | 329 | void folio_activate(struct folio *folio) |
| 330 | 330 | { |
| 331 | − if (folio_test_active(folio) || folio_test_unevictable(folio)) | |
| 331 | + if (folio_test_active(folio) || folio_test_unevictable(folio) || | |
| 332 | + !folio_test_lru(folio)) | |
| 332 | 333 | return; |
| 333 | 334 | |
| 334 | − folio_batch_add_and_move(folio, lru_activate, true); | |
| 335 | + folio_batch_add_and_move(folio, lru_activate); | |
| 335 | 336 | } |
| 336 | 337 | |
| 337 | 338 | #else |
| @@ -507,7 +508,7 @@ void folio_add_lru(struct folio *folio) · 169 unmodified lines | ||
| 507 | 508 | lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) |
| 508 | 509 | folio_set_active(folio); |
| 509 | 510 | |
| 510 | − folio_batch_add_and_move(folio, lru_add, false); | |
| 511 | + folio_batch_add_and_move(folio, lru_add); | |
| 511 | 512 | } |
| 512 | 513 | EXPORT_SYMBOL(folio_add_lru); |
| 513 | 514 | |
| @@ -685,13 +686,13 @@ void lru_add_drain_cpu(int cpu) · 171 unmodified lines | ||
| 685 | 686 | void deactivate_file_folio(struct folio *folio) |
| 686 | 687 | { |
| 687 | 688 | /* Deactivating an unevictable folio will not accelerate reclaim */ |
| 688 | − if (folio_test_unevictable(folio)) | |
| 689 | + if (folio_test_unevictable(folio) || !folio_test_lru(folio)) | |
| 689 | 690 | return; |
| 690 | 691 | |
| 691 | 692 | if (lru_gen_enabled() && lru_gen_clear_refs(folio)) |
| 692 | 693 | return; |
| 693 | 694 | |
| 694 | − folio_batch_add_and_move(folio, lru_deactivate_file, true); | |
| 695 | + folio_batch_add_and_move(folio, lru_deactivate_file); | |
| 695 | 696 | } |
| 696 | 697 | |
| 697 | 698 | /* |
| @@ -704,13 +705,13 @@ void deactivate_file_folio(struct folio *folio) · 6 unmodified lines | ||
| 704 | 705 | */ |
| 705 | 706 | void folio_deactivate(struct folio *folio) |
| 706 | 707 | { |
| 707 | − if (folio_test_unevictable(folio)) | |
| 708 | + if (folio_test_unevictable(folio) || !folio_test_lru(folio)) | |
| 708 | 709 | return; |
| 709 | 710 | |
| 710 | 711 | if (lru_gen_enabled() ? lru_gen_clear_refs(folio) : !folio_test_active(folio)) |
| 711 | 712 | return; |
| 712 | 713 | |
| 713 | − folio_batch_add_and_move(folio, lru_deactivate, true); | |
| 714 | + folio_batch_add_and_move(folio, lru_deactivate); | |
| 714 | 715 | } |
| 715 | 716 | |
| 716 | 717 | /** |
| @@ -723,10 +724,11 @@ void folio_deactivate(struct folio *folio) · 6 unmodified lines | ||
| 723 | 724 | void folio_mark_lazyfree(struct folio *folio) |
| 724 | 725 | { |
| 725 | 726 | if (!folio_test_anon(folio) || !folio_test_swapbacked(folio) || |
| 727 | + !folio_test_lru(folio) || | |
| 726 | 728 | folio_test_swapcache(folio) || folio_test_unevictable(folio)) |
| 727 | 729 | return; |
| 728 | 730 | |
| 729 | − folio_batch_add_and_move(folio, lru_lazyfree, true); | |
| 731 | + folio_batch_add_and_move(folio, lru_lazyfree); | |
| 730 | 732 | } |
| 731 | 733 | |
| 732 | 734 | void lru_add_drain(void) |
| @@ -4507,7 +4507,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c · 4506 unmodified lines | ||
| 4507 | 4507 | } |
| 4508 | 4508 | |
| 4509 | 4509 | /* ineligible */ |
| 4510 | − if (!folio_test_lru(folio) || zone > sc->reclaim_idx) { | |
| 4510 | + if (zone > sc->reclaim_idx) { | |
| 4511 | 4511 | gen = folio_inc_gen(lruvec, folio, false); |
| 4512 | 4512 | list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]); |
| 4513 | 4513 | return true; |
| @@ -1524,7 +1524,7 @@ static void con_fault_finish(struct ceph_connection *con) · 1523 unmodified lines | ||
| 1524 | 1524 | * in case we faulted due to authentication, invalidate our |
| 1525 | 1525 | * current tickets so that we can get new ones. |
| 1526 | 1526 | */ |
| 1527 | − if (con->v1.auth_retry) { | |
| 1527 | + if (!ceph_msgr2(from_msgr(con->msgr)) && con->v1.auth_retry) { | |
| 1528 | 1528 | dout("auth_retry %d, invalidating\n", con->v1.auth_retry); |
| 1529 | 1529 | if (con->ops->invalidate_authorizer) |
| 1530 | 1530 | con->ops->invalidate_authorizer(con); |
| @@ -1714,9 +1714,10 @@ static void clear_standby(struct ceph_connection *con) · 183 unmodified lines | ||
| 1714 | 1714 | { |
| 1715 | 1715 | /* come back from STANDBY? */ |
| 1716 | 1716 | if (con->state == CEPH_CON_S_STANDBY) { |
| 1717 | − dout("clear_standby %p and ++connect_seq\n", con); | |
| 1717 | + dout("clear_standby %p\n", con); | |
| 1718 | 1718 | con->state = CEPH_CON_S_PREOPEN; |
| 1719 | − con->v1.connect_seq++; | |
| 1719 | + if (!ceph_msgr2(from_msgr(con->msgr))) | |
| 1720 | + con->v1.connect_seq++; | |
| 1720 | 1721 | WARN_ON(ceph_con_flag_test(con, CEPH_CON_F_WRITE_PENDING)); |
| 1721 | 1722 | WARN_ON(ceph_con_flag_test(con, CEPH_CON_F_KEEPALIVE_PENDING)); |
| 1722 | 1723 | } |
| @@ -7046,7 +7046,7 @@ static void napi_stop_kthread(struct napi_struct *napi) · 7045 unmodified lines | ||
| 7046 | 7046 | * the kthread. |
| 7047 | 7047 | */ |
| 7048 | 7048 | while (true) { |
| 7049 | − if (!test_bit(NAPIF_STATE_SCHED_THREADED, &napi->state)) | |
| 7049 | + if (!test_bit(NAPI_STATE_SCHED_THREADED, &napi->state)) | |
| 7050 | 7050 | break; |
| 7051 | 7051 | |
| 7052 | 7052 | msleep(20); |
| @@ -34,7 +34,7 @@ devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info) · 33 unmodified lines | ||
| 34 | 34 | static struct devlink_rate * |
| 35 | 35 | devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name) |
| 36 | 36 | { |
| 37 | − static struct devlink_rate *devlink_rate; | |
| 37 | + struct devlink_rate *devlink_rate; | |
| 38 | 38 | |
| 39 | 39 | list_for_each_entry(devlink_rate, &devlink->rate_list, list) { |
| 40 | 40 | if (devlink_rate_is_node(devlink_rate) && |
| @@ -819,8 +819,8 @@ EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy); · 778 unmodified lines | ||
| 819 | 819 | */ |
| 820 | 820 | void devl_rate_nodes_destroy(struct devlink *devlink) |
| 821 | 821 | { |
| 822 | − static struct devlink_rate *devlink_rate, *tmp; | |
| 823 | 822 | const struct devlink_ops *ops = devlink->ops; |
| 823 | + struct devlink_rate *devlink_rate, *tmp; | |
| 824 | 824 | |
| 825 | 825 | devl_assert_locked(devlink); |
| 826 | 826 | |
| @@ -925,7 +925,7 @@ int ethtool_net_get_ts_info_by_phc(struct net_device *dev, · 924 unmodified lines | ||
| 925 | 925 | int err; |
| 926 | 926 | |
| 927 | 927 | if (!ops->get_ts_info) |
| 928 | − return -ENODEV; | |
| 928 | + return -EOPNOTSUPP; | |
| 929 | 929 | |
| 930 | 930 | /* Does ptp comes from netdev */ |
| 931 | 931 | ethtool_init_tsinfo(info); |
| @@ -993,7 +993,7 @@ int ethtool_get_ts_info_by_phc(struct net_device *dev, · 61 unmodified lines | ||
| 993 | 993 | int err; |
| 994 | 994 | |
| 995 | 995 | err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc); |
| 996 | − if (err == -ENODEV) { | |
| 996 | + if (err == -ENODEV || err == -EOPNOTSUPP) { | |
| 997 | 997 | struct phy_device *phy; |
| 998 | 998 | |
| 999 | 999 | phy = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc); |
| @@ -3348,6 +3348,7 @@ int tcp_disconnect(struct sock *sk, int flags) · 3347 unmodified lines | ||
| 3348 | 3348 | struct inet_connection_sock *icsk = inet_csk(sk); |
| 3349 | 3349 | struct tcp_sock *tp = tcp_sk(sk); |
| 3350 | 3350 | int old_state = sk->sk_state; |
| 3351 | + struct request_sock *req; | |
| 3351 | 3352 | u32 seq; |
| 3352 | 3353 | |
| 3353 | 3354 | if (old_state != TCP_CLOSE) |
| @@ -3468,6 +3469,10 @@ int tcp_disconnect(struct sock *sk, int flags) · 114 unmodified lines | ||
| 3468 | 3469 | |
| 3469 | 3470 | |
| 3470 | 3471 | /* Clean up fastopen related fields */ |
| 3472 | + req = rcu_dereference_protected(tp->fastopen_rsk, | |
| 3473 | + lockdep_sock_is_held(sk)); | |
| 3474 | + if (req) | |
| 3475 | + reqsk_fastopen_remove(sk, req, false); | |
| 3471 | 3476 | tcp_free_fastopen_req(tp); |
| 3472 | 3477 | inet_clear_bit(DEFER_CONNECT, sk); |
| 3473 | 3478 | tp->fastopen_client_fail = 0; |
| @@ -1177,7 +1177,9 @@ void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb) · 1176 unmodified lines | ||
| 1177 | 1177 | if (!ao) |
| 1178 | 1178 | return; |
| 1179 | 1179 | |
| 1180 | − WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq); | |
| 1180 | + /* sk with TCP_REPAIR_ON does not have skb in tcp_finish_connect */ | |
| 1181 | + if (skb) | |
| 1182 | + WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq); | |
| 1181 | 1183 | ao->rcv_sne = 0; |
| 1182 | 1184 | |
| 1183 | 1185 | hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) |
| @@ -985,13 +985,13 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, · 984 unmodified lines | ||
| 985 | 985 | return false; |
| 986 | 986 | } |
| 987 | 987 | |
| 988 | − if (mp_opt->deny_join_id0) | |
| 989 | − WRITE_ONCE(msk->pm.remote_deny_join_id0, true); | |
| 990 | − | |
| 991 | 988 | if (unlikely(!READ_ONCE(msk->pm.server_side))) |
| 992 | 989 | pr_warn_once("bogus mpc option on established client sk"); |
| 993 | 990 | |
| 994 | 991 | set_fully_established: |
| 992 | + if (mp_opt->deny_join_id0) | |
| 993 | + WRITE_ONCE(msk->pm.remote_deny_join_id0, true); | |
| 994 | + | |
| 995 | 995 | mptcp_data_lock((struct sock *)msk); |
| 996 | 996 | __mptcp_subflow_fully_established(msk, subflow, mp_opt); |
| 997 | 997 | mptcp_data_unlock((struct sock *)msk); |
| @@ -408,6 +408,7 @@ static int mptcp_event_created(struct sk_buff *skb, · 407 unmodified lines | ||
| 408 | 408 | const struct sock *ssk) |
| 409 | 409 | { |
| 410 | 410 | int err = nla_put_u32(skb, MPTCP_ATTR_TOKEN, READ_ONCE(msk->token)); |
| 411 | + u16 flags = 0; | |
| 411 | 412 | |
| 412 | 413 | if (err) |
| 413 | 414 | return err; |
| @@ -415,6 +416,12 @@ static int mptcp_event_created(struct sk_buff *skb, · 1 unmodified line | ||
| 415 | 416 | if (nla_put_u8(skb, MPTCP_ATTR_SERVER_SIDE, READ_ONCE(msk->pm.server_side))) |
| 416 | 417 | return -EMSGSIZE; |
| 417 | 418 | |
| 419 | + if (READ_ONCE(msk->pm.remote_deny_join_id0)) | |
| 420 | + flags |= MPTCP_PM_EV_FLAG_DENY_JOIN_ID0; | |
| 421 | + | |
| 422 | + if (flags && nla_put_u16(skb, MPTCP_ATTR_FLAGS, flags)) | |
| 423 | + return -EMSGSIZE; | |
| 424 | + | |
| 418 | 425 | return mptcp_event_add_subflow(skb, ssk); |
| 419 | 426 | } |
| 420 | 427 | |
| @@ -372,6 +372,20 @@ static void mptcp_close_wake_up(struct sock *sk) · 371 unmodified lines | ||
| 372 | 372 | sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | +static void mptcp_shutdown_subflows(struct mptcp_sock *msk) | |
| 376 | +{ | |
| 377 | + struct mptcp_subflow_context *subflow; | |
| 378 | + | |
| 379 | + mptcp_for_each_subflow(msk, subflow) { | |
| 380 | + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); | |
| 381 | + bool slow; | |
| 382 | + | |
| 383 | + slow = lock_sock_fast(ssk); | |
| 384 | + tcp_shutdown(ssk, SEND_SHUTDOWN); | |
| 385 | + unlock_sock_fast(ssk, slow); | |
| 386 | + } | |
| 387 | +} | |
| 388 | + | |
| 375 | 389 | /* called under the msk socket lock */ |
| 376 | 390 | static bool mptcp_pending_data_fin_ack(struct sock *sk) |
| 377 | 391 | { |
| @@ -396,6 +410,7 @@ static void mptcp_check_data_fin_ack(struct sock *sk) · 18 unmodified lines | ||
| 396 | 410 | break; |
| 397 | 411 | case TCP_CLOSING: |
| 398 | 412 | case TCP_LAST_ACK: |
| 413 | + mptcp_shutdown_subflows(msk); | |
| 399 | 414 | mptcp_set_state(sk, TCP_CLOSE); |
| 400 | 415 | break; |
| 401 | 416 | } |
| @@ -564,6 +579,7 @@ static bool mptcp_check_data_fin(struct sock *sk) · 162 unmodified lines | ||
| 564 | 579 | mptcp_set_state(sk, TCP_CLOSING); |
| 565 | 580 | break; |
| 566 | 581 | case TCP_FIN_WAIT2: |
| 582 | + mptcp_shutdown_subflows(msk); | |
| 567 | 583 | mptcp_set_state(sk, TCP_CLOSE); |
| 568 | 584 | break; |
| 569 | 585 | default: |
| @@ -883,6 +883,10 @@ create_child: · 882 unmodified lines | ||
| 883 | 883 | |
| 884 | 884 | ctx->subflow_id = 1; |
| 885 | 885 | owner = mptcp_sk(ctx->conn); |
| 886 | + | |
| 887 | + if (mp_opt.deny_join_id0) | |
| 888 | + WRITE_ONCE(owner->pm.remote_deny_join_id0, true); | |
| 889 | + | |
| 886 | 890 | mptcp_pm_new_connection(owner, child, 1); |
| 887 | 891 | |
| 888 | 892 | /* with OoO packets we can reach here without ingress |
| @@ -133,12 +133,15 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr) · 132 unmodified lines | ||
| 133 | 133 | |
| 134 | 134 | ret = ib_map_mr_sg_zbva(frmr->mr, ibmr->sg, ibmr->sg_dma_len, |
| 135 | 135 | &off, PAGE_SIZE); |
| 136 | − if (unlikely(ret != ibmr->sg_dma_len)) | |
| 137 | − return ret < 0 ? ret : -EINVAL; | |
| 136 | + if (unlikely(ret != ibmr->sg_dma_len)) { | |
| 137 | + ret = ret < 0 ? ret : -EINVAL; | |
| 138 | + goto out_inc; | |
| 139 | + } | |
| 138 | 140 | |
| 139 | − if (cmpxchg(&frmr->fr_state, | |
| 140 | − FRMR_IS_FREE, FRMR_IS_INUSE) != FRMR_IS_FREE) | |
| 141 | − return -EBUSY; | |
| 141 | + if (cmpxchg(&frmr->fr_state, FRMR_IS_FREE, FRMR_IS_INUSE) != FRMR_IS_FREE) { | |
| 142 | + ret = -EBUSY; | |
| 143 | + goto out_inc; | |
| 144 | + } | |
| 142 | 145 | |
| 143 | 146 | atomic_inc(&ibmr->ic->i_fastreg_inuse_count); |
| 144 | 147 | |
| @@ -166,11 +169,10 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr) · 21 unmodified lines | ||
| 166 | 169 | /* Failure here can be because of -ENOMEM as well */ |
| 167 | 170 | rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE); |
| 168 | 171 | |
| 169 | − atomic_inc(&ibmr->ic->i_fastreg_wrs); | |
| 170 | 172 | if (printk_ratelimit()) |
| 171 | 173 | pr_warn("RDS/IB: %s returned error(%d)\n", |
| 172 | 174 | __func__, ret); |
| 173 | − goto out; | |
| 175 | + goto out_inc; | |
| 174 | 176 | } |
| 175 | 177 | |
| 176 | 178 | /* Wait for the registration to complete in order to prevent an invalid |
| @@ -179,8 +181,10 @@ static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr) · 2 unmodified lines | ||
| 179 | 181 | */ |
| 180 | 182 | wait_event(frmr->fr_reg_done, !frmr->fr_reg); |
| 181 | 183 | |
| 182 | −out: | |
| 184 | + return ret; | |
| 183 | 185 | |
| 186 | +out_inc: | |
| 187 | + atomic_inc(&ibmr->ic->i_fastreg_wrs); | |
| 184 | 188 | return ret; |
| 185 | 189 | } |
| 186 | 190 | |
| @@ -94,10 +94,10 @@ static const struct dmi_system_id rfkill_gpio_deny_table[] = { · 93 unmodified lines | ||
| 94 | 94 | static int rfkill_gpio_probe(struct platform_device *pdev) |
| 95 | 95 | { |
| 96 | 96 | struct rfkill_gpio_data *rfkill; |
| 97 | − struct gpio_desc *gpio; | |
| 97 | + const char *type_name = NULL; | |
| 98 | 98 | const char *name_property; |
| 99 | 99 | const char *type_property; |
| 100 | − const char *type_name; | |
| 100 | + struct gpio_desc *gpio; | |
| 101 | 101 | int ret; |
| 102 | 102 | |
| 103 | 103 | if (dmi_check_system(rfkill_gpio_deny_table)) |
| @@ -475,7 +475,7 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call, · 474 unmodified lines | ||
| 475 | 475 | struct krb5_buffer metadata; |
| 476 | 476 | unsigned int offset = sp->offset, len = sp->len; |
| 477 | 477 | size_t data_offset = 0, data_len = len; |
| 478 | − u32 ac; | |
| 478 | + u32 ac = 0; | |
| 479 | 479 | int ret = -ENOMEM; |
| 480 | 480 | |
| 481 | 481 | _enter(""); |
| @@ -499,9 +499,10 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call, · 17 unmodified lines | ||
| 499 | 499 | ret = rxgk_verify_mic_skb(gk->krb5, gk->rx_Kc, &metadata, |
| 500 | 500 | skb, &offset, &len, &ac); |
| 501 | 501 | kfree(hdr); |
| 502 | − if (ret == -EPROTO) { | |
| 503 | − rxrpc_abort_eproto(call, skb, ac, | |
| 504 | − rxgk_abort_1_verify_mic_eproto); | |
| 502 | + if (ret < 0) { | |
| 503 | + if (ret != -ENOMEM) | |
| 504 | + rxrpc_abort_eproto(call, skb, ac, | |
| 505 | + rxgk_abort_1_verify_mic_eproto); | |
| 505 | 506 | } else { |
| 506 | 507 | sp->offset = offset; |
| 507 | 508 | sp->len = len; |
| @@ -524,15 +525,16 @@ static int rxgk_verify_packet_encrypted(struct rxrpc_call *call, · 16 unmodified lines | ||
| 524 | 525 | struct rxgk_header hdr; |
| 525 | 526 | unsigned int offset = sp->offset, len = sp->len; |
| 526 | 527 | int ret; |
| 527 | − u32 ac; | |
| 528 | + u32 ac = 0; | |
| 528 | 529 | |
| 529 | 530 | _enter(""); |
| 530 | 531 | |
| 531 | 532 | ret = rxgk_decrypt_skb(gk->krb5, gk->rx_enc, skb, &offset, &len, &ac); |
| 532 | − if (ret == -EPROTO) | |
| 533 | − rxrpc_abort_eproto(call, skb, ac, rxgk_abort_2_decrypt_eproto); | |
| 534 | − if (ret < 0) | |
| 533 | + if (ret < 0) { | |
| 534 | + if (ret != -ENOMEM) | |
| 535 | + rxrpc_abort_eproto(call, skb, ac, rxgk_abort_2_decrypt_eproto); | |
| 535 | 536 | goto error; |
| 537 | + } | |
| 536 | 538 | |
| 537 | 539 | if (len < sizeof(hdr)) { |
| 538 | 540 | ret = rxrpc_abort_eproto(call, skb, RXGK_PACKETSHORT, |
| @@ -54,6 +54,10 @@ int rxgk_yfs_decode_ticket(struct rxrpc_connection *conn, struct sk_buff *skb, · 53 unmodified lines | ||
| 54 | 54 | |
| 55 | 55 | _enter(""); |
| 56 | 56 | |
| 57 | + if (ticket_len < 10 * sizeof(__be32)) | |
| 58 | + return rxrpc_abort_conn(conn, skb, RXGK_INCONSISTENCY, -EPROTO, | |
| 59 | + rxgk_abort_resp_short_yfs_tkt); | |
| 60 | + | |
| 57 | 61 | /* Get the session key length */ |
| 58 | 62 | ret = skb_copy_bits(skb, ticket_offset, tmp, sizeof(tmp)); |
| 59 | 63 | if (ret < 0) |
| @@ -187,7 +191,7 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, · 127 unmodified lines | ||
| 187 | 191 | struct key *server_key; |
| 188 | 192 | unsigned int ticket_offset, ticket_len; |
| 189 | 193 | u32 kvno, enctype; |
| 190 | − int ret, ec; | |
| 194 | + int ret, ec = 0; | |
| 191 | 195 | |
| 192 | 196 | struct { |
| 193 | 197 | __be32 kvno; |
| @@ -195,22 +199,23 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, · 1 unmodified line | ||
| 195 | 199 | __be32 token_len; |
| 196 | 200 | } container; |
| 197 | 201 | |
| 202 | + if (token_len < sizeof(container)) | |
| 203 | + goto short_packet; | |
| 204 | + | |
| 198 | 205 | /* Decode the RXGK_TokenContainer object. This tells us which server |
| 199 | 206 | * key we should be using. We can then fetch the key, get the secret |
| 200 | 207 | * and set up the crypto to extract the token. |
| 201 | 208 | */ |
| 202 | 209 | if (skb_copy_bits(skb, token_offset, &container, sizeof(container)) < 0) |
| 203 | − return rxrpc_abort_conn(conn, skb, RXGK_PACKETSHORT, -EPROTO, | |
| 204 | − rxgk_abort_resp_tok_short); | |
| 210 | + goto short_packet; | |
| 205 | 211 | |
| 206 | 212 | kvno = ntohl(container.kvno); |
| 207 | 213 | enctype = ntohl(container.enctype); |
| 208 | 214 | ticket_len = ntohl(container.token_len); |
| 209 | 215 | ticket_offset = token_offset + sizeof(container); |
| 210 | 216 | |
| 211 | − if (xdr_round_up(ticket_len) > token_len - 3 * 4) | |
| 212 | − return rxrpc_abort_conn(conn, skb, RXGK_PACKETSHORT, -EPROTO, | |
| 213 | − rxgk_abort_resp_tok_short); | |
| 217 | + if (xdr_round_up(ticket_len) > token_len - sizeof(container)) | |
| 218 | + goto short_packet; | |
| 214 | 219 | |
| 215 | 220 | _debug("KVNO %u", kvno); |
| 216 | 221 | _debug("ENC %u", enctype); |
| @@ -236,9 +241,11 @@ int rxgk_extract_token(struct rxrpc_connection *conn, struct sk_buff *skb, · 19 unmodified lines | ||
| 236 | 241 | &ticket_offset, &ticket_len, &ec); |
| 237 | 242 | crypto_free_aead(token_enc); |
| 238 | 243 | token_enc = NULL; |
| 239 | − if (ret < 0) | |
| 240 | − return rxrpc_abort_conn(conn, skb, ec, ret, | |
| 241 | − rxgk_abort_resp_tok_dec); | |
| 244 | + if (ret < 0) { | |
| 245 | + if (ret != -ENOMEM) | |
| 246 | + return rxrpc_abort_conn(conn, skb, ec, ret, | |
| 247 | + rxgk_abort_resp_tok_dec); | |
| 248 | + } | |
| 242 | 249 | |
| 243 | 250 | ret = conn->security->default_decode_ticket(conn, skb, ticket_offset, |
| 244 | 251 | ticket_len, _key); |
| @@ -283,4 +290,8 @@ temporary_error: · 38 unmodified lines | ||
| 283 | 290 | * also come out this way if the ticket decryption fails. |
| 284 | 291 | */ |
| 285 | 292 | return ret; |
| 293 | + | |
| 294 | +short_packet: | |
| 295 | + return rxrpc_abort_conn(conn, skb, RXGK_PACKETSHORT, -EPROTO, | |
| 296 | + rxgk_abort_resp_tok_short); | |
| 286 | 297 | } |
| @@ -88,11 +88,16 @@ int rxgk_decrypt_skb(const struct krb5_enctype *krb5, · 87 unmodified lines | ||
| 88 | 88 | *_offset += offset; |
| 89 | 89 | *_len = len; |
| 90 | 90 | break; |
| 91 | + case -EBADMSG: /* Checksum mismatch. */ | |
| 91 | 92 | case -EPROTO: |
| 92 | − case -EBADMSG: | |
| 93 | 93 | *_error_code = RXGK_SEALEDINCON; |
| 94 | 94 | break; |
| 95 | + case -EMSGSIZE: | |
| 96 | + *_error_code = RXGK_PACKETSHORT; | |
| 97 | + break; | |
| 98 | + case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */ | |
| 95 | 99 | default: |
| 100 | + *_error_code = RXGK_INCONSISTENCY; | |
| 96 | 101 | break; |
| 97 | 102 | } |
| 98 | 103 | |
| @@ -127,11 +132,16 @@ int rxgk_verify_mic_skb(const struct krb5_enctype *krb5, · 28 unmodified lines | ||
| 127 | 132 | *_offset += offset; |
| 128 | 133 | *_len = len; |
| 129 | 134 | break; |
| 135 | + case -EBADMSG: /* Checksum mismatch */ | |
| 130 | 136 | case -EPROTO: |
| 131 | − case -EBADMSG: | |
| 132 | 137 | *_error_code = RXGK_SEALEDINCON; |
| 133 | 138 | break; |
| 139 | + case -EMSGSIZE: | |
| 140 | + *_error_code = RXGK_PACKETSHORT; | |
| 141 | + break; | |
| 142 | + case -ENOPKG: /* Would prefer RXGK_BADETYPE, but not available for YFS. */ | |
| 134 | 143 | default: |
| 144 | + *_error_code = RXGK_INCONSISTENCY; | |
| 135 | 145 | break; |
| 136 | 146 | } |
| 137 | 147 | |
| @@ -141,6 +141,7 @@ void update_sk_prot(struct sock *sk, struct tls_context *ctx); · 140 unmodified lines | ||
| 141 | 141 | |
| 142 | 142 | int wait_on_pending_writer(struct sock *sk, long *timeo); |
| 143 | 143 | void tls_err_abort(struct sock *sk, int err); |
| 144 | +void tls_strp_abort_strp(struct tls_strparser *strp, int err); | |
| 144 | 145 | |
| 145 | 146 | int init_prot_info(struct tls_prot_info *prot, |
| 146 | 147 | const struct tls_crypto_info *crypto_info, |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | static struct workqueue_struct *tls_strp_wq; |
| 15 | 15 | |
| 16 | −static void tls_strp_abort_strp(struct tls_strparser *strp, int err) | |
| 16 | +void tls_strp_abort_strp(struct tls_strparser *strp, int err) | |
| 17 | 17 | { |
| 18 | 18 | if (strp->stopped) |
| 19 | 19 | return; |
| @@ -211,11 +211,17 @@ static int tls_strp_copyin_frag(struct tls_strparser *strp, struct sk_buff *skb, · 191 unmodified lines | ||
| 211 | 211 | struct sk_buff *in_skb, unsigned int offset, |
| 212 | 212 | size_t in_len) |
| 213 | 213 | { |
| 214 | + unsigned int nfrag = skb->len / PAGE_SIZE; | |
| 214 | 215 | size_t len, chunk; |
| 215 | 216 | skb_frag_t *frag; |
| 216 | 217 | int sz; |
| 217 | 218 | |
| 218 | − frag = &skb_shinfo(skb)->frags[skb->len / PAGE_SIZE]; | |
| 219 | + if (unlikely(nfrag >= skb_shinfo(skb)->nr_frags)) { | |
| 220 | + DEBUG_NET_WARN_ON_ONCE(1); | |
| 221 | + return -EMSGSIZE; | |
| 222 | + } | |
| 223 | + | |
| 224 | + frag = &skb_shinfo(skb)->frags[nfrag]; | |
| 219 | 225 | |
| 220 | 226 | len = in_len; |
| 221 | 227 | /* First make sure we got the header */ |
| @@ -520,10 +526,8 @@ static int tls_strp_read_sock(struct tls_strparser *strp) · 298 unmodified lines | ||
| 520 | 526 | tls_strp_load_anchor_with_queue(strp, inq); |
| 521 | 527 | if (!strp->stm.full_len) { |
| 522 | 528 | sz = tls_rx_msg_size(strp, strp->anchor); |
| 523 | − if (sz < 0) { | |
| 524 | − tls_strp_abort_strp(strp, sz); | |
| 529 | + if (sz < 0) | |
| 525 | 530 | return sz; |
| 526 | − } | |
| 527 | 531 | |
| 528 | 532 | strp->stm.full_len = sz; |
| 529 | 533 | |
| @@ -2474,8 +2474,7 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb) · 2473 unmodified lines | ||
| 2474 | 2474 | return data_len + TLS_HEADER_SIZE; |
| 2475 | 2475 | |
| 2476 | 2476 | read_failure: |
| 2477 | − tls_err_abort(strp->sk, ret); | |
| 2478 | − | |
| 2477 | + tls_strp_abort_strp(strp, ret); | |
| 2479 | 2478 | return ret; |
| 2480 | 2479 | } |
| 2481 | 2480 | |
| @@ -138,7 +138,9 @@ pub mod property; · 137 unmodified lines | ||
| 138 | 138 | /// } |
| 139 | 139 | /// ``` |
| 140 | 140 | /// |
| 141 | −/// An example for a class device implementation is [`drm::Device`]. | |
| 141 | +/// An example for a class device implementation is | |
| 142 | +#[cfg_attr(CONFIG_DRM = "y", doc = "[`drm::Device`](kernel::drm::Device).")] | |
| 143 | +#[cfg_attr(not(CONFIG_DRM = "y"), doc = "`drm::Device`.")] | |
| 142 | 144 | /// |
| 143 | 145 | /// # Invariants |
| 144 | 146 | /// |
| @@ -151,7 +153,6 @@ pub mod property; · 6 unmodified lines | ||
| 151 | 153 | /// dropped from any thread. |
| 152 | 154 | /// |
| 153 | 155 | /// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted |
| 154 | −/// [`drm::Device`]: kernel::drm::Device | |
| 155 | 156 | /// [`impl_device_context_deref`]: kernel::impl_device_context_deref |
| 156 | 157 | /// [`pci::Device`]: kernel::pci::Device |
| 157 | 158 | /// [`platform::Device`]: kernel::platform::Device |
| @@ -208,6 +208,9 @@ static int damon_sample_mtier_enable_store( · 207 unmodified lines | ||
| 208 | 208 | if (enabled == is_enabled) |
| 209 | 209 | return 0; |
| 210 | 210 | |
| 211 | + if (!init_called) | |
| 212 | + return 0; | |
| 213 | + | |
| 211 | 214 | if (enabled) { |
| 212 | 215 | err = damon_sample_mtier_start(); |
| 213 | 216 | if (err) |
| @@ -137,6 +137,9 @@ static int damon_sample_prcl_enable_store( · 136 unmodified lines | ||
| 137 | 137 | if (enabled == is_enabled) |
| 138 | 138 | return 0; |
| 139 | 139 | |
| 140 | + if (!init_called) | |
| 141 | + return 0; | |
| 142 | + | |
| 140 | 143 | if (enabled) { |
| 141 | 144 | err = damon_sample_prcl_start(); |
| 142 | 145 | if (err) |
| @@ -118,6 +118,9 @@ static int damon_sample_wsse_enable_store( · 117 unmodified lines | ||
| 118 | 118 | return 0; |
| 119 | 119 | |
| 120 | 120 | if (enabled) { |
| 121 | + if (!init_called) | |
| 122 | + return 0; | |
| 123 | + | |
| 121 | 124 | err = damon_sample_wsse_start(); |
| 122 | 125 | if (err) |
| 123 | 126 | enabled = false; |
| @@ -75,6 +75,9 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) · 74 unmodified lines | ||
| 75 | 75 | size_t ci, cj, ei; |
| 76 | 76 | int cmp; |
| 77 | 77 | |
| 78 | + if (!excludes->cnt) | |
| 79 | + return; | |
| 80 | + | |
| 78 | 81 | ci = cj = ei = 0; |
| 79 | 82 | while (ci < cmds->cnt && ei < excludes->cnt) { |
| 80 | 83 | cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name); |
| @@ -2009,6 +2009,7 @@ static int __cmd_contention(int argc, const char **argv) · 2008 unmodified lines | ||
| 2009 | 2009 | .owner = show_lock_owner, |
| 2010 | 2010 | .cgroups = RB_ROOT, |
| 2011 | 2011 | }; |
| 2012 | + struct perf_env host_env; | |
| 2012 | 2013 | |
| 2013 | 2014 | lockhash_table = calloc(LOCKHASH_SIZE, sizeof(*lockhash_table)); |
| 2014 | 2015 | if (!lockhash_table) |
| @@ -2024,7 +2025,10 @@ static int __cmd_contention(int argc, const char **argv) · 9 unmodified lines | ||
| 2024 | 2025 | eops.mmap = perf_event__process_mmap; |
| 2025 | 2026 | eops.tracing_data = perf_event__process_tracing_data; |
| 2026 | 2027 | |
| 2027 | − session = perf_session__new(use_bpf ? NULL : &data, &eops); | |
| 2028 | + perf_env__init(&host_env); | |
| 2029 | + session = __perf_session__new(use_bpf ? NULL : &data, &eops, | |
| 2030 | + /*trace_event_repipe=*/false, &host_env); | |
| 2031 | + | |
| 2028 | 2032 | if (IS_ERR(session)) { |
| 2029 | 2033 | pr_err("Initializing perf session failed\n"); |
| 2030 | 2034 | err = PTR_ERR(session); |
| @@ -2142,6 +2146,7 @@ out_delete: · 111 unmodified lines | ||
| 2142 | 2146 | evlist__delete(con.evlist); |
| 2143 | 2147 | lock_contention_finish(&con); |
| 2144 | 2148 | perf_session__delete(session); |
| 2149 | + perf_env__exit(&host_env); | |
| 2145 | 2150 | zfree(&lockhash_table); |
| 2146 | 2151 | return err; |
| 2147 | 2152 | } |
| @@ -477,6 +477,7 @@ static int __maps__insert(struct maps *maps, struct map *new) · 476 unmodified lines | ||
| 477 | 477 | } |
| 478 | 478 | /* Insert the value at the end. */ |
| 479 | 479 | maps_by_address[nr_maps] = map__get(new); |
| 480 | + map__set_kmap_maps(new, maps); | |
| 480 | 481 | if (maps_by_name) |
| 481 | 482 | maps_by_name[nr_maps] = map__get(new); |
| 482 | 483 | |
| @@ -502,8 +503,6 @@ static int __maps__insert(struct maps *maps, struct map *new) · 19 unmodified lines | ||
| 502 | 503 | if (map__end(new) < map__start(new)) |
| 503 | 504 | RC_CHK_ACCESS(maps)->ends_broken = true; |
| 504 | 505 | |
| 505 | − map__set_kmap_maps(new, maps); | |
| 506 | − | |
| 507 | 506 | return 0; |
| 508 | 507 | } |
| 509 | 508 | |
| @@ -891,6 +890,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) · 381 unmodified lines | ||
| 891 | 890 | if (before) { |
| 892 | 891 | map__put(maps_by_address[i]); |
| 893 | 892 | maps_by_address[i] = before; |
| 893 | + map__set_kmap_maps(before, maps); | |
| 894 | 894 | |
| 895 | 895 | if (maps_by_name) { |
| 896 | 896 | map__put(maps_by_name[ni]); |
| @@ -918,6 +918,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) · 21 unmodified lines | ||
| 918 | 918 | */ |
| 919 | 919 | map__put(maps_by_address[i]); |
| 920 | 920 | maps_by_address[i] = map__get(new); |
| 921 | + map__set_kmap_maps(new, maps); | |
| 921 | 922 | |
| 922 | 923 | if (maps_by_name) { |
| 923 | 924 | map__put(maps_by_name[ni]); |
| @@ -942,14 +943,13 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) · 18 unmodified lines | ||
| 942 | 943 | */ |
| 943 | 944 | map__put(maps_by_address[i]); |
| 944 | 945 | maps_by_address[i] = map__get(new); |
| 946 | + map__set_kmap_maps(new, maps); | |
| 945 | 947 | |
| 946 | 948 | if (maps_by_name) { |
| 947 | 949 | map__put(maps_by_name[ni]); |
| 948 | 950 | maps_by_name[ni] = map__get(new); |
| 949 | 951 | } |
| 950 | 952 | |
| 951 | − map__set_kmap_maps(new, maps); | |
| 952 | − | |
| 953 | 953 | check_invariants(maps); |
| 954 | 954 | return err; |
| 955 | 955 | } |
| @@ -1019,6 +1019,7 @@ int maps__copy_from(struct maps *dest, struct maps *parent) · 63 unmodified lines | ||
| 1019 | 1019 | err = unwind__prepare_access(dest, new, NULL); |
| 1020 | 1020 | if (!err) { |
| 1021 | 1021 | dest_maps_by_address[i] = new; |
| 1022 | + map__set_kmap_maps(new, dest); | |
| 1022 | 1023 | if (dest_maps_by_name) |
| 1023 | 1024 | dest_maps_by_name[i] = map__get(new); |
| 1024 | 1025 | RC_CHK_ACCESS(dest)->nr_maps = i + 1; |
| @@ -7,6 +7,8 @@ ALL_TESTS=" · 6 unmodified lines | ||
| 7 | 7 | prio |
| 8 | 8 | arp_validate |
| 9 | 9 | num_grat_arp |
| 10 | + fail_over_mac | |
| 11 | + vlan_over_bond | |
| 10 | 12 | " |
| 11 | 13 | |
| 12 | 14 | lib_dir=$(dirname "$0") |
| @@ -352,8 +354,8 @@ garp_test() · 339 unmodified lines | ||
| 352 | 354 | |
| 353 | 355 | exp_num=$(echo "${param}" | cut -f6 -d ' ') |
| 354 | 356 | active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") |
| 355 | − slowwait_for_counter $((exp_num + 5)) $exp_num \ | |
| 356 | − tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}" | |
| 357 | + slowwait_for_counter $((exp_num + 5)) $exp_num tc_rule_handle_stats_get \ | |
| 358 | + "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}" &> /dev/null | |
| 357 | 359 | |
| 358 | 360 | # check result |
| 359 | 361 | real_num=$(tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}") |
| @@ -376,6 +378,197 @@ num_grat_arp() · 16 unmodified lines | ||
| 376 | 378 | done |
| 377 | 379 | } |
| 378 | 380 | |
| 381 | +check_all_mac_same() | |
| 382 | +{ | |
| 383 | + RET=0 | |
| 384 | + # all slaves should have same mac address (with the first port's mac) | |
| 385 | + local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]') | |
| 386 | + local eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]') | |
| 387 | + local eth1_mac=$(ip -n "$s_ns" -j link show eth1 | jq -r '.[]["address"]') | |
| 388 | + local eth2_mac=$(ip -n "$s_ns" -j link show eth2 | jq -r '.[]["address"]') | |
| 389 | + if [ "$bond_mac" != "${mac[0]}" ] || [ "$eth0_mac" != "$bond_mac" ] || \ | |
| 390 | + [ "$eth1_mac" != "$bond_mac" ] || [ "$eth2_mac" != "$bond_mac" ]; then | |
| 391 | + RET=1 | |
| 392 | + fi | |
| 393 | +} | |
| 394 | + | |
| 395 | +check_bond_mac_same_with_first() | |
| 396 | +{ | |
| 397 | + RET=0 | |
| 398 | + # bond mac address should be same with the first added slave | |
| 399 | + local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]') | |
| 400 | + if [ "$bond_mac" != "${mac[0]}" ]; then | |
| 401 | + RET=1 | |
| 402 | + fi | |
| 403 | +} | |
| 404 | + | |
| 405 | +check_bond_mac_same_with_active() | |
| 406 | +{ | |
| 407 | + RET=0 | |
| 408 | + # bond mac address should be same with active slave | |
| 409 | + local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]') | |
| 410 | + local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") | |
| 411 | + local active_slave_mac=$(ip -n "$s_ns" -j link show "$active_slave" | jq -r '.[]["address"]') | |
| 412 | + if [ "$bond_mac" != "$active_slave_mac" ]; then | |
| 413 | + RET=1 | |
| 414 | + fi | |
| 415 | +} | |
| 416 | + | |
| 417 | +check_backup_slave_mac_not_change() | |
| 418 | +{ | |
| 419 | + RET=0 | |
| 420 | + # backup slave's mac address is not changed | |
| 421 | + if ip -n "$s_ns" -d -j link show type bond_slave | jq -e '.[] | |
| 422 | + | select(.linkinfo.info_slave_data.state=="BACKUP") | |
| 423 | + | select(.address != .linkinfo.info_slave_data.perm_hwaddr)' &> /dev/null; then | |
| 424 | + RET=1 | |
| 425 | + fi | |
| 426 | +} | |
| 427 | + | |
| 428 | +check_backup_slave_mac_inherit() | |
| 429 | +{ | |
| 430 | + local backup_mac | |
| 431 | + RET=0 | |
| 432 | + | |
| 433 | + # backup slaves should use mac[1] or mac[2] | |
| 434 | + local backup_macs=$(ip -n "$s_ns" -d -j link show type bond_slave | \ | |
| 435 | + jq -r '.[] | select(.linkinfo.info_slave_data.state=="BACKUP") | .address') | |
| 436 | + for backup_mac in $backup_macs; do | |
| 437 | + if [ "$backup_mac" != "${mac[1]}" ] && [ "$backup_mac" != "${mac[2]}" ]; then | |
| 438 | + RET=1 | |
| 439 | + fi | |
| 440 | + done | |
| 441 | +} | |
| 442 | + | |
| 443 | +check_first_slave_random_mac() | |
| 444 | +{ | |
| 445 | + RET=0 | |
| 446 | + # remove the first added slave and added it back | |
| 447 | + ip -n "$s_ns" link set eth0 nomaster | |
| 448 | + ip -n "$s_ns" link set eth0 master bond0 | |
| 449 | + | |
| 450 | + # the first slave should use random mac address | |
| 451 | + eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]') | |
| 452 | + [ "$eth0_mac" = "${mac[0]}" ] && RET=1 | |
| 453 | + log_test "bond fail_over_mac follow" "random first slave mac" | |
| 454 | + | |
| 455 | + # remove the first slave, the permanent MAC address should be restored back | |
| 456 | + ip -n "$s_ns" link set eth0 nomaster | |
| 457 | + eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]') | |
| 458 | + [ "$eth0_mac" != "${mac[0]}" ] && RET=1 | |
| 459 | +} | |
| 460 | + | |
| 461 | +do_active_backup_failover() | |
| 462 | +{ | |
| 463 | + local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave") | |
| 464 | + ip -n ${s_ns} link set ${active_slave} down | |
| 465 | + slowwait 2 active_slave_changed $active_slave | |
| 466 | + ip -n ${s_ns} link set ${active_slave} up | |
| 467 | +} | |
| 468 | + | |
| 469 | +fail_over_mac() | |
| 470 | +{ | |
| 471 | + # Bring down the first interface on the switch to force the bond to | |
| 472 | + # select another active interface instead of the first one that joined. | |
| 473 | + ip -n "$g_ns" link set s0 down | |
| 474 | + | |
| 475 | + # fail_over_mac none | |
| 476 | + bond_reset "mode active-backup miimon 100 fail_over_mac 0" | |
| 477 | + check_all_mac_same | |
| 478 | + log_test "fail_over_mac 0" "all slaves have same mac" | |
| 479 | + do_active_backup_failover | |
| 480 | + check_all_mac_same | |
| 481 | + log_test "fail_over_mac 0" "failover: all slaves have same mac" | |
| 482 | + | |
| 483 | + # fail_over_mac active | |
| 484 | + bond_reset "mode active-backup miimon 100 fail_over_mac 1" | |
| 485 | + check_bond_mac_same_with_active | |
| 486 | + log_test "fail_over_mac 1" "bond mac is same with active slave mac" | |
| 487 | + check_backup_slave_mac_not_change | |
| 488 | + log_test "fail_over_mac 1" "backup slave mac is not changed" | |
| 489 | + do_active_backup_failover | |
| 490 | + check_bond_mac_same_with_active | |
| 491 | + log_test "fail_over_mac 1" "failover: bond mac is same with active slave mac" | |
| 492 | + check_backup_slave_mac_not_change | |
| 493 | + log_test "fail_over_mac 1" "failover: backup slave mac is not changed" | |
| 494 | + | |
| 495 | + # fail_over_mac follow | |
| 496 | + bond_reset "mode active-backup miimon 100 fail_over_mac 2" | |
| 497 | + check_bond_mac_same_with_first | |
| 498 | + log_test "fail_over_mac 2" "bond mac is same with first slave mac" | |
| 499 | + check_bond_mac_same_with_active | |
| 500 | + log_test "fail_over_mac 2" "bond mac is same with active slave mac" | |
| 501 | + check_backup_slave_mac_inherit | |
| 502 | + log_test "fail_over_mac 2" "backup slave mac inherit" | |
| 503 | + do_active_backup_failover | |
| 504 | + check_bond_mac_same_with_first | |
| 505 | + log_test "fail_over_mac 2" "failover: bond mac is same with first slave mac" | |
| 506 | + check_bond_mac_same_with_active | |
| 507 | + log_test "fail_over_mac 2" "failover: bond mac is same with active slave mac" | |
| 508 | + check_backup_slave_mac_inherit | |
| 509 | + log_test "fail_over_mac 2" "failover: backup slave mac inherit" | |
| 510 | + check_first_slave_random_mac | |
| 511 | + log_test "fail_over_mac 2" "first slave mac random" | |
| 512 | +} | |
| 513 | + | |
| 514 | +vlan_over_bond_arp() | |
| 515 | +{ | |
| 516 | + local mode="$1" | |
| 517 | + RET=0 | |
| 518 | + | |
| 519 | + bond_reset "mode $mode arp_interval 100 arp_ip_target 192.0.3.10" | |
| 520 | + ip -n "${s_ns}" link add bond0.3 link bond0 type vlan id 3 | |
| 521 | + ip -n "${s_ns}" link set bond0.3 up | |
| 522 | + ip -n "${s_ns}" addr add 192.0.3.1/24 dev bond0.3 | |
| 523 | + ip -n "${s_ns}" addr add 2001:db8::3:1/64 dev bond0.3 | |
| 524 | + | |
| 525 | + slowwait_for_counter 5 5 tc_rule_handle_stats_get \ | |
| 526 | + "dev eth0.3 ingress" 101 ".packets" "-n ${c_ns}" &> /dev/null || RET=1 | |
| 527 | + log_test "vlan over bond arp" "$mode" | |
| 528 | +} | |
| 529 | + | |
| 530 | +vlan_over_bond_ns() | |
| 531 | +{ | |
| 532 | + local mode="$1" | |
| 533 | + RET=0 | |
| 534 | + | |
| 535 | + if skip_ns; then | |
| 536 | + log_test_skip "vlan_over_bond ns" "$mode" | |
| 537 | + return 0 | |
| 538 | + fi | |
| 539 | + | |
| 540 | + bond_reset "mode $mode arp_interval 100 ns_ip6_target 2001:db8::3:10" | |
| 541 | + ip -n "${s_ns}" link add bond0.3 link bond0 type vlan id 3 | |
| 542 | + ip -n "${s_ns}" link set bond0.3 up | |
| 543 | + ip -n "${s_ns}" addr add 192.0.3.1/24 dev bond0.3 | |
| 544 | + ip -n "${s_ns}" addr add 2001:db8::3:1/64 dev bond0.3 | |
| 545 | + | |
| 546 | + slowwait_for_counter 5 5 tc_rule_handle_stats_get \ | |
| 547 | + "dev eth0.3 ingress" 102 ".packets" "-n ${c_ns}" &> /dev/null || RET=1 | |
| 548 | + log_test "vlan over bond ns" "$mode" | |
| 549 | +} | |
| 550 | + | |
| 551 | +vlan_over_bond() | |
| 552 | +{ | |
| 553 | + # add vlan 3 for client | |
| 554 | + ip -n "${c_ns}" link add eth0.3 link eth0 type vlan id 3 | |
| 555 | + ip -n "${c_ns}" link set eth0.3 up | |
| 556 | + ip -n "${c_ns}" addr add 192.0.3.10/24 dev eth0.3 | |
| 557 | + ip -n "${c_ns}" addr add 2001:db8::3:10/64 dev eth0.3 | |
| 558 | + | |
| 559 | + # Add tc rule to check the vlan pkts | |
| 560 | + tc -n "${c_ns}" qdisc add dev eth0.3 clsact | |
| 561 | + tc -n "${c_ns}" filter add dev eth0.3 ingress protocol arp \ | |
| 562 | + handle 101 flower skip_hw arp_op request \ | |
| 563 | + arp_sip 192.0.3.1 arp_tip 192.0.3.10 action pass | |
| 564 | + tc -n "${c_ns}" filter add dev eth0.3 ingress protocol ipv6 \ | |
| 565 | + handle 102 flower skip_hw ip_proto icmpv6 \ | |
| 566 | + type 135 src_ip 2001:db8::3:1 action pass | |
| 567 | + | |
| 568 | + vlan_over_bond_arp "active-backup" | |
| 569 | + vlan_over_bond_ns "active-backup" | |
| 570 | +} | |
| 571 | + | |
| 379 | 572 | trap cleanup EXIT |
| 380 | 573 | |
| 381 | 574 | setup_prepare |
| @@ -39,6 +39,8 @@ g_ip4="192.0.2.254" · 38 unmodified lines | ||
| 39 | 39 | s_ip6="2001:db8::1" |
| 40 | 40 | c_ip6="2001:db8::10" |
| 41 | 41 | g_ip6="2001:db8::254" |
| 42 | +mac[0]="00:0a:0b:0c:0d:01" | |
| 43 | +mac[1]="00:0a:0b:0c:0d:02" | |
| 42 | 44 | |
| 43 | 45 | gateway_create() |
| 44 | 46 | { |
| @@ -62,6 +64,7 @@ server_create() · 17 unmodified lines | ||
| 62 | 64 | |
| 63 | 65 | for i in $(seq 0 1); do |
| 64 | 66 | ip -n ${s_ns} link add eth${i} type veth peer name s${i} netns ${g_ns} |
| 67 | + ip -n "${s_ns}" link set "eth${i}" addr "${mac[$i]}" | |
| 65 | 68 | |
| 66 | 69 | ip -n ${g_ns} link set s${i} up |
| 67 | 70 | ip -n ${g_ns} link set s${i} master br0 |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | # +-------------------------------------+ |
| 27 | 27 | |
| 28 | 28 | source bond_topo_2d1c.sh |
| 29 | +mac[2]="00:0a:0b:0c:0d:03" | |
| 29 | 30 | |
| 30 | 31 | setup_prepare() |
| 31 | 32 | { |
| @@ -36,6 +37,7 @@ setup_prepare() · 4 unmodified lines | ||
| 36 | 37 | # Add the extra device as we use 3 down links for bond0 |
| 37 | 38 | local i=2 |
| 38 | 39 | ip -n ${s_ns} link add eth${i} type veth peer name s${i} netns ${g_ns} |
| 40 | + ip -n "${s_ns}" link set "eth${i}" addr "${mac[$i]}" | |
| 39 | 41 | ip -n ${g_ns} link set s${i} up |
| 40 | 42 | ip -n ${g_ns} link set s${i} master br0 |
| 41 | 43 | ip -n ${s_ns} link set eth${i} master bond0 |
| @@ -10,3 +10,4 @@ CONFIG_NET_CLS_MATCHALL=m · 9 unmodified lines | ||
| 10 | 10 | CONFIG_NET_SCH_INGRESS=y |
| 11 | 11 | CONFIG_NLMON=y |
| 12 | 12 | CONFIG_VETH=y |
| 13 | +CONFIG_VLAN_8021Q=m | |
| @@ -1093,6 +1093,7 @@ int main_loop_s(int listensock) · 1092 unmodified lines | ||
| 1093 | 1093 | struct pollfd polls; |
| 1094 | 1094 | socklen_t salen; |
| 1095 | 1095 | int remotesock; |
| 1096 | + int err = 0; | |
| 1096 | 1097 | int fd = 0; |
| 1097 | 1098 | |
| 1098 | 1099 | again: |
| @@ -1125,7 +1126,7 @@ again: · 26 unmodified lines | ||
| 1125 | 1126 | SOCK_TEST_TCPULP(remotesock, 0); |
| 1126 | 1127 | |
| 1127 | 1128 | memset(&winfo, 0, sizeof(winfo)); |
| 1128 | − copyfd_io(fd, remotesock, 1, true, &winfo); | |
| 1129 | + err = copyfd_io(fd, remotesock, 1, true, &winfo); | |
| 1129 | 1130 | } else { |
| 1130 | 1131 | perror("accept"); |
| 1131 | 1132 | return 1; |
| @@ -1134,10 +1135,10 @@ again: · 2 unmodified lines | ||
| 1134 | 1135 | if (cfg_input) |
| 1135 | 1136 | close(fd); |
| 1136 | 1137 | |
| 1137 | − if (--cfg_repeat > 0) | |
| 1138 | + if (!err && --cfg_repeat > 0) | |
| 1138 | 1139 | goto again; |
| 1139 | 1140 | |
| 1140 | − return 0; | |
| 1141 | + return err; | |
| 1141 | 1142 | } |
| 1142 | 1143 | |
| 1143 | 1144 | static void init_rng(void) |
| @@ -1247,7 +1248,7 @@ void xdisconnect(int fd) · 103 unmodified lines | ||
| 1247 | 1248 | else |
| 1248 | 1249 | xerror("bad family"); |
| 1249 | 1250 | |
| 1250 | − strcpy(cmd, "ss -M | grep -q "); | |
| 1251 | + strcpy(cmd, "ss -Mnt | grep -q "); | |
| 1251 | 1252 | cmdlen = strlen(cmd); |
| 1252 | 1253 | if (!inet_ntop(addr.ss_family, raw_addr, &cmd[cmdlen], |
| 1253 | 1254 | sizeof(cmd) - cmdlen)) |
| @@ -1257,7 +1258,7 @@ void xdisconnect(int fd) · 3 unmodified lines | ||
| 1257 | 1258 | |
| 1258 | 1259 | /* |
| 1259 | 1260 | * wait until the pending data is completely flushed and all |
| 1260 | − * the MPTCP sockets reached the closed status. | |
| 1261 | + * the sockets reached the closed status. | |
| 1261 | 1262 | * disconnect will bypass/ignore/drop any pending data. |
| 1262 | 1263 | */ |
| 1263 | 1264 | for (i = 0; ; i += msec_sleep) { |
| @@ -211,6 +211,11 @@ if $checksum; then · 210 unmodified lines | ||
| 211 | 211 | done |
| 212 | 212 | fi |
| 213 | 213 | |
| 214 | +if $capture; then | |
| 215 | + rndh="${ns1:4}" | |
| 216 | + mptcp_lib_pr_info "Packet capture files will have this prefix: ${rndh}-" | |
| 217 | +fi | |
| 218 | + | |
| 214 | 219 | set_ethtool_flags() { |
| 215 | 220 | local ns="$1" |
| 216 | 221 | local dev="$2" |
| @@ -361,7 +366,6 @@ do_transfer() · 144 unmodified lines | ||
| 361 | 366 | |
| 362 | 367 | if $capture; then |
| 363 | 368 | local capuser |
| 364 | − local rndh="${connector_ns:4}" | |
| 365 | 369 | if [ -z $SUDO_USER ] ; then |
| 366 | 370 | capuser="" |
| 367 | 371 | else |
| @@ -384,7 +384,7 @@ mptcp_lib_make_file() { · 383 unmodified lines | ||
| 384 | 384 | mptcp_lib_print_file_err() { |
| 385 | 385 | ls -l "${1}" 1>&2 |
| 386 | 386 | echo "Trailing bytes are: " |
| 387 | − tail -c 27 "${1}" | |
| 387 | + tail -c 32 "${1}" | od -x | head -n2 | |
| 388 | 388 | } |
| 389 | 389 | |
| 390 | 390 | # $1: input file ; $2: output file ; $3: what kind of file |
| @@ -667,22 +667,26 @@ static void process_one_client(int fd, int pipefd) · 666 unmodified lines | ||
| 667 | 667 | |
| 668 | 668 | do_getsockopts(&s, fd, ret, ret2); |
| 669 | 669 | if (s.mptcpi_rcv_delta != (uint64_t)ret + 1) |
| 670 | − xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret); | |
| 670 | + xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64 ", diff %" PRId64, | |
| 671 | + s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - (ret + 1)); | |
| 671 | 672 | |
| 672 | 673 | /* be nice when running on top of older kernel */ |
| 673 | 674 | if (s.pkt_stats_avail) { |
| 674 | 675 | if (s.last_sample.mptcpi_bytes_sent != ret2) |
| 675 | − xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64, | |
| 676 | + xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64 | |
| 677 | + ", diff %" PRId64, | |
| 676 | 678 | s.last_sample.mptcpi_bytes_sent, ret2, |
| 677 | 679 | s.last_sample.mptcpi_bytes_sent - ret2); |
| 678 | 680 | if (s.last_sample.mptcpi_bytes_received != ret) |
| 679 | − xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64, | |
| 681 | + xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64 | |
| 682 | + ", diff %" PRId64, | |
| 680 | 683 | s.last_sample.mptcpi_bytes_received, ret, |
| 681 | 684 | s.last_sample.mptcpi_bytes_received - ret); |
| 682 | 685 | if (s.last_sample.mptcpi_bytes_acked != ret) |
| 683 | − xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64, | |
| 684 | − s.last_sample.mptcpi_bytes_acked, ret2, | |
| 685 | − s.last_sample.mptcpi_bytes_acked - ret2); | |
| 686 | + xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64 | |
| 687 | + ", diff %" PRId64, | |
| 688 | + s.last_sample.mptcpi_bytes_acked, ret, | |
| 689 | + s.last_sample.mptcpi_bytes_acked - ret); | |
| 686 | 690 | } |
| 687 | 691 | |
| 688 | 692 | close(fd); |
| @@ -188,6 +188,13 @@ static int capture_events(int fd, int event_group) · 187 unmodified lines | ||
| 188 | 188 | fprintf(stderr, ",error:%u", *(__u8 *)RTA_DATA(attrs)); |
| 189 | 189 | else if (attrs->rta_type == MPTCP_ATTR_SERVER_SIDE) |
| 190 | 190 | fprintf(stderr, ",server_side:%u", *(__u8 *)RTA_DATA(attrs)); |
| 191 | + else if (attrs->rta_type == MPTCP_ATTR_FLAGS) { | |
| 192 | + __u16 flags = *(__u16 *)RTA_DATA(attrs); | |
| 193 | + | |
| 194 | + /* only print when present, easier */ | |
| 195 | + if (flags & MPTCP_PM_EV_FLAG_DENY_JOIN_ID0) | |
| 196 | + fprintf(stderr, ",deny_join_id0:1"); | |
| 197 | + } | |
| 191 | 198 | |
| 192 | 199 | attrs = RTA_NEXT(attrs, msg_len); |
| 193 | 200 | } |
| @@ -201,6 +201,9 @@ make_connection() · 200 unmodified lines | ||
| 201 | 201 | is_v6="v4" |
| 202 | 202 | fi |
| 203 | 203 | |
| 204 | + # set this on the client side only: will not affect the rest | |
| 205 | + ip netns exec "$ns2" sysctl -q net.mptcp.allow_join_initial_addr_port=0 | |
| 206 | + | |
| 204 | 207 | :>"$client_evts" |
| 205 | 208 | :>"$server_evts" |
| 206 | 209 | |
| @@ -223,23 +226,28 @@ make_connection() · 16 unmodified lines | ||
| 223 | 226 | local client_token |
| 224 | 227 | local client_port |
| 225 | 228 | local client_serverside |
| 229 | + local client_nojoin | |
| 226 | 230 | local server_token |
| 227 | 231 | local server_serverside |
| 232 | + local server_nojoin | |
| 228 | 233 | |
| 229 | 234 | client_token=$(mptcp_lib_evts_get_info token "$client_evts") |
| 230 | 235 | client_port=$(mptcp_lib_evts_get_info sport "$client_evts") |
| 231 | 236 | client_serverside=$(mptcp_lib_evts_get_info server_side "$client_evts") |
| 237 | + client_nojoin=$(mptcp_lib_evts_get_info deny_join_id0 "$client_evts") | |
| 232 | 238 | server_token=$(mptcp_lib_evts_get_info token "$server_evts") |
| 233 | 239 | server_serverside=$(mptcp_lib_evts_get_info server_side "$server_evts") |
| 240 | + server_nojoin=$(mptcp_lib_evts_get_info deny_join_id0 "$server_evts") | |
| 234 | 241 | |
| 235 | 242 | print_test "Established IP${is_v6} MPTCP Connection ns2 => ns1" |
| 236 | − if [ "$client_token" != "" ] && [ "$server_token" != "" ] && [ "$client_serverside" = 0 ] && | |
| 237 | − [ "$server_serverside" = 1 ] | |
| 243 | + if [ "${client_token}" != "" ] && [ "${server_token}" != "" ] && | |
| 244 | + [ "${client_serverside}" = 0 ] && [ "${server_serverside}" = 1 ] && | |
| 245 | + [ "${client_nojoin:-0}" = 0 ] && [ "${server_nojoin:-0}" = 1 ] | |
| 238 | 246 | then |
| 239 | 247 | test_pass |
| 240 | 248 | print_title "Connection info: ${client_addr}:${client_port} -> ${connect_addr}:${app_port}" |
| 241 | 249 | else |
| 242 | − test_fail "Expected tokens (c:${client_token} - s:${server_token}) and server (c:${client_serverside} - s:${server_serverside})" | |
| 250 | + test_fail "Expected tokens (c:${client_token} - s:${server_token}), server (c:${client_serverside} - s:${server_serverside}), nojoin (c:${client_nojoin} - s:${server_nojoin})" | |
| 243 | 251 | mptcp_lib_result_print_all_tap |
| 244 | 252 | exit ${KSFT_FAIL} |
| 245 | 253 | fi |
| @@ -25,6 +25,7 @@ tests=" · 24 unmodified lines | ||
| 25 | 25 | nat_related_v4 ip4-nat-related: ICMP related matches work with SNAT |
| 26 | 26 | netlink_checks ovsnl: validate netlink attrs and settings |
| 27 | 27 | upcall_interfaces ovs: test the upcall interfaces |
| 28 | + tunnel_metadata ovs: test extraction of tunnel metadata | |
| 28 | 29 | drop_reason drop: test drop reasons are emitted |
| 29 | 30 | psample psample: Sampling packets with psample" |
| 30 | 31 | |
| @@ -113,13 +114,13 @@ ovs_add_dp () { · 82 unmodified lines | ||
| 113 | 114 | } |
| 114 | 115 | |
| 115 | 116 | ovs_add_if () { |
| 116 | − info "Adding IF to DP: br:$2 if:$3" | |
| 117 | − if [ "$4" != "-u" ]; then | |
| 118 | − ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if "$2" "$3" \ | |
| 119 | − || return 1 | |
| 117 | + info "Adding IF to DP: br:$3 if:$4 ($2)" | |
| 118 | + if [ "$5" != "-u" ]; then | |
| 119 | + ovs_sbx "$1" python3 $ovs_base/ovs-dpctl.py add-if \ | |
| 120 | + -t "$2" "$3" "$4" || return 1 | |
| 120 | 121 | else |
| 121 | 122 | python3 $ovs_base/ovs-dpctl.py add-if \ |
| 122 | − -u "$2" "$3" >$ovs_dir/$3.out 2>$ovs_dir/$3.err & | |
| 123 | + -u -t "$2" "$3" "$4" >$ovs_dir/$4.out 2>$ovs_dir/$4.err & | |
| 123 | 124 | pid=$! |
| 124 | 125 | on_exit "ovs_sbx $1 kill -TERM $pid 2>/dev/null" |
| 125 | 126 | fi |
| @@ -166,9 +167,9 @@ ovs_add_netns_and_veths () { · 40 unmodified lines | ||
| 166 | 167 | fi |
| 167 | 168 | |
| 168 | 169 | if [ "$7" != "-u" ]; then |
| 169 | − ovs_add_if "$1" "$2" "$4" || return 1 | |
| 170 | + ovs_add_if "$1" "netdev" "$2" "$4" || return 1 | |
| 170 | 171 | else |
| 171 | − ovs_add_if "$1" "$2" "$4" -u || return 1 | |
| 172 | + ovs_add_if "$1" "netdev" "$2" "$4" -u || return 1 | |
| 172 | 173 | fi |
| 173 | 174 | |
| 174 | 175 | if [ $TRACING -eq 1 ]; then |
| @@ -756,6 +757,79 @@ test_upcall_interfaces() { · 581 unmodified lines | ||
| 756 | 757 | return 0 |
| 757 | 758 | } |
| 758 | 759 | |
| 760 | +ovs_add_kernel_tunnel() { | |
| 761 | + local sbxname=$1; shift | |
| 762 | + local ns=$1; shift | |
| 763 | + local tnl_type=$1; shift | |
| 764 | + local name=$1; shift | |
| 765 | + local addr=$1; shift | |
| 766 | + | |
| 767 | + info "setting up kernel ${tnl_type} tunnel ${name}" | |
| 768 | + ovs_sbx "${sbxname}" ip -netns ${ns} link add dev ${name} type ${tnl_type} $* || return 1 | |
| 769 | + on_exit "ovs_sbx ${sbxname} ip -netns ${ns} link del ${name} >/dev/null 2>&1" | |
| 770 | + ovs_sbx "${sbxname}" ip -netns ${ns} addr add dev ${name} ${addr} || return 1 | |
| 771 | + ovs_sbx "${sbxname}" ip -netns ${ns} link set dev ${name} mtu 1450 up || return 1 | |
| 772 | +} | |
| 773 | + | |
| 774 | +test_tunnel_metadata() { | |
| 775 | + which arping >/dev/null 2>&1 || return $ksft_skip | |
| 776 | + | |
| 777 | + sbxname="test_tunnel_metadata" | |
| 778 | + sbx_add "${sbxname}" || return 1 | |
| 779 | + | |
| 780 | + info "setting up new DP" | |
| 781 | + ovs_add_dp "${sbxname}" tdp0 -V 2:1 || return 1 | |
| 782 | + | |
| 783 | + ovs_add_netns_and_veths "${sbxname}" tdp0 tns left0 l0 \ | |
| 784 | + 172.31.110.1/24 || return 1 | |
| 785 | + | |
| 786 | + info "removing veth interface from openvswitch and setting IP" | |
| 787 | + ovs_del_if "${sbxname}" tdp0 left0 || return 1 | |
| 788 | + ovs_sbx "${sbxname}" ip addr add 172.31.110.2/24 dev left0 || return 1 | |
| 789 | + ovs_sbx "${sbxname}" ip link set left0 up || return 1 | |
| 790 | + | |
| 791 | + info "setting up tunnel port in openvswitch" | |
| 792 | + ovs_add_if "${sbxname}" "vxlan" tdp0 ovs-vxlan0 -u || return 1 | |
| 793 | + on_exit "ovs_sbx ${sbxname} ip link del ovs-vxlan0" | |
| 794 | + ovs_wait ip link show ovs-vxlan0 &>/dev/null || return 1 | |
| 795 | + ovs_sbx "${sbxname}" ip link set ovs-vxlan0 up || return 1 | |
| 796 | + | |
| 797 | + configs=$(echo ' | |
| 798 | + 1 172.31.221.1/24 1155332 32 set udpcsum flags\(df\|csum\) | |
| 799 | + 2 172.31.222.1/24 1234567 45 set noudpcsum flags\(df\) | |
| 800 | + 3 172.31.223.1/24 1020304 23 unset udpcsum flags\(csum\) | |
| 801 | + 4 172.31.224.1/24 1357986 15 unset noudpcsum' | sed '/^$/d') | |
| 802 | + | |
| 803 | + while read -r i addr id ttl df csum flags; do | |
| 804 | + ovs_add_kernel_tunnel "${sbxname}" tns vxlan vxlan${i} ${addr} \ | |
| 805 | + remote 172.31.110.2 id ${id} dstport 4789 \ | |
| 806 | + ttl ${ttl} df ${df} ${csum} || return 1 | |
| 807 | + done <<< "${configs}" | |
| 808 | + | |
| 809 | + ovs_wait grep -q 'listening on upcall packet handler' \ | |
| 810 | + ${ovs_dir}/ovs-vxlan0.out || return 1 | |
| 811 | + | |
| 812 | + info "sending arping" | |
| 813 | + for i in 1 2 3 4; do | |
| 814 | + ovs_sbx "${sbxname}" ip netns exec tns \ | |
| 815 | + arping -I vxlan${i} 172.31.22${i}.2 -c 1 \ | |
| 816 | + >${ovs_dir}/arping.stdout 2>${ovs_dir}/arping.stderr | |
| 817 | + done | |
| 818 | + | |
| 819 | + info "checking that received decapsulated packets carry correct metadata" | |
| 820 | + while read -r i addr id ttl df csum flags; do | |
| 821 | + arp_hdr="arp\\(sip=172.31.22${i}.1,tip=172.31.22${i}.2,op=1,sha=" | |
| 822 | + addrs="src=172.31.110.1,dst=172.31.110.2" | |
| 823 | + ports="tp_src=[0-9]*,tp_dst=4789" | |
| 824 | + tnl_md="tunnel\\(tun_id=${id},${addrs},ttl=${ttl},${ports},${flags}\\)" | |
| 825 | + | |
| 826 | + ovs_sbx "${sbxname}" grep -qE "MISS upcall.*${tnl_md}.*${arp_hdr}" \ | |
| 827 | + ${ovs_dir}/ovs-vxlan0.out || return 1 | |
| 828 | + done <<< "${configs}" | |
| 829 | + | |
| 830 | + return 0 | |
| 831 | +} | |
| 832 | + | |
| 759 | 833 | run_test() { |
| 760 | 834 | ( |
| 761 | 835 | tname="$1" |
| @@ -0,0 +1,26 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +`./defaults.sh | |
| 3 | + ./set_sysctls.py /proc/sys/net/ipv4/tcp_fastopen=0x602 /proc/sys/net/ipv4/tcp_timestamps=0` | |
| 4 | + | |
| 5 | + 0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3 | |
| 6 | + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 | |
| 7 | + +0 bind(3, ..., ...) = 0 | |
| 8 | + +0 listen(3, 1) = 0 | |
| 9 | + | |
| 10 | + +0 < S 0:10(10) win 32792 <mss 1460,nop,nop,sackOK> | |
| 11 | + +0 > S. 0:0(0) ack 11 win 65535 <mss 1460,nop,nop,sackOK> | |
| 12 | + | |
| 13 | +// sk->sk_state is TCP_SYN_RECV | |
| 14 | + +.1 accept(3, ..., ...) = 4 | |
| 15 | + | |
| 16 | +// tcp_disconnect() sets sk->sk_state to TCP_CLOSE | |
| 17 | + +0 connect(4, AF_UNSPEC, ...) = 0 | |
| 18 | + +0 > R. 1:1(0) ack 11 win 65535 | |
| 19 | + | |
| 20 | +// connect() sets sk->sk_state to TCP_SYN_SENT | |
| 21 | + +0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 | |
| 22 | + +0 connect(4, ..., ...) = -1 EINPROGRESS (Operation is now in progress) | |
| 23 | + +0 > S 0:0(0) win 65535 <mss 1460,nop,nop,sackOK,nop,wscale 8> | |
| 24 | + | |
| 25 | +// tp->fastopen_rsk must be NULL | |
| 26 | + +1 > S 0:0(0) win 65535 <mss 1460,nop,nop,sackOK,nop,wscale 8> | |
| @@ -2775,6 +2775,22 @@ TEST_F(tls_err, poll_partial_rec_async) · 2774 unmodified lines | ||
| 2775 | 2775 | } |
| 2776 | 2776 | } |
| 2777 | 2777 | |
| 2778 | +/* Use OOB+large send to trigger copy mode due to memory pressure. | |
| 2779 | + * OOB causes a short read. | |
| 2780 | + */ | |
| 2781 | +TEST_F(tls_err, oob_pressure) | |
| 2782 | +{ | |
| 2783 | + char buf[1<<16]; | |
| 2784 | + int i; | |
| 2785 | + | |
| 2786 | + memrnd(buf, sizeof(buf)); | |
| 2787 | + | |
| 2788 | + EXPECT_EQ(send(self->fd2, buf, 5, MSG_OOB), 5); | |
| 2789 | + EXPECT_EQ(send(self->fd2, buf, sizeof(buf), 0), sizeof(buf)); | |
| 2790 | + for (i = 0; i < 64; i++) | |
| 2791 | + EXPECT_EQ(send(self->fd2, buf, 5, MSG_OOB), 5); | |
| 2792 | +} | |
| 2793 | + | |
| 2778 | 2794 | TEST(non_established) { |
| 2779 | 2795 | struct tls12_crypto_info_aes_gcm_256 tls12; |
| 2780 | 2796 | struct sockaddr_in addr; |