Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge commit '6e64f4580381e32c06ee146ca807c555b8f73e24' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux into gpio/for-next

+17679 -7501
+1
.mailmap
··· 673 673 Ross Zwisler <zwisler@kernel.org> <ross.zwisler@linux.intel.com> 674 674 Rudolf Marek <R.Marek@sh.cvut.cz> 675 675 Rui Saraiva <rmps@joel.ist.utl.pt> 676 + Sachin Mokashi <sachin.mokashi@intel.com> <sachinx.mokashi@intel.com> 676 677 Sachin P Sant <ssant@in.ibm.com> 677 678 Sai Prakash Ranjan <quic_saipraka@quicinc.com> <saiprakash.ranjan@codeaurora.org> 678 679 Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi>
+6
CREDITS
··· 4378 4378 S: New York, New York 10025 4379 4379 S: USA 4380 4380 4381 + N: Masahiro Yamada 4382 + E: masahiroy@kernel.org 4383 + D: Kbuild Maintainer 2017-2025 4384 + D: Kconfig Maintainer 2018-2025 4385 + S: Japan 4386 + 4381 4387 N: Li Yang 4382 4388 E: leoli@freescale.com 4383 4389 D: Freescale Highspeed USB device driver
+22
Documentation/ABI/testing/sysfs-fs-f2fs
··· 861 861 SB_ENC_STRICT_MODE_FL 0x00000001 862 862 SB_ENC_NO_COMPAT_FALLBACK_FL 0x00000002 863 863 ============================ ========== 864 + 865 + What: /sys/fs/f2fs/<disk>/reserved_pin_section 866 + Date: June 2025 867 + Contact: "Chao Yu" <chao@kernel.org> 868 + Description: This threshold is used to control triggering garbage collection while 869 + fallocating on pinned file, so, it can guarantee there is enough free 870 + reserved section before preallocating on pinned file. 871 + By default, the value is ovp_sections, especially, for zoned ufs, the 872 + value is 1. 873 + 874 + What: /sys/fs/f2fs/<disk>/gc_boost_gc_multiple 875 + Date: June 2025 876 + Contact: "Daeho Jeong" <daehojeong@google.com> 877 + Description: Set a multiplier for the background GC migration window when F2FS GC is 878 + boosted. The range should be from 1 to the segment count in a section. 879 + Default: 5 880 + 881 + What: /sys/fs/f2fs/<disk>/gc_boost_gc_greedy 882 + Date: June 2025 883 + Contact: "Daeho Jeong" <daehojeong@google.com> 884 + Description: Control GC algorithm for boost GC. 0: cost benefit, 1: greedy 885 + Default: 1
+56
Documentation/accounting/delay-accounting.rst
··· 131 131 linuxrc: read=65536, write=0, cancelled_write=0 132 132 133 133 The above command can be used with -v to get more debug information. 134 + 135 + After the system starts, use `delaytop` to get the system-wide delay information, 136 + which includes system-wide PSI information and Top-N high-latency tasks. 137 + 138 + `delaytop` supports sorting by CPU latency in descending order by default, 139 + displays the top 20 high-latency tasks by default, and refreshes the latency 140 + data every 2 seconds by default. 141 + 142 + Get PSI information and Top-N tasks delay, since system boot:: 143 + 144 + bash# ./delaytop 145 + System Pressure Information: (avg10/avg60/avg300/total) 146 + CPU some: 0.0%/ 0.0%/ 0.0%/ 345(ms) 147 + CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms) 148 + Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms) 149 + Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms) 150 + IO full: 0.0%/ 0.0%/ 0.0%/ 65(ms) 151 + IO some: 0.0%/ 0.0%/ 0.0%/ 79(ms) 152 + IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms) 153 + Top 20 processes (sorted by CPU delay): 154 + PID TGID COMMAND CPU(ms) IO(ms) SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms) 155 + ---------------------------------------------------------------------------------------------- 156 + 161 161 zombie_memcg_re 1.40 0.00 0.00 0.00 0.00 0.00 0.00 0.00 157 + 130 130 blkcg_punt_bio 1.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00 158 + 444 444 scsi_tmf_0 0.73 0.00 0.00 0.00 0.00 0.00 0.00 0.00 159 + 1280 1280 rsyslogd 0.53 0.04 0.00 0.00 0.00 0.00 0.00 0.00 160 + 12 12 ksoftirqd/0 0.47 0.00 0.00 0.00 0.00 0.00 0.00 0.00 161 + 1277 1277 nbd-server 0.44 0.00 0.00 0.00 0.00 0.00 0.00 0.00 162 + 308 308 kworker/2:2-sys 0.41 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163 + 55 55 netns 0.36 0.00 0.00 0.00 0.00 0.00 0.00 0.00 164 + 1187 1187 acpid 0.31 0.03 0.00 0.00 0.00 0.00 0.00 0.00 165 + 6184 6184 kworker/1:2-sys 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00 166 + 186 186 kaluad 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00 167 + 18 18 ksoftirqd/1 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00 168 + 185 185 kmpath_rdacd 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00 169 + 190 190 kstrp 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00 170 + 2759 2759 agetty 0.20 0.03 0.00 0.00 0.00 0.00 0.00 0.00 171 + 1190 1190 kworker/0:3-sys 0.19 0.00 0.00 0.00 0.00 0.00 0.00 0.00 172 + 1272 1272 sshd 0.15 0.04 0.00 0.00 0.00 0.00 0.00 0.00 173 + 1156 1156 license 0.15 0.11 0.00 0.00 0.00 0.00 0.00 0.00 174 + 134 134 md 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00 175 + 6142 6142 kworker/3:2-xfs 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00 176 + 177 + Dynamic interactive interface of delaytop:: 178 + 179 + # ./delaytop -p pid 180 + Print delayacct stats 181 + 182 + # ./delaytop -P num 183 + Display the top N tasks 184 + 185 + # ./delaytop -n num 186 + Set delaytop refresh frequency (num times) 187 + 188 + # ./delaytop -d secs 189 + Specify refresh interval as secs
+8 -8
Documentation/admin-guide/device-mapper/thin-provisioning.rst
··· 80 80 81 81 As a guide, we suggest you calculate the number of bytes to use in the 82 82 metadata device as 48 * $data_dev_size / $data_block_size but round it up 83 - to 2MB if the answer is smaller. If you're creating large numbers of 83 + to 2MiB if the answer is smaller. If you're creating large numbers of 84 84 snapshots which are recording large amounts of change, you may find you 85 85 need to increase this. 86 86 87 - The largest size supported is 16GB: If the device is larger, 87 + The largest size supported is 16GiB: If the device is larger, 88 88 a warning will be issued and the excess space will not be used. 89 89 90 90 Reloading a pool table ··· 107 107 108 108 $data_block_size gives the smallest unit of disk space that can be 109 109 allocated at a time expressed in units of 512-byte sectors. 110 - $data_block_size must be between 128 (64KB) and 2097152 (1GB) and a 111 - multiple of 128 (64KB). $data_block_size cannot be changed after the 110 + $data_block_size must be between 128 (64KiB) and 2097152 (1GiB) and a 111 + multiple of 128 (64KiB). $data_block_size cannot be changed after the 112 112 thin-pool is created. People primarily interested in thin provisioning 113 - may want to use a value such as 1024 (512KB). People doing lots of 114 - snapshotting may want a smaller value such as 128 (64KB). If you are 113 + may want to use a value such as 1024 (512KiB). People doing lots of 114 + snapshotting may want a smaller value such as 128 (64KiB). If you are 115 115 not zeroing newly-allocated data, a larger $data_block_size in the 116 - region of 256000 (128MB) is suggested. 116 + region of 262144 (128MiB) is suggested. 117 117 118 118 $low_water_mark is expressed in blocks of size $data_block_size. If 119 119 free space on the data device drops below this level then a dm event ··· 291 291 error_if_no_space: 292 292 Error IOs, instead of queueing, if no space. 293 293 294 - Data block size must be between 64KB (128 sectors) and 1GB 294 + Data block size must be between 64KiB (128 sectors) and 1GiB 295 295 (2097152 sectors) inclusive. 296 296 297 297
+21
Documentation/admin-guide/kdump/kdump.rst
··· 311 311 312 312 crashkernel=0,low 313 313 314 + 4) crashkernel=size,cma 315 + 316 + Reserve additional crash kernel memory from CMA. This reservation is 317 + usable by the first system's userspace memory and kernel movable 318 + allocations (memory balloon, zswap). Pages allocated from this memory 319 + range will not be included in the vmcore so this should not be used if 320 + dumping of userspace memory is intended and it has to be expected that 321 + some movable kernel pages may be missing from the dump. 322 + 323 + A standard crashkernel reservation, as described above, is still needed 324 + to hold the crash kernel and initrd. 325 + 326 + This option increases the risk of a kdump failure: DMA transfers 327 + configured by the first kernel may end up corrupting the second 328 + kernel's memory. 329 + 330 + This reservation method is intended for systems that can't afford to 331 + sacrifice enough memory for standard crashkernel reservation and where 332 + less reliable and possibly incomplete kdump is preferable to no kdump at 333 + all. 334 + 314 335 Boot into System Kernel 315 336 ----------------------- 316 337 1) Update the boot loader (such as grub, yaboot, or lilo) configuration
+73 -13
Documentation/admin-guide/kernel-parameters.txt
··· 994 994 0: to disable low allocation. 995 995 It will be ignored when crashkernel=X,high is not used 996 996 or memory reserved is below 4G. 997 + crashkernel=size[KMG],cma 998 + [KNL, X86] Reserve additional crash kernel memory from 999 + CMA. This reservation is usable by the first system's 1000 + userspace memory and kernel movable allocations (memory 1001 + balloon, zswap). Pages allocated from this memory range 1002 + will not be included in the vmcore so this should not 1003 + be used if dumping of userspace memory is intended and 1004 + it has to be expected that some movable kernel pages 1005 + may be missing from the dump. 1006 + 1007 + A standard crashkernel reservation, as described above, 1008 + is still needed to hold the crash kernel and initrd. 1009 + 1010 + This option increases the risk of a kdump failure: DMA 1011 + transfers configured by the first kernel may end up 1012 + corrupting the second kernel's memory. 1013 + 1014 + This reservation method is intended for systems that 1015 + can't afford to sacrifice enough memory for standard 1016 + crashkernel reservation and where less reliable and 1017 + possibly incomplete kdump is preferable to no kdump at 1018 + all. 997 1019 998 1020 cryptomgr.notests 999 1021 [KNL] Disable crypto self-tests ··· 1827 1805 [KNL] Should the hard-lockup detector generate 1828 1806 backtraces on all cpus. 1829 1807 Format: 0 | 1 1808 + 1809 + hash_pointers= 1810 + [KNL,EARLY] 1811 + By default, when pointers are printed to the console 1812 + or buffers via the %p format string, that pointer is 1813 + "hashed", i.e. obscured by hashing the pointer value. 1814 + This is a security feature that hides actual kernel 1815 + addresses from unprivileged users, but it also makes 1816 + debugging the kernel more difficult since unequal 1817 + pointers can no longer be compared. The choices are: 1818 + Format: { auto | always | never } 1819 + Default: auto 1820 + 1821 + auto - Hash pointers unless slab_debug is enabled. 1822 + always - Always hash pointers (even if slab_debug is 1823 + enabled). 1824 + never - Never hash pointers. This option should only 1825 + be specified when debugging the kernel. Do 1826 + not use on production kernels. The boot 1827 + param "no_hash_pointers" is an alias for 1828 + this mode. 1830 1829 1831 1830 hashdist= [KNL,NUMA] Large hashes allocated during boot 1832 1831 are distributed across NUMA nodes. Defaults on ··· 4237 4194 4238 4195 no_hash_pointers 4239 4196 [KNL,EARLY] 4240 - Force pointers printed to the console or buffers to be 4241 - unhashed. By default, when a pointer is printed via %p 4242 - format string, that pointer is "hashed", i.e. obscured 4243 - by hashing the pointer value. This is a security feature 4244 - that hides actual kernel addresses from unprivileged 4245 - users, but it also makes debugging the kernel more 4246 - difficult since unequal pointers can no longer be 4247 - compared. However, if this command-line option is 4248 - specified, then all normal pointers will have their true 4249 - value printed. This option should only be specified when 4250 - debugging the kernel. Please do not use on production 4251 - kernels. 4197 + Alias for "hash_pointers=never". 4252 4198 4253 4199 nohibernate [HIBERNATION] Disable hibernation and resume. 4254 4200 ··· 4589 4557 bit 2: print timer info 4590 4558 bit 3: print locks info if CONFIG_LOCKDEP is on 4591 4559 bit 4: print ftrace buffer 4592 - bit 5: print all printk messages in buffer 4560 + bit 5: replay all messages on consoles at the end of panic 4593 4561 bit 6: print all CPUs backtrace (if available in the arch) 4594 4562 bit 7: print only tasks in uninterruptible (blocked) state 4595 4563 *Be aware* that this option may print a _lot_ of lines, 4596 4564 so there are risks of losing older messages in the log. 4597 4565 Use this option carefully, maybe worth to setup a 4598 4566 bigger log buffer with "log_buf_len" along with this. 4567 + 4568 + panic_sys_info= A comma separated list of extra information to be dumped 4569 + on panic. 4570 + Format: val[,val...] 4571 + Where @val can be any of the following: 4572 + 4573 + tasks: print all tasks info 4574 + mem: print system memory info 4575 + timers: print timers info 4576 + locks: print locks info if CONFIG_LOCKDEP is on 4577 + ftrace: print ftrace buffer 4578 + all_bt: print all CPUs backtrace (if available in the arch) 4579 + blocked_tasks: print only tasks in uninterruptible (blocked) state 4580 + 4581 + This is a human readable alternative to the 'panic_print' option. 4582 + 4583 + panic_console_replay 4584 + When panic happens, replay all kernel messages on 4585 + consoles at the end of panic. 4599 4586 4600 4587 parkbd.port= [HW] Parallel port number the keyboard adapter is 4601 4588 connected to, default is 0. ··· 6654 6603 Documentation/admin-guide/mm/slab.rst. 6655 6604 (slub_debug legacy name also accepted for now) 6656 6605 6606 + Using this option implies the "no_hash_pointers" 6607 + option which can be undone by adding the 6608 + "hash_pointers=always" option. 6609 + 6657 6610 slab_max_order= [MM] 6658 6611 Determines the maximum allowed order for slabs. 6659 6612 A high setting may cause OOMs due to memory ··· 7086 7031 disable the stack depot thereby saving the static memory 7087 7032 consumed by the stack hash table. By default this is set 7088 7033 to false. 7034 + 7035 + stack_depot_max_pools= [KNL,EARLY] 7036 + Specify the maximum number of pools to use for storing 7037 + stack traces. Pools are allocated on-demand up to this 7038 + limit. Default value is 8191 pools. 7089 7039 7090 7040 stacktrace [FTRACE] 7091 7041 Enabled the stack tracer on boot up.
+19 -1
Documentation/admin-guide/sysctl/kernel.rst
··· 890 890 bit 2 print timer info 891 891 bit 3 print locks info if ``CONFIG_LOCKDEP`` is on 892 892 bit 4 print ftrace buffer 893 - bit 5 print all printk messages in buffer 893 + bit 5 replay all messages on consoles at the end of panic 894 894 bit 6 print all CPUs backtrace (if available in the arch) 895 895 bit 7 print only tasks in uninterruptible (blocked) state 896 896 ===== ============================================ ··· 898 898 So for example to print tasks and memory info on panic, user can:: 899 899 900 900 echo 3 > /proc/sys/kernel/panic_print 901 + 902 + 903 + panic_sys_info 904 + ============== 905 + 906 + A comma separated list of extra information to be dumped on panic, 907 + for example, "tasks,mem,timers,...". It is a human readable alternative 908 + to 'panic_print'. Possible values are: 909 + 910 + ============= =================================================== 911 + tasks print all tasks info 912 + mem print system memory info 913 + timer print timers info 914 + lock print locks info if CONFIG_LOCKDEP is on 915 + ftrace print ftrace buffer 916 + all_bt print all CPUs backtrace (if available in the arch) 917 + blocked_tasks print only tasks in uninterruptible (blocked) state 918 + ============= =================================================== 901 919 902 920 903 921 panic_on_rcu_stall
-1
Documentation/core-api/mm-api.rst
··· 133 133 .. kernel-doc:: mm/mmu_notifier.c 134 134 .. kernel-doc:: mm/balloon_compaction.c 135 135 .. kernel-doc:: mm/huge_memory.c 136 - .. kernel-doc:: mm/io-mapping.c
+5
Documentation/devicetree/bindings/i2c/apple,i2c.yaml
··· 22 22 compatible: 23 23 items: 24 24 - enum: 25 + - apple,s5l8960x-i2c 26 + - apple,t7000-i2c 27 + - apple,s8000-i2c 28 + - apple,t8010-i2c 29 + - apple,t8015-i2c 25 30 - apple,t8103-i2c 26 31 - apple,t8112-i2c 27 32 - apple,t6000-i2c
+179
Documentation/devicetree/bindings/i3c/renesas,i3c.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/i3c/renesas,i3c.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Renesas RZ/G3S and RZ/G3E I3C Bus Interface 8 + 9 + maintainers: 10 + - Wolfram Sang <wsa+renesas@sang-engineering.com> 11 + - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com> 12 + 13 + properties: 14 + compatible: 15 + items: 16 + - enum: 17 + - renesas,r9a08g045-i3c # RZ/G3S 18 + - renesas,r9a09g047-i3c # RZ/G3E 19 + 20 + reg: 21 + maxItems: 1 22 + 23 + interrupts: 24 + items: 25 + - description: Non-recoverable internal error interrupt 26 + - description: Normal transfer error interrupt 27 + - description: Normal transfer abort interrupt 28 + - description: Normal response status buffer full interrupt 29 + - description: Normal command buffer empty interrupt 30 + - description: Normal IBI status buffer full interrupt 31 + - description: Normal Rx data buffer full interrupt 32 + - description: Normal Tx data buffer empty interrupt 33 + - description: Normal receive status buffer full interrupt 34 + - description: START condition detection interrupt 35 + - description: STOP condition detection interrupt 36 + - description: Transmit end interrupt 37 + - description: NACK detection interrupt 38 + - description: Arbitration lost interrupt 39 + - description: Timeout detection interrupt 40 + - description: Wake-up condition detection interrupt 41 + - description: HDR Exit Pattern detection interrupt 42 + minItems: 16 43 + 44 + interrupt-names: 45 + items: 46 + - const: ierr 47 + - const: terr 48 + - const: abort 49 + - const: resp 50 + - const: cmd 51 + - const: ibi 52 + - const: rx 53 + - const: tx 54 + - const: rcv 55 + - const: st 56 + - const: sp 57 + - const: tend 58 + - const: nack 59 + - const: al 60 + - const: tmo 61 + - const: wu 62 + - const: exit 63 + minItems: 16 64 + 65 + clocks: 66 + items: 67 + - description: APB bus clock 68 + - description: transfer clock 69 + - description: SFRs clock 70 + minItems: 2 71 + 72 + clock-names: 73 + items: 74 + - const: pclk 75 + - const: tclk 76 + - const: pclkrw 77 + minItems: 2 78 + 79 + power-domains: 80 + maxItems: 1 81 + 82 + resets: 83 + items: 84 + - description: Reset signal 85 + - description: APB interface reset signal/SCAN reset signal 86 + 87 + reset-names: 88 + items: 89 + - const: presetn 90 + - const: tresetn 91 + 92 + required: 93 + - compatible 94 + - reg 95 + - interrupts 96 + - interrupt-names 97 + - clock-names 98 + - clocks 99 + - power-domains 100 + - resets 101 + - reset-names 102 + 103 + allOf: 104 + - $ref: i3c.yaml# 105 + 106 + - if: 107 + properties: 108 + compatible: 109 + contains: 110 + const: renesas,r9a08g045-i3c 111 + then: 112 + properties: 113 + clocks: 114 + maxItems: 2 115 + clock-names: 116 + maxItems: 2 117 + interrupts: 118 + minItems: 17 119 + interrupt-names: 120 + minItems: 17 121 + 122 + - if: 123 + properties: 124 + compatible: 125 + contains: 126 + const: renesas,r9a09g047-i3c 127 + then: 128 + properties: 129 + clocks: 130 + minItems: 3 131 + clock-names: 132 + minItems: 3 133 + interrupts: 134 + maxItems: 16 135 + interrupt-names: 136 + maxItems: 16 137 + 138 + unevaluatedProperties: false 139 + 140 + examples: 141 + - | 142 + #include <dt-bindings/clock/r9a08g045-cpg.h> 143 + #include <dt-bindings/interrupt-controller/arm-gic.h> 144 + 145 + i3c@1005b000 { 146 + compatible = "renesas,r9a08g045-i3c"; 147 + reg = <0x1005b000 0x1000>; 148 + clocks = <&cpg CPG_MOD R9A08G045_I3C_PCLK>, 149 + <&cpg CPG_MOD R9A08G045_I3C_TCLK>; 150 + clock-names = "pclk", "tclk"; 151 + interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>, 152 + <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>, 153 + <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>, 154 + <GIC_SPI 294 IRQ_TYPE_EDGE_RISING>, 155 + <GIC_SPI 295 IRQ_TYPE_EDGE_RISING>, 156 + <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>, 157 + <GIC_SPI 297 IRQ_TYPE_EDGE_RISING>, 158 + <GIC_SPI 298 IRQ_TYPE_EDGE_RISING>, 159 + <GIC_SPI 299 IRQ_TYPE_EDGE_RISING>, 160 + <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>, 161 + <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>, 162 + <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>, 163 + <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>, 164 + <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>, 165 + <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>, 166 + <GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>, 167 + <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>; 168 + interrupt-names = "ierr", "terr", "abort", "resp", 169 + "cmd", "ibi", "rx", "tx", "rcv", 170 + "st", "sp", "tend", "nack", 171 + "al", "tmo", "wu", "exit"; 172 + resets = <&cpg R9A08G045_I3C_PRESETN>, 173 + <&cpg R9A08G045_I3C_TRESETN>; 174 + reset-names = "presetn", "tresetn"; 175 + power-domains = <&cpg>; 176 + #address-cells = <3>; 177 + #size-cells = <0>; 178 + }; 179 + ...
+20
Documentation/devicetree/bindings/input/syna,rmi4.yaml
··· 89 89 required: 90 90 - reg 91 91 92 + rmi4-f1a@1a: 93 + type: object 94 + additionalProperties: false 95 + $ref: input.yaml# 96 + description: 97 + RMI4 Function 1A is for capacitive keys. 98 + 99 + properties: 100 + reg: 101 + maxItems: 1 102 + 103 + linux,keycodes: 104 + minItems: 1 105 + maxItems: 4 106 + 107 + required: 108 + - reg 109 + 92 110 patternProperties: 93 111 "^rmi4-f1[12]@1[12]$": 94 112 type: object ··· 219 201 220 202 examples: 221 203 - | 204 + #include <dt-bindings/input/linux-event-codes.h> 222 205 #include <dt-bindings/interrupt-controller/irq.h> 223 206 224 207 i2c { ··· 253 234 254 235 rmi4-f1a@1a { 255 236 reg = <0x1a>; 237 + linux,keycodes = <KEY_BACK KEY_HOME KEY_MENU>; 256 238 }; 257 239 }; 258 240 };
+1
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
··· 43 43 - focaltech,ft5452 44 44 - focaltech,ft6236 45 45 - focaltech,ft8201 46 + - focaltech,ft8716 46 47 - focaltech,ft8719 47 48 48 49 reg:
-16
Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt
··· 1 - * NXP LPC32xx SoC Touchscreen Controller (TSC) 2 - 3 - Required properties: 4 - - compatible: must be "nxp,lpc3220-tsc" 5 - - reg: physical base address of the controller and length of memory mapped 6 - region. 7 - - interrupts: The TSC/ADC interrupt 8 - 9 - Example: 10 - 11 - tsc@40048000 { 12 - compatible = "nxp,lpc3220-tsc"; 13 - reg = <0x40048000 0x1000>; 14 - interrupt-parent = <&mic>; 15 - interrupts = <39 0>; 16 - };
+43
Documentation/devicetree/bindings/input/touchscreen/nxp,lpc3220-tsc.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/input/touchscreen/nxp,lpc3220-tsc.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP LPC32xx SoC Touchscreen Controller (TSC) 8 + 9 + maintainers: 10 + - Frank Li <Frank.Li@nxp.com> 11 + 12 + properties: 13 + compatible: 14 + const: nxp,lpc3220-tsc 15 + 16 + reg: 17 + maxItems: 1 18 + 19 + clocks: 20 + maxItems: 1 21 + 22 + interrupts: 23 + maxItems: 1 24 + 25 + required: 26 + - compatible 27 + - reg 28 + - clocks 29 + - interrupts 30 + 31 + additionalProperties: false 32 + 33 + examples: 34 + - | 35 + #include <dt-bindings/clock/lpc32xx-clock.h> 36 + 37 + touchscreen@40048000 { 38 + compatible = "nxp,lpc3220-tsc"; 39 + reg = <0x40048000 0x1000>; 40 + interrupt-parent = <&mic>; 41 + interrupts = <39 0>; 42 + clocks = <&clk LPC32XX_CLK_ADC>; 43 + };
+29
Documentation/devicetree/bindings/input/touchscreen/sitronix,st1232.yaml
··· 37 37 38 38 examples: 39 39 - | 40 + #include <dt-bindings/input/linux-event-codes.h> 40 41 i2c { 41 42 #address-cells = <1>; 42 43 #size-cells = <0>; ··· 47 46 reg = <0x55>; 48 47 interrupts = <2 0>; 49 48 gpios = <&gpio1 166 0>; 49 + 50 + touch-overlay { 51 + segment-0 { 52 + label = "Touchscreen"; 53 + x-origin = <0>; 54 + x-size = <240>; 55 + y-origin = <40>; 56 + y-size = <280>; 57 + }; 58 + 59 + segment-1a { 60 + label = "Camera light"; 61 + linux,code = <KEY_LIGHTS_TOGGLE>; 62 + x-origin = <40>; 63 + x-size = <40>; 64 + y-origin = <0>; 65 + y-size = <40>; 66 + }; 67 + 68 + segment-2a { 69 + label = "Power"; 70 + linux,code = <KEY_POWER>; 71 + x-origin = <160>; 72 + x-size = <40>; 73 + y-origin = <0>; 74 + y-size = <40>; 75 + }; 76 + }; 50 77 }; 51 78 };
+75
Documentation/devicetree/bindings/input/touchscreen/ti.tsc2007.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/input/touchscreen/ti.tsc2007.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Texas Instruments tsc2007 touchscreen controller 8 + 9 + maintainers: 10 + - Frank Li <Frank.Li@nxp.com> 11 + 12 + properties: 13 + compatible: 14 + const: ti,tsc2007 15 + 16 + reg: 17 + maxItems: 1 18 + 19 + interrupts: 20 + maxItems: 1 21 + 22 + ti,x-plate-ohms: 23 + description: X-plate resistance in ohms. 24 + 25 + gpios: true 26 + 27 + pendown-gpio: true 28 + 29 + ti,max-rt: 30 + $ref: /schemas/types.yaml#/definitions/uint32 31 + description: maximum pressure. 32 + 33 + ti,fuzzx: 34 + $ref: /schemas/types.yaml#/definitions/uint32 35 + description: 36 + specifies the absolute input fuzz x value. 37 + If set, it will permit noise in the data up to +- the value given to the fuzz 38 + parameter, that is used to filter noise from the event stream. 39 + 40 + ti,fuzzy: 41 + $ref: /schemas/types.yaml#/definitions/uint32 42 + description: specifies the absolute input fuzz y value. 43 + 44 + ti,fuzzz: 45 + $ref: /schemas/types.yaml#/definitions/uint32 46 + description: specifies the absolute input fuzz z value. 47 + 48 + ti,poll-period: 49 + $ref: /schemas/types.yaml#/definitions/uint32 50 + description: 51 + how much time to wait (in milliseconds) before reading again the 52 + values from the tsc2007. 53 + 54 + required: 55 + - compatible 56 + - reg 57 + - ti,x-plate-ohms 58 + 59 + additionalProperties: false 60 + 61 + examples: 62 + - | 63 + i2c { 64 + #address-cells = <1>; 65 + #size-cells = <0>; 66 + 67 + touch@49 { 68 + compatible = "ti,tsc2007"; 69 + reg = <0x49>; 70 + interrupt-parent = <&gpio4>; 71 + interrupts = <0x0 0x8>; 72 + gpios = <&gpio4 0 0>; 73 + ti,x-plate-ohms = <180>; 74 + }; 75 + };
+119
Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml
··· 87 87 touchscreen-y-plate-ohms: 88 88 description: Resistance of the Y-plate in Ohms 89 89 90 + touch-overlay: 91 + description: | 92 + List of nodes defining segments (touch areas) on the touchscreen. 93 + 94 + This object can be used to describe a series of segments to restrict 95 + the region within touch events are reported or buttons with a specific 96 + functionality. 97 + 98 + This is of special interest if the touchscreen is shipped with a physical 99 + overlay on top of it with a frame that hides some part of the original 100 + touchscreen area. Printed buttons on that overlay are also a typical 101 + use case. 102 + 103 + A new touchscreen area is defined as a sub-node without a key code. If a 104 + key code is defined in the sub-node, it will be interpreted as a button. 105 + 106 + The x-origin and y-origin properties of a touchscreen area define the 107 + offset of a new origin from where the touchscreen events are referenced. 108 + This offset is applied to the events accordingly. The x-size and y-size 109 + properties define the size of the touchscreen effective area. 110 + 111 + The following example shows a new touchscreen area with the new origin 112 + (0',0') for the touch events generated by the device. 113 + 114 + Touchscreen (full area) 115 + ┌────────────────────────────────────────┐ 116 + │ ┌───────────────────────────────┐ │ 117 + │ │ │ │ 118 + │ ├ y-size │ │ 119 + │ │ │ │ 120 + │ │ touchscreen area │ │ 121 + │ │ (no key code) │ │ 122 + │ │ │ │ 123 + │ │ x-size │ │ 124 + │ ┌└──────────────┴────────────────┘ │ 125 + │(0',0') │ 126 + ┌└────────────────────────────────────────┘ 127 + (0,0) 128 + 129 + where (0',0') = (0+x-origin,0+y-origin) 130 + 131 + Sub-nodes with key codes report the touch events on their surface as key 132 + events instead. 133 + 134 + The following example shows a touchscreen with a single button on it. 135 + 136 + Touchscreen (full area) 137 + ┌───────────────────────────────────┐ 138 + │ │ 139 + │ │ 140 + │ ┌─────────┐ │ 141 + │ │button 0 │ │ 142 + │ │KEY_POWER│ │ 143 + │ └─────────┘ │ 144 + │ │ 145 + │ │ 146 + ┌└───────────────────────────────────┘ 147 + (0,0) 148 + 149 + Segments defining buttons and clipped toushcreen areas can be combined 150 + as shown in the following example. 151 + In that case only the events within the touchscreen area are reported 152 + as touch events. Events within the button areas report their associated 153 + key code. Any events outside the defined areas are ignored. 154 + 155 + Touchscreen (full area) 156 + ┌─────────┬──────────────────────────────┐ 157 + │ │ │ 158 + │ │ ┌───────────────────────┐ │ 159 + │ button 0│ │ │ │ 160 + │KEY_POWER│ │ │ │ 161 + │ │ │ │ │ 162 + ├─────────┤ │ touchscreen area │ │ 163 + │ │ │ (no key code) │ │ 164 + │ │ │ │ │ 165 + │ button 1│ │ │ │ 166 + │ KEY_INFO│ ┌└───────────────────────┘ │ 167 + │ │(0',0') │ 168 + ┌└─────────┴──────────────────────────────┘ 169 + (0,0) 170 + 171 + type: object 172 + 173 + patternProperties: 174 + '^segment-': 175 + type: object 176 + description: 177 + Each segment is represented as a sub-node. 178 + properties: 179 + x-origin: 180 + description: horizontal origin of the node area 181 + $ref: /schemas/types.yaml#/definitions/uint32 182 + 183 + y-origin: 184 + description: vertical origin of the node area 185 + $ref: /schemas/types.yaml#/definitions/uint32 186 + 187 + x-size: 188 + description: horizontal resolution of the node area 189 + $ref: /schemas/types.yaml#/definitions/uint32 190 + 191 + y-size: 192 + description: vertical resolution of the node area 193 + $ref: /schemas/types.yaml#/definitions/uint32 194 + 195 + label: 196 + description: descriptive name of the segment 197 + $ref: /schemas/types.yaml#/definitions/string 198 + 199 + linux,code: true 200 + 201 + required: 202 + - x-origin 203 + - y-origin 204 + - x-size 205 + - y-size 206 + 207 + unevaluatedProperties: false 208 + 90 209 dependencies: 91 210 touchscreen-size-x: [ touchscreen-size-y ] 92 211 touchscreen-size-y: [ touchscreen-size-x ]
-39
Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
··· 1 - * Texas Instruments tsc2007 touchscreen controller 2 - 3 - Required properties: 4 - - compatible: must be "ti,tsc2007". 5 - - reg: I2C address of the chip. 6 - - ti,x-plate-ohms: X-plate resistance in ohms. 7 - 8 - Optional properties: 9 - - gpios: the interrupt gpio the chip is connected to (through the penirq pin). 10 - The penirq pin goes to low when the panel is touched. 11 - (see GPIO binding[1] for more details). 12 - - interrupts: (gpio) interrupt to which the chip is connected 13 - (see interrupt binding[0]). 14 - - ti,max-rt: maximum pressure. 15 - - ti,fuzzx: specifies the absolute input fuzz x value. 16 - If set, it will permit noise in the data up to +- the value given to the fuzz 17 - parameter, that is used to filter noise from the event stream. 18 - - ti,fuzzy: specifies the absolute input fuzz y value. 19 - - ti,fuzzz: specifies the absolute input fuzz z value. 20 - - ti,poll-period: how much time to wait (in milliseconds) before reading again the 21 - values from the tsc2007. 22 - 23 - [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt 24 - [1]: Documentation/devicetree/bindings/gpio/gpio.txt 25 - 26 - Example: 27 - &i2c1 { 28 - /* ... */ 29 - tsc2007@49 { 30 - compatible = "ti,tsc2007"; 31 - reg = <0x49>; 32 - interrupt-parent = <&gpio4>; 33 - interrupts = <0x0 0x8>; 34 - gpios = <&gpio4 0 0>; 35 - ti,x-plate-ohms = <180>; 36 - }; 37 - 38 - /* ... */ 39 - };
+8 -3
Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
··· 16 16 17 17 properties: 18 18 compatible: 19 - enum: 20 - - amlogic,a4-rtc 21 - - amlogic,a5-rtc 19 + oneOf: 20 + - enum: 21 + - amlogic,a4-rtc 22 + - amlogic,a5-rtc 23 + - items: 24 + - enum: 25 + - amlogic,c3-rtc 26 + - const: amlogic,a5-rtc 22 27 23 28 reg: 24 29 maxItems: 1
+6 -1
Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml
··· 18 18 19 19 properties: 20 20 compatible: 21 - const: nxp,lpc1788-rtc 21 + oneOf: 22 + - items: 23 + - enum: 24 + - nxp,lpc1850-rtc 25 + - const: nxp,lpc1788-rtc 26 + - const: nxp,lpc1788-rtc 22 27 23 28 reg: 24 29 maxItems: 1
+49
Documentation/devicetree/bindings/rtc/nxp,lpc3220-rtc.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/rtc/nxp,lpc3220-rtc.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP LPC32xx SoC Real-time Clock 8 + 9 + maintainers: 10 + - Frank Li <Frank.Li@nxp.com> 11 + 12 + properties: 13 + compatible: 14 + enum: 15 + - nxp,lpc3220-rtc 16 + 17 + reg: 18 + maxItems: 1 19 + 20 + clocks: 21 + maxItems: 1 22 + 23 + interrupts: 24 + maxItems: 1 25 + 26 + start-year: true 27 + 28 + required: 29 + - compatible 30 + - reg 31 + 32 + allOf: 33 + - $ref: rtc.yaml# 34 + 35 + unevaluatedProperties: false 36 + 37 + examples: 38 + - | 39 + #include <dt-bindings/interrupt-controller/irq.h> 40 + #include <dt-bindings/clock/lpc32xx-clock.h> 41 + 42 + rtc@40024000 { 43 + compatible = "nxp,lpc3220-rtc"; 44 + reg = <0x40024000 0x1000>; 45 + interrupt-parent = <&sic1>; 46 + interrupts = <20 IRQ_TYPE_LEVEL_HIGH>; 47 + clocks = <&clk LPC32XX_CLK_RTC>; 48 + }; 49 +
+32 -1
Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
··· 12 12 properties: 13 13 compatible: 14 14 enum: 15 + - microcrystal,rv8063 15 16 - microcrystal,rv8263 16 17 - nxp,pcf85063 17 18 - nxp,pcf85063a ··· 45 44 46 45 wakeup-source: true 47 46 47 + spi-cs-high: true 48 + 49 + spi-3wire: true 50 + 48 51 allOf: 52 + - $ref: /schemas/spi/spi-peripheral-props.yaml# 49 53 - $ref: rtc.yaml# 50 54 - if: 51 55 properties: 52 56 compatible: 53 57 contains: 54 58 enum: 59 + - microcrystal,rv8063 55 60 - microcrystal,rv8263 56 61 then: 57 62 properties: ··· 72 65 properties: 73 66 quartz-load-femtofarads: 74 67 const: 7000 68 + - if: 69 + properties: 70 + compatible: 71 + not: 72 + contains: 73 + enum: 74 + - microcrystal,rv8063 75 + then: 76 + properties: 77 + spi-cs-high: false 78 + spi-3wire: false 75 79 76 80 required: 77 81 - compatible 78 82 - reg 79 83 80 - additionalProperties: false 84 + unevaluatedProperties: false 81 85 82 86 examples: 83 87 - | ··· 108 90 }; 109 91 }; 110 92 }; 93 + 94 + - | 95 + spi { 96 + #address-cells = <1>; 97 + #size-cells = <0>; 98 + 99 + rtc@0 { 100 + compatible = "microcrystal,rv8063"; 101 + reg = <0>; 102 + spi-cs-high; 103 + spi-3wire; 104 + }; 105 + };
-2
Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
··· 63 63 - microcrystal,rv3029 64 64 # Real Time Clock 65 65 - microcrystal,rv8523 66 - # NXP LPC32xx SoC Real-time Clock 67 - - nxp,lpc3220-rtc 68 66 # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC 69 67 - ricoh,r2025sd 70 68 # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
+1 -1
Documentation/devicetree/bindings/soc/sophgo/sophgo,cv1800b-rtc.yaml Documentation/devicetree/bindings/rtc/sophgo,cv1800b-rtc.yaml
··· 1 1 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 2 %YAML 1.2 3 3 --- 4 - $id: http://devicetree.org/schemas/sophgo/sophgo,cv1800b-rtc.yaml# 4 + $id: http://devicetree.org/schemas/rtc/sophgo,cv1800b-rtc.yaml# 5 5 $schema: http://devicetree.org/meta-schemas/core.yaml# 6 6 7 7 title: Real Time Clock of the Sophgo CV1800 SoC
+40 -6
Documentation/devicetree/bindings/ufs/mediatek,ufs.yaml
··· 9 9 maintainers: 10 10 - Stanley Chu <stanley.chu@mediatek.com> 11 11 12 - allOf: 13 - - $ref: ufs-common.yaml 14 - 15 12 properties: 16 13 compatible: 17 14 enum: 18 15 - mediatek,mt8183-ufshci 19 16 - mediatek,mt8192-ufshci 17 + - mediatek,mt8195-ufshci 20 18 21 19 clocks: 22 - maxItems: 1 20 + minItems: 1 21 + maxItems: 8 23 22 24 23 clock-names: 25 - items: 26 - - const: ufs 24 + minItems: 1 25 + maxItems: 8 27 26 28 27 phys: 29 28 maxItems: 1 ··· 31 32 maxItems: 1 32 33 33 34 vcc-supply: true 35 + 36 + mediatek,ufs-disable-mcq: 37 + $ref: /schemas/types.yaml#/definitions/flag 38 + description: The mask to disable MCQ (Multi-Circular Queue) for UFS host. 34 39 35 40 required: 36 41 - compatible ··· 45 42 - vcc-supply 46 43 47 44 unevaluatedProperties: false 45 + 46 + allOf: 47 + - $ref: ufs-common.yaml 48 + 49 + - if: 50 + properties: 51 + compatible: 52 + contains: 53 + enum: 54 + - mediatek,mt8195-ufshci 55 + then: 56 + properties: 57 + clocks: 58 + minItems: 8 59 + clock-names: 60 + items: 61 + - const: ufs 62 + - const: ufs_aes 63 + - const: ufs_tick 64 + - const: unipro_sysclk 65 + - const: unipro_tick 66 + - const: unipro_mp_bclk 67 + - const: ufs_tx_symbol 68 + - const: ufs_mem_sub 69 + else: 70 + properties: 71 + clocks: 72 + maxItems: 1 73 + clock-names: 74 + items: 75 + - const: ufs 48 76 49 77 examples: 50 78 - |
+3 -3
Documentation/filesystems/f2fs.rst
··· 238 238 grpjquota=<file> information can be properly updated during recovery flow, 239 239 prjjquota=<file> <quota file>: must be in root directory; 240 240 jqfmt=<quota type> <quota type>: [vfsold,vfsv0,vfsv1]. 241 - offusrjquota Turn off user journalled quota. 242 - offgrpjquota Turn off group journalled quota. 243 - offprjjquota Turn off project journalled quota. 241 + usrjquota= Turn off user journalled quota. 242 + grpjquota= Turn off group journalled quota. 243 + prjjquota= Turn off project journalled quota. 244 244 quota Enable plain user disk quota accounting. 245 245 noquota Disable all plain disk quota option. 246 246 alloc_mode=%s Adjust block allocation policy, which supports "reuse"
+19 -2
Documentation/input/devices/edt-ft5x06.rst
··· 29 29 30 30 31 31 For debugging purposes the driver provides a few files in the debug 32 - filesystem (if available in the kernel). In /sys/kernel/debug/edt_ft5x06 33 - you'll find the following files: 32 + filesystem (if available in the kernel). They are located in: 33 + 34 + /sys/kernel/debug/i2c/<i2c-bus>/<i2c-device>/ 35 + 36 + If you don't know the bus and device numbers, you can look them up with this 37 + command: 38 + 39 + $ ls -l /sys/bus/i2c/drivers/edt_ft5x06 40 + 41 + The dereference of the symlink will contain the needed information. You will 42 + need the last two elements of its path: 43 + 44 + 0-0038 -> ../../../../devices/platform/soc/fcfee800.i2c/i2c-0/0-0038 45 + 46 + So in this case, the location for the debug files is: 47 + 48 + /sys/kernel/debug/i2c/i2c-0/0-0038/ 49 + 50 + There, you'll find the following files: 34 51 35 52 num_x, num_y: 36 53 (readonly) contains the number of sensor fields in X- and
+16 -3
Documentation/input/gamepad.rst
··· 190 190 191 191 Rumble is advertised as FF_RUMBLE. 192 192 193 + - Grip buttons: 194 + 195 + Many pads include buttons on the rear, usually referred to as either grip or 196 + rear buttons, or paddles. These are often reprogrammable by the firmware to 197 + appear as "normal" buttons, but are sometimes exposed to software too. Some 198 + notable examples of this are the Steam Deck, which has R4, R5, L4, and L5 on 199 + the back; the Xbox Elite pads, which have P1-P4; and the Switch 2 Pro 200 + Controller, which has GL and GR. 201 + 202 + For these controllers, BTN_GRIPR and BTN_GRIPR2 should be used for the top 203 + and bottom (if present) right grip button(s), and BTN_GRIPL and BTN_GRIPL2 204 + should be used for the top and bottom (if present) left grip button(s). 205 + 193 206 - Profile: 194 207 195 - Some pads provide a multi-value profile selection switch. An example is the 196 - XBox Adaptive and the XBox Elite 2 controllers. When the active profile is 197 - switched, its newly selected value is emitted as an ABS_PROFILE event. 208 + Some pads provide a multi-value profile selection switch. Examples include 209 + the Xbox Adaptive and the Xbox Elite 2 controllers. When the active profile 210 + is switched, its newly selected value is emitted as an ABS_PROFILE event.
+4 -4
Documentation/kbuild/kconfig.rst
··· 67 67 with its value when saving the configuration, instead of using the 68 68 default, ``CONFIG_``. 69 69 70 - Environment variables for ``{allyes/allmod/allno/rand}config``: 70 + Environment variables for ``{allyes/allmod/allno/alldef/rand}config``: 71 71 72 72 ``KCONFIG_ALLCONFIG`` 73 - The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also 74 - use the environment variable KCONFIG_ALLCONFIG as a flag or a filename 75 - that contains config symbols that the user requires to be set to a 73 + The allyesconfig/allmodconfig/alldefconfig/allnoconfig/randconfig variants 74 + can also use the environment variable KCONFIG_ALLCONFIG as a flag or a 75 + filename that contains config symbols that the user requires to be set to a 76 76 specific value. If KCONFIG_ALLCONFIG is used without a filename where 77 77 KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", ``make *config`` 78 78 checks for a file named "all{yes/mod/no/def/random}.config"
+2 -2
Documentation/userspace-api/media/rc/rc-protos.rst
··· 449 449 xbox-dvd (RC_PROTO_XBOX_DVD) 450 450 ---------------------------- 451 451 452 - This protocol is used by XBox DVD Remote, which was made for the original 453 - XBox. There is no in-kernel decoder or encoder for this protocol. The usb 452 + This protocol is used by Xbox DVD Remote, which was made for the original 453 + Xbox. There is no in-kernel decoder or encoder for this protocol. The usb 454 454 device decodes the protocol. There is a BPF decoder available in v4l-utils.
+38 -11
MAINTAINERS
··· 6713 6713 F: drivers/input/keyboard/dlink-dir685-touchkeys.c 6714 6714 6715 6715 DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK 6716 - M: Joshua Kinard <kumba@gentoo.org> 6716 + M: Joshua Kinard <linux@kumba.dev> 6717 6717 S: Maintained 6718 6718 F: drivers/rtc/rtc-ds1685.c 6719 6719 F: include/linux/rtc/ds1685.h ··· 11100 11100 F: drivers/infiniband/hw/hns/ 11101 11101 11102 11102 HISILICON SAS Controller 11103 - M: Yihang Li <liyihang9@huawei.com> 11103 + M: Yihang Li <liyihang9@h-partners.com> 11104 11104 S: Supported 11105 11105 W: http://www.hisilicon.com 11106 11106 F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt ··· 11612 11612 F: Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml 11613 11613 F: drivers/i3c/master/i3c-master-cdns.c 11614 11614 11615 + I3C DRIVER FOR RENESAS 11616 + M: Wolfram Sang <wsa+renesas@sang-engineering.com> 11617 + M: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com> 11618 + S: Supported 11619 + F: Documentation/devicetree/bindings/i3c/renesas,i3c.yaml 11620 + F: drivers/i3c/master/renesas-i3c.c 11621 + 11615 11622 I3C DRIVER FOR SYNOPSYS DESIGNWARE 11616 11623 S: Orphan 11617 11624 F: Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml ··· 11629 11622 R: Frank Li <Frank.Li@nxp.com> 11630 11623 L: linux-i3c@lists.infradead.org (moderated for non-subscribers) 11631 11624 S: Maintained 11625 + Q: https://patchwork.kernel.org/project/linux-i3c/list/ 11632 11626 C: irc://chat.freenode.net/linux-i3c 11633 11627 T: git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git 11634 11628 F: Documentation/ABI/testing/sysfs-bus-i3c ··· 13174 13166 F: scripts/Makefile.kasan 13175 13167 13176 13168 KCONFIG 13177 - M: Masahiro Yamada <masahiroy@kernel.org> 13178 13169 L: linux-kbuild@vger.kernel.org 13179 - S: Maintained 13170 + S: Orphan 13180 13171 Q: https://patchwork.kernel.org/project/linux-kbuild/list/ 13181 - T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kbuild 13182 13172 F: Documentation/kbuild/kconfig* 13183 13173 F: scripts/Kconfig.include 13184 13174 F: scripts/kconfig/ ··· 13241 13235 F: fs/autofs/ 13242 13236 13243 13237 KERNEL BUILD + files below scripts/ (unless maintained elsewhere) 13244 - M: Masahiro Yamada <masahiroy@kernel.org> 13245 - R: Nathan Chancellor <nathan@kernel.org> 13246 - R: Nicolas Schier <nicolas@fjasle.eu> 13238 + M: Nathan Chancellor <nathan@kernel.org> 13239 + M: Nicolas Schier <nicolas@fjasle.eu> 13247 13240 L: linux-kbuild@vger.kernel.org 13248 - S: Maintained 13241 + S: Odd Fixes 13249 13242 Q: https://patchwork.kernel.org/project/linux-kbuild/list/ 13250 - T: git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git 13243 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git 13251 13244 F: Documentation/kbuild/ 13252 13245 F: Makefile 13253 13246 F: scripts/*vmlinux* ··· 13541 13536 F: Documentation/core-api/kho/* 13542 13537 F: include/linux/kexec_handover.h 13543 13538 F: kernel/kexec_handover.c 13539 + F: tools/testing/selftests/kho/ 13544 13540 13545 13541 KEYS-ENCRYPTED 13546 13542 M: Mimi Zohar <zohar@linux.ibm.com> ··· 19739 19733 F: include/linux/delayacct.h 19740 19734 F: kernel/delayacct.c 19741 19735 19736 + TASK DELAY MONITORING TOOLS 19737 + M: Andrew Morton <akpm@linux-foundation.org> 19738 + M: Wang Yaxin <wang.yaxin@zte.com.cn> 19739 + M: Fan Yu <fan.yu9@zte.com.cn> 19740 + L: linux-kernel@vger.kernel.org 19741 + S: Maintained 19742 + F: Documentation/accounting/delay-accounting.rst 19743 + F: tools/accounting/delaytop.c 19744 + F: tools/accounting/getdelays.c 19745 + 19742 19746 PERFORMANCE EVENTS SUBSYSTEM 19743 19747 M: Peter Zijlstra <peterz@infradead.org> 19744 19748 M: Ingo Molnar <mingo@redhat.com> ··· 22048 22032 22049 22033 RUST [ALLOC] 22050 22034 M: Danilo Krummrich <dakr@kernel.org> 22035 + R: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> 22036 + R: Vlastimil Babka <vbabka@suse.cz> 22037 + R: Liam R. Howlett <Liam.Howlett@oracle.com> 22038 + R: Uladzislau Rezki <urezki@gmail.com> 22051 22039 L: rust-for-linux@vger.kernel.org 22052 22040 S: Maintained 22053 22041 T: git https://github.com/Rust-for-Linux/linux.git alloc-next ··· 23390 23370 F: drivers/md/raid* 23391 23371 F: include/linux/raid/ 23392 23372 F: include/uapi/linux/raid/ 23373 + F: lib/raid6/ 23393 23374 23394 23375 SOLIDRUN CLEARFOG SUPPORT 23395 23376 M: Russell King <linux@armlinux.org.uk> ··· 25499 25478 S: Maintained 25500 25479 F: drivers/platform/x86/toshiba-wmi.c 25501 25480 25481 + TOUCH OVERLAY 25482 + M: Javier Carrasco <javier.carrasco@wolfvision.net> 25483 + L: linux-input@vger.kernel.org 25484 + S: Maintained 25485 + F: drivers/input/touch-overlay.c 25486 + F: include/linux/input/touch-overlay.h 25487 + 25502 25488 TPM DEVICE DRIVER 25503 25489 M: Peter Huewe <peterhuewe@gmx.de> 25504 25490 M: Jarkko Sakkinen <jarkko@kernel.org> ··· 26462 26434 F: drivers/vfio/platform/ 26463 26435 26464 26436 VFIO QAT PCI DRIVER 26465 - M: Xin Zeng <xin.zeng@intel.com> 26466 26437 M: Giovanni Cabiddu <giovanni.cabiddu@intel.com> 26467 26438 L: kvm@vger.kernel.org 26468 26439 L: qat-linux@intel.com
+9 -2
Makefile
··· 479 479 -Wrust_2018_idioms \ 480 480 -Wunreachable_pub \ 481 481 -Wclippy::all \ 482 + -Wclippy::as_ptr_cast_mut \ 483 + -Wclippy::as_underscore \ 484 + -Wclippy::cast_lossless \ 482 485 -Wclippy::ignored_unit_patterns \ 483 486 -Wclippy::mut_mut \ 484 487 -Wclippy::needless_bitwise_bool \ 485 488 -Aclippy::needless_lifetimes \ 486 489 -Wclippy::no_mangle_with_rust_abi \ 490 + -Wclippy::ptr_as_ptr \ 491 + -Wclippy::ptr_cast_constness \ 492 + -Wclippy::ref_as_ptr \ 487 493 -Wclippy::undocumented_unsafe_blocks \ 488 494 -Wclippy::unnecessary_safety_comment \ 489 495 -Wclippy::unnecessary_safety_doc \ ··· 549 543 LZ4 = lz4 550 544 XZ = xz 551 545 ZSTD = zstd 546 + TAR = tar 552 547 553 548 CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ 554 549 -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) ··· 629 622 export HOSTRUSTC KBUILD_HOSTRUSTFLAGS 630 623 export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL 631 624 export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX 632 - export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD 625 + export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD TAR 633 626 export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS KBUILD_PROCMACROLDFLAGS LDFLAGS_MODULE 634 627 export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS 635 628 ··· 1142 1135 KBUILD_USERLDFLAGS += $(filter -m32 -m64 --target=%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) 1143 1136 1144 1137 # userspace programs are linked via the compiler, use the correct linker 1145 - ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_LD_IS_LLD),yy) 1138 + ifdef CONFIG_CC_IS_CLANG 1146 1139 KBUILD_USERLDFLAGS += --ld-path=$(LD) 1147 1140 endif 1148 1141
+7 -4
arch/alpha/kernel/core_marvel.c
··· 17 17 #include <linux/vmalloc.h> 18 18 #include <linux/mc146818rtc.h> 19 19 #include <linux/rtc.h> 20 + #include <linux/string.h> 20 21 #include <linux/module.h> 21 22 #include <linux/memblock.h> 22 23 ··· 80 79 { 81 80 char tmp[80]; 82 81 char *name; 83 - 84 - sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port); 85 - name = memblock_alloc_or_panic(strlen(tmp) + 1, SMP_CACHE_BYTES); 86 - strcpy(name, tmp); 82 + size_t sz; 83 + 84 + sz = scnprintf(tmp, sizeof(tmp), "PCI %s PE %d PORT %d", str, pe, port); 85 + sz += 1; /* NUL terminator */ 86 + name = memblock_alloc_or_panic(sz, SMP_CACHE_BYTES); 87 + strscpy(name, tmp, sz); 87 88 88 89 return name; 89 90 }
-160
arch/arm/include/asm/cti.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef __ASMARM_CTI_H 3 - #define __ASMARM_CTI_H 4 - 5 - #include <asm/io.h> 6 - #include <asm/hardware/coresight.h> 7 - 8 - /* The registers' definition is from section 3.2 of 9 - * Embedded Cross Trigger Revision: r0p0 10 - */ 11 - #define CTICONTROL 0x000 12 - #define CTISTATUS 0x004 13 - #define CTILOCK 0x008 14 - #define CTIPROTECTION 0x00C 15 - #define CTIINTACK 0x010 16 - #define CTIAPPSET 0x014 17 - #define CTIAPPCLEAR 0x018 18 - #define CTIAPPPULSE 0x01c 19 - #define CTIINEN 0x020 20 - #define CTIOUTEN 0x0A0 21 - #define CTITRIGINSTATUS 0x130 22 - #define CTITRIGOUTSTATUS 0x134 23 - #define CTICHINSTATUS 0x138 24 - #define CTICHOUTSTATUS 0x13c 25 - #define CTIPERIPHID0 0xFE0 26 - #define CTIPERIPHID1 0xFE4 27 - #define CTIPERIPHID2 0xFE8 28 - #define CTIPERIPHID3 0xFEC 29 - #define CTIPCELLID0 0xFF0 30 - #define CTIPCELLID1 0xFF4 31 - #define CTIPCELLID2 0xFF8 32 - #define CTIPCELLID3 0xFFC 33 - 34 - /* The below are from section 3.6.4 of 35 - * CoreSight v1.0 Architecture Specification 36 - */ 37 - #define LOCKACCESS 0xFB0 38 - #define LOCKSTATUS 0xFB4 39 - 40 - /** 41 - * struct cti - cross trigger interface struct 42 - * @base: mapped virtual address for the cti base 43 - * @irq: irq number for the cti 44 - * @trig_out_for_irq: triger out number which will cause 45 - * the @irq happen 46 - * 47 - * cti struct used to operate cti registers. 48 - */ 49 - struct cti { 50 - void __iomem *base; 51 - int irq; 52 - int trig_out_for_irq; 53 - }; 54 - 55 - /** 56 - * cti_init - initialize the cti instance 57 - * @cti: cti instance 58 - * @base: mapped virtual address for the cti base 59 - * @irq: irq number for the cti 60 - * @trig_out: triger out number which will cause 61 - * the @irq happen 62 - * 63 - * called by machine code to pass the board dependent 64 - * @base, @irq and @trig_out to cti. 65 - */ 66 - static inline void cti_init(struct cti *cti, 67 - void __iomem *base, int irq, int trig_out) 68 - { 69 - cti->base = base; 70 - cti->irq = irq; 71 - cti->trig_out_for_irq = trig_out; 72 - } 73 - 74 - /** 75 - * cti_map_trigger - use the @chan to map @trig_in to @trig_out 76 - * @cti: cti instance 77 - * @trig_in: trigger in number 78 - * @trig_out: trigger out number 79 - * @channel: channel number 80 - * 81 - * This function maps one trigger in of @trig_in to one trigger 82 - * out of @trig_out using the channel @chan. 83 - */ 84 - static inline void cti_map_trigger(struct cti *cti, 85 - int trig_in, int trig_out, int chan) 86 - { 87 - void __iomem *base = cti->base; 88 - unsigned long val; 89 - 90 - val = __raw_readl(base + CTIINEN + trig_in * 4); 91 - val |= BIT(chan); 92 - __raw_writel(val, base + CTIINEN + trig_in * 4); 93 - 94 - val = __raw_readl(base + CTIOUTEN + trig_out * 4); 95 - val |= BIT(chan); 96 - __raw_writel(val, base + CTIOUTEN + trig_out * 4); 97 - } 98 - 99 - /** 100 - * cti_enable - enable the cti module 101 - * @cti: cti instance 102 - * 103 - * enable the cti module 104 - */ 105 - static inline void cti_enable(struct cti *cti) 106 - { 107 - __raw_writel(0x1, cti->base + CTICONTROL); 108 - } 109 - 110 - /** 111 - * cti_disable - disable the cti module 112 - * @cti: cti instance 113 - * 114 - * enable the cti module 115 - */ 116 - static inline void cti_disable(struct cti *cti) 117 - { 118 - __raw_writel(0, cti->base + CTICONTROL); 119 - } 120 - 121 - /** 122 - * cti_irq_ack - clear the cti irq 123 - * @cti: cti instance 124 - * 125 - * clear the cti irq 126 - */ 127 - static inline void cti_irq_ack(struct cti *cti) 128 - { 129 - void __iomem *base = cti->base; 130 - unsigned long val; 131 - 132 - val = __raw_readl(base + CTIINTACK); 133 - val |= BIT(cti->trig_out_for_irq); 134 - __raw_writel(val, base + CTIINTACK); 135 - } 136 - 137 - /** 138 - * cti_unlock - unlock cti module 139 - * @cti: cti instance 140 - * 141 - * unlock the cti module, or else any writes to the cti 142 - * module is not allowed. 143 - */ 144 - static inline void cti_unlock(struct cti *cti) 145 - { 146 - __raw_writel(CS_LAR_KEY, cti->base + LOCKACCESS); 147 - } 148 - 149 - /** 150 - * cti_lock - lock cti module 151 - * @cti: cti instance 152 - * 153 - * lock the cti module, so any writes to the cti 154 - * module will be not allowed. 155 - */ 156 - static inline void cti_lock(struct cti *cti) 157 - { 158 - __raw_writel(~CS_LAR_KEY, cti->base + LOCKACCESS); 159 - } 160 - #endif
+1 -1
arch/arm/kernel/setup.c
··· 1004 1004 total_mem = get_total_mem(); 1005 1005 ret = parse_crashkernel(boot_command_line, total_mem, 1006 1006 &crash_size, &crash_base, 1007 - NULL, NULL); 1007 + NULL, NULL, NULL); 1008 1008 /* invalid value specified or crashkernel=0 */ 1009 1009 if (ret || !crash_size) 1010 1010 return;
+25
arch/arm64/boot/dts/mediatek/mt8195.dtsi
··· 1430 1430 status = "disabled"; 1431 1431 }; 1432 1432 1433 + ufshci: ufshci@11270000 { 1434 + compatible = "mediatek,mt8195-ufshci"; 1435 + reg = <0 0x11270000 0 0x2300>; 1436 + interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH 0>; 1437 + phys = <&ufsphy>; 1438 + clocks = <&infracfg_ao CLK_INFRA_AO_AES_UFSFDE>, 1439 + <&infracfg_ao CLK_INFRA_AO_AES>, 1440 + <&infracfg_ao CLK_INFRA_AO_UFS_TICK>, 1441 + <&infracfg_ao CLK_INFRA_AO_UNIPRO_SYS>, 1442 + <&infracfg_ao CLK_INFRA_AO_UNIPRO_TICK>, 1443 + <&infracfg_ao CLK_INFRA_AO_UFS_MP_SAP_B>, 1444 + <&infracfg_ao CLK_INFRA_AO_UFS_TX_SYMBOL>, 1445 + <&infracfg_ao CLK_INFRA_AO_PERI_UFS_MEM_SUB>; 1446 + clock-names = "ufs", "ufs_aes", "ufs_tick", 1447 + "unipro_sysclk", "unipro_tick", 1448 + "unipro_mp_bclk", "ufs_tx_symbol", 1449 + "ufs_mem_sub"; 1450 + freq-table-hz = <0 0>, <0 0>, <0 0>, 1451 + <0 0>, <0 0>, <0 0>, 1452 + <0 0>, <0 0>; 1453 + 1454 + mediatek,ufs-disable-mcq; 1455 + status = "disabled"; 1456 + }; 1457 + 1433 1458 lvts_mcu: thermal-sensor@11278000 { 1434 1459 compatible = "mediatek,mt8195-lvts-mcu"; 1435 1460 reg = <0 0x11278000 0 0x1000>;
+29 -4
arch/arm64/include/asm/asm-bug.h
··· 21 21 #endif 22 22 23 23 #ifdef CONFIG_GENERIC_BUG 24 - 25 - #define __BUG_ENTRY(flags) \ 24 + #define __BUG_ENTRY_START \ 26 25 .pushsection __bug_table,"aw"; \ 27 26 .align 2; \ 28 27 14470: .long 14471f - .; \ 29 - _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \ 30 - .short flags; \ 28 + 29 + #define __BUG_ENTRY_END \ 31 30 .align 2; \ 32 31 .popsection; \ 33 32 14471: 33 + 34 + #define __BUG_ENTRY(flags) \ 35 + __BUG_ENTRY_START \ 36 + _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \ 37 + .short flags; \ 38 + __BUG_ENTRY_END 34 39 #else 35 40 #define __BUG_ENTRY(flags) 36 41 #endif ··· 45 40 brk BUG_BRK_IMM 46 41 47 42 #define ASM_BUG() ASM_BUG_FLAGS(0) 43 + 44 + #ifdef CONFIG_DEBUG_BUGVERBOSE 45 + #define __BUG_LOCATION_STRING(file, line) \ 46 + ".long " file "- .;" \ 47 + ".short " line ";" 48 + #else 49 + #define __BUG_LOCATION_STRING(file, line) 50 + #endif 51 + 52 + #define __BUG_ENTRY_STRING(file, line, flags) \ 53 + __stringify(__BUG_ENTRY_START) \ 54 + __BUG_LOCATION_STRING(file, line) \ 55 + ".short " flags ";" \ 56 + __stringify(__BUG_ENTRY_END) 57 + 58 + #define ARCH_WARN_ASM(file, line, flags, size) \ 59 + __BUG_ENTRY_STRING(file, line, flags) \ 60 + __stringify(brk BUG_BRK_IMM) 61 + 62 + #define ARCH_WARN_REACHABLE 48 63 49 64 #endif /* __ASM_ASM_BUG_H */
+1 -1
arch/arm64/mm/init.c
··· 106 106 107 107 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 108 108 &crash_size, &crash_base, 109 - &low_size, &high); 109 + &low_size, NULL, &high); 110 110 if (ret) 111 111 return; 112 112
+2 -2
arch/arm64/mm/mmu.c
··· 721 721 722 722 static void __init declare_vma(struct vm_struct *vma, 723 723 void *va_start, void *va_end, 724 - vm_flags_t vm_flags) 724 + unsigned long vm_flags) 725 725 { 726 726 phys_addr_t pa_start = __pa_symbol(va_start); 727 727 unsigned long size = va_end - va_start; ··· 1528 1528 pte_t modify_prot_start_ptes(struct vm_area_struct *vma, unsigned long addr, 1529 1529 pte_t *ptep, unsigned int nr) 1530 1530 { 1531 - pte_t pte = get_and_clear_full_ptes(vma->vm_mm, addr, ptep, nr, /* full = */ 0); 1531 + pte_t pte = get_and_clear_ptes(vma->vm_mm, addr, ptep, nr); 1532 1532 1533 1533 if (alternative_has_cap_unlikely(ARM64_WORKAROUND_2645198)) { 1534 1534 /*
+1 -1
arch/loongarch/kernel/setup.c
··· 265 265 return; 266 266 267 267 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 268 - &crash_size, &crash_base, &low_size, &high); 268 + &crash_size, &crash_base, &low_size, NULL, &high); 269 269 if (ret) 270 270 return; 271 271
+1 -1
arch/mips/kernel/setup.c
··· 458 458 total_mem = memblock_phys_mem_size(); 459 459 ret = parse_crashkernel(boot_command_line, total_mem, 460 460 &crash_size, &crash_base, 461 - NULL, NULL); 461 + NULL, NULL, NULL); 462 462 if (ret != 0 || crash_size <= 0) 463 463 return; 464 464
+1 -1
arch/openrisc/include/asm/mmu.h
··· 15 15 #ifndef __ASM_OPENRISC_MMU_H 16 16 #define __ASM_OPENRISC_MMU_H 17 17 18 - #ifndef __ASSEMBLY__ 18 + #ifndef __ASSEMBLER__ 19 19 typedef unsigned long mm_context_t; 20 20 #endif 21 21
+4 -4
arch/openrisc/include/asm/page.h
··· 25 25 */ 26 26 #include <asm/setup.h> 27 27 28 - #ifndef __ASSEMBLY__ 28 + #ifndef __ASSEMBLER__ 29 29 30 30 #define clear_page(page) memset((page), 0, PAGE_SIZE) 31 31 #define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) ··· 55 55 #define __pgd(x) ((pgd_t) { (x) }) 56 56 #define __pgprot(x) ((pgprot_t) { (x) }) 57 57 58 - #endif /* !__ASSEMBLY__ */ 58 + #endif /* !__ASSEMBLER__ */ 59 59 60 60 61 - #ifndef __ASSEMBLY__ 61 + #ifndef __ASSEMBLER__ 62 62 63 63 #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) 64 64 #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) ··· 73 73 74 74 #define virt_addr_valid(kaddr) (pfn_valid(virt_to_pfn(kaddr))) 75 75 76 - #endif /* __ASSEMBLY__ */ 76 + #endif /* __ASSEMBLER__ */ 77 77 78 78 #include <asm-generic/memory_model.h> 79 79 #include <asm-generic/getorder.h>
+2 -2
arch/openrisc/include/asm/pgtable.h
··· 23 23 24 24 #include <asm-generic/pgtable-nopmd.h> 25 25 26 - #ifndef __ASSEMBLY__ 26 + #ifndef __ASSEMBLER__ 27 27 #include <asm/mmu.h> 28 28 #include <asm/fixmap.h> 29 29 ··· 430 430 431 431 typedef pte_t *pte_addr_t; 432 432 433 - #endif /* __ASSEMBLY__ */ 433 + #endif /* __ASSEMBLER__ */ 434 434 #endif /* __ASM_OPENRISC_PGTABLE_H */
+2 -2
arch/openrisc/include/asm/processor.h
··· 39 39 */ 40 40 #define TASK_UNMAPPED_BASE (TASK_SIZE / 8 * 3) 41 41 42 - #ifndef __ASSEMBLY__ 42 + #ifndef __ASSEMBLER__ 43 43 44 44 struct task_struct; 45 45 ··· 78 78 79 79 #define cpu_relax() barrier() 80 80 81 - #endif /* __ASSEMBLY__ */ 81 + #endif /* __ASSEMBLER__ */ 82 82 #endif /* __ASM_OPENRISC_PROCESSOR_H */
+2 -2
arch/openrisc/include/asm/ptrace.h
··· 27 27 * they share a cacheline (not done yet, though... future optimization). 28 28 */ 29 29 30 - #ifndef __ASSEMBLY__ 30 + #ifndef __ASSEMBLER__ 31 31 /* 32 32 * This struct describes how the registers are laid out on the kernel stack 33 33 * during a syscall or other kernel entry. ··· 147 147 return *(unsigned long *)((unsigned long)regs + offset); 148 148 } 149 149 150 - #endif /* __ASSEMBLY__ */ 150 + #endif /* __ASSEMBLER__ */ 151 151 152 152 /* 153 153 * Offsets used by 'ptrace' system call interface.
+1 -1
arch/openrisc/include/asm/setup.h
··· 8 8 #include <linux/init.h> 9 9 #include <asm-generic/setup.h> 10 10 11 - #ifndef __ASSEMBLY__ 11 + #ifndef __ASSEMBLER__ 12 12 void __init or1k_early_setup(void *fdt); 13 13 #endif 14 14
+4 -4
arch/openrisc/include/asm/thread_info.h
··· 17 17 18 18 #ifdef __KERNEL__ 19 19 20 - #ifndef __ASSEMBLY__ 20 + #ifndef __ASSEMBLER__ 21 21 #include <asm/types.h> 22 22 #include <asm/processor.h> 23 23 #endif ··· 38 38 * - if the contents of this structure are changed, the assembly constants 39 39 * must also be changed 40 40 */ 41 - #ifndef __ASSEMBLY__ 41 + #ifndef __ASSEMBLER__ 42 42 43 43 struct thread_info { 44 44 struct task_struct *task; /* main task structure */ ··· 58 58 * 59 59 * preempt_count needs to be 1 initially, until the scheduler is functional. 60 60 */ 61 - #ifndef __ASSEMBLY__ 61 + #ifndef __ASSEMBLER__ 62 62 #define INIT_THREAD_INFO(tsk) \ 63 63 { \ 64 64 .task = &tsk, \ ··· 75 75 #define get_thread_info(ti) get_task_struct((ti)->task) 76 76 #define put_thread_info(ti) put_task_struct((ti)->task) 77 77 78 - #endif /* !__ASSEMBLY__ */ 78 + #endif /* !__ASSEMBLER__ */ 79 79 80 80 /* 81 81 * thread information flags
+1 -1
arch/openrisc/include/uapi/asm/ptrace.h
··· 20 20 #ifndef _UAPI__ASM_OPENRISC_PTRACE_H 21 21 #define _UAPI__ASM_OPENRISC_PTRACE_H 22 22 23 - #ifndef __ASSEMBLY__ 23 + #ifndef __ASSEMBLER__ 24 24 /* 25 25 * This is the layout of the regset returned by the GETREGSET ptrace call 26 26 */
+1
arch/powerpc/include/asm/ppc-opcode.h
··· 425 425 #define PPC_RAW_SC() (0x44000002) 426 426 #define PPC_RAW_SYNC() (0x7c0004ac) 427 427 #define PPC_RAW_ISYNC() (0x4c00012c) 428 + #define PPC_RAW_LWSYNC() (0x7c2004ac) 428 429 429 430 /* 430 431 * Define what the VSX XX1 form instructions will look like, then add
+1
arch/powerpc/kernel/eeh.c
··· 1139 1139 1140 1140 return ret; 1141 1141 } 1142 + EXPORT_SYMBOL_GPL(eeh_unfreeze_pe); 1142 1143 1143 1144 1144 1145 static struct pci_device_id eeh_reset_ids[] = {
+32 -16
arch/powerpc/kernel/eeh_driver.c
··· 257 257 struct pci_driver *driver; 258 258 enum pci_ers_result new_result; 259 259 260 - pci_lock_rescan_remove(); 261 260 pdev = edev->pdev; 262 261 if (pdev) 263 262 get_device(&pdev->dev); 264 - pci_unlock_rescan_remove(); 265 263 if (!pdev) { 266 264 eeh_edev_info(edev, "no device"); 265 + *result = PCI_ERS_RESULT_DISCONNECT; 267 266 return; 268 267 } 269 268 device_lock(&pdev->dev); ··· 303 304 struct eeh_dev *edev, *tmp; 304 305 305 306 pr_info("EEH: Beginning: '%s'\n", name); 306 - eeh_for_each_pe(root, pe) eeh_pe_for_each_dev(pe, edev, tmp) 307 - eeh_pe_report_edev(edev, fn, result); 307 + eeh_for_each_pe(root, pe) 308 + eeh_pe_for_each_dev(pe, edev, tmp) 309 + eeh_pe_report_edev(edev, fn, result); 308 310 if (result) 309 311 pr_info("EEH: Finished:'%s' with aggregate recovery state:'%s'\n", 310 312 name, pci_ers_result_name(*result)); ··· 383 383 if (!edev) 384 384 return; 385 385 386 + pci_lock_rescan_remove(); 387 + 386 388 /* 387 389 * The content in the config space isn't saved because 388 390 * the blocked config space on some adapters. We have ··· 395 393 if (list_is_last(&edev->entry, &edev->pe->edevs)) 396 394 eeh_pe_restore_bars(edev->pe); 397 395 396 + pci_unlock_rescan_remove(); 398 397 return; 399 398 } 400 399 401 400 pdev = eeh_dev_to_pci_dev(edev); 402 - if (!pdev) 401 + if (!pdev) { 402 + pci_unlock_rescan_remove(); 403 403 return; 404 + } 404 405 405 406 pci_restore_state(pdev); 407 + 408 + pci_unlock_rescan_remove(); 406 409 } 407 410 408 411 /** ··· 654 647 if (any_passed || driver_eeh_aware || (pe->type & EEH_PE_VF)) { 655 648 eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data); 656 649 } else { 657 - pci_lock_rescan_remove(); 658 650 pci_hp_remove_devices(bus); 659 - pci_unlock_rescan_remove(); 660 651 } 661 652 662 653 /* ··· 670 665 if (rc) 671 666 return rc; 672 667 673 - pci_lock_rescan_remove(); 674 - 675 668 /* Restore PE */ 676 669 eeh_ops->configure_bridge(pe); 677 670 eeh_pe_restore_bars(pe); ··· 677 674 /* Clear frozen state */ 678 675 rc = eeh_clear_pe_frozen_state(pe, false); 679 676 if (rc) { 680 - pci_unlock_rescan_remove(); 681 677 return rc; 682 678 } 683 679 ··· 711 709 pe->tstamp = tstamp; 712 710 pe->freeze_count = cnt; 713 711 714 - pci_unlock_rescan_remove(); 715 712 return 0; 716 713 } 717 714 ··· 844 843 {LIST_HEAD_INIT(rmv_data.removed_vf_list), 0}; 845 844 int devices = 0; 846 845 846 + pci_lock_rescan_remove(); 847 + 847 848 bus = eeh_pe_bus_get(pe); 848 849 if (!bus) { 849 850 pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", 850 851 __func__, pe->phb->global_number, pe->addr); 852 + pci_unlock_rescan_remove(); 851 853 return; 852 854 } 853 855 ··· 1098 1094 eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true); 1099 1095 eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); 1100 1096 1101 - pci_lock_rescan_remove(); 1102 - pci_hp_remove_devices(bus); 1103 - pci_unlock_rescan_remove(); 1097 + bus = eeh_pe_bus_get(pe); 1098 + if (bus) 1099 + pci_hp_remove_devices(bus); 1100 + else 1101 + pr_err("%s: PCI bus for PHB#%x-PE#%x disappeared\n", 1102 + __func__, pe->phb->global_number, pe->addr); 1103 + 1104 1104 /* The passed PE should no longer be used */ 1105 + pci_unlock_rescan_remove(); 1105 1106 return; 1106 1107 } 1107 1108 ··· 1123 1114 eeh_clear_slot_attention(edev->pdev); 1124 1115 1125 1116 eeh_pe_state_clear(pe, EEH_PE_RECOVERING, true); 1117 + 1118 + pci_unlock_rescan_remove(); 1126 1119 } 1127 1120 1128 1121 /** ··· 1143 1132 unsigned long flags; 1144 1133 int rc; 1145 1134 1135 + pci_lock_rescan_remove(); 1146 1136 1147 1137 do { 1148 1138 rc = eeh_ops->next_error(&pe); ··· 1183 1171 1184 1172 break; 1185 1173 case EEH_NEXT_ERR_NONE: 1174 + pci_unlock_rescan_remove(); 1186 1175 return; 1187 1176 default: 1188 1177 pr_warn("%s: Invalid value %d from next_error()\n", 1189 1178 __func__, rc); 1179 + pci_unlock_rescan_remove(); 1190 1180 return; 1191 1181 } 1192 1182 ··· 1200 1186 if (rc == EEH_NEXT_ERR_FROZEN_PE || 1201 1187 rc == EEH_NEXT_ERR_FENCED_PHB) { 1202 1188 eeh_pe_state_mark(pe, EEH_PE_RECOVERING); 1189 + pci_unlock_rescan_remove(); 1203 1190 eeh_handle_normal_event(pe); 1191 + pci_lock_rescan_remove(); 1204 1192 } else { 1205 1193 eeh_for_each_pe(pe, tmp_pe) 1206 1194 eeh_pe_for_each_dev(tmp_pe, edev, tmp_edev) ··· 1215 1199 eeh_report_failure, NULL); 1216 1200 eeh_set_channel_state(pe, pci_channel_io_perm_failure); 1217 1201 1218 - pci_lock_rescan_remove(); 1219 1202 list_for_each_entry(hose, &hose_list, list_node) { 1220 1203 phb_pe = eeh_phb_pe_get(hose); 1221 1204 if (!phb_pe || ··· 1233 1218 } 1234 1219 pci_hp_remove_devices(bus); 1235 1220 } 1236 - pci_unlock_rescan_remove(); 1237 1221 } 1238 1222 1239 1223 /* ··· 1242 1228 if (rc == EEH_NEXT_ERR_DEAD_IOC) 1243 1229 break; 1244 1230 } while (rc != EEH_NEXT_ERR_NONE); 1231 + 1232 + pci_unlock_rescan_remove(); 1245 1233 }
+6 -4
arch/powerpc/kernel/eeh_pe.c
··· 671 671 eeh_ops->write_config(edev, cap + PCI_EXP_LNKCTL, 2, val); 672 672 673 673 /* Check link */ 674 - if (!edev->pdev->link_active_reporting) { 675 - eeh_edev_dbg(edev, "No link reporting capability\n"); 676 - msleep(1000); 677 - return; 674 + if (edev->pdev) { 675 + if (!edev->pdev->link_active_reporting) { 676 + eeh_edev_dbg(edev, "No link reporting capability\n"); 677 + msleep(1000); 678 + return; 679 + } 678 680 } 679 681 680 682 /* Wait the link is up until timeout (5s) */
+1 -1
arch/powerpc/kernel/fadump.c
··· 333 333 * memory at a predefined offset. 334 334 */ 335 335 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 336 - &size, &base, NULL, NULL); 336 + &size, &base, NULL, NULL, NULL); 337 337 if (ret == 0 && size > 0) { 338 338 unsigned long max_size; 339 339
+3
arch/powerpc/kernel/pci-hotplug.c
··· 141 141 struct pci_controller *phb; 142 142 struct device_node *dn = pci_bus_to_OF_node(bus); 143 143 144 + if (!dn) 145 + return; 146 + 144 147 phb = pci_bus_to_host(bus); 145 148 146 149 mode = PCI_PROBE_NORMAL;
+1 -1
arch/powerpc/kexec/core.c
··· 110 110 111 111 /* use common parsing */ 112 112 ret = parse_crashkernel(boot_command_line, total_mem_sz, &crash_size, 113 - &crash_base, NULL, NULL); 113 + &crash_base, NULL, NULL, NULL); 114 114 115 115 if (ret) 116 116 return;
+1 -1
arch/powerpc/mm/nohash/kaslr_booke.c
··· 178 178 int ret; 179 179 180 180 ret = parse_crashkernel(boot_command_line, size, &crash_size, 181 - &crash_base, NULL, NULL); 181 + &crash_base, NULL, NULL, NULL); 182 182 if (ret != 0 || crash_size == 0) 183 183 return; 184 184 if (crash_base == 0)
+82
arch/powerpc/net/bpf_jit_comp64.c
··· 409 409 " blr ;" 410 410 ); 411 411 412 + static int emit_atomic_ld_st(const struct bpf_insn insn, struct codegen_context *ctx, u32 *image) 413 + { 414 + u32 code = insn.code; 415 + u32 dst_reg = bpf_to_ppc(insn.dst_reg); 416 + u32 src_reg = bpf_to_ppc(insn.src_reg); 417 + u32 size = BPF_SIZE(code); 418 + u32 tmp1_reg = bpf_to_ppc(TMP_REG_1); 419 + u32 tmp2_reg = bpf_to_ppc(TMP_REG_2); 420 + s16 off = insn.off; 421 + s32 imm = insn.imm; 422 + 423 + switch (imm) { 424 + case BPF_LOAD_ACQ: 425 + switch (size) { 426 + case BPF_B: 427 + EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off)); 428 + break; 429 + case BPF_H: 430 + EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off)); 431 + break; 432 + case BPF_W: 433 + EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off)); 434 + break; 435 + case BPF_DW: 436 + if (off % 4) { 437 + EMIT(PPC_RAW_LI(tmp1_reg, off)); 438 + EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg)); 439 + } else { 440 + EMIT(PPC_RAW_LD(dst_reg, src_reg, off)); 441 + } 442 + break; 443 + } 444 + EMIT(PPC_RAW_LWSYNC()); 445 + break; 446 + case BPF_STORE_REL: 447 + EMIT(PPC_RAW_LWSYNC()); 448 + switch (size) { 449 + case BPF_B: 450 + EMIT(PPC_RAW_STB(src_reg, dst_reg, off)); 451 + break; 452 + case BPF_H: 453 + EMIT(PPC_RAW_STH(src_reg, dst_reg, off)); 454 + break; 455 + case BPF_W: 456 + EMIT(PPC_RAW_STW(src_reg, dst_reg, off)); 457 + break; 458 + case BPF_DW: 459 + if (off % 4) { 460 + EMIT(PPC_RAW_LI(tmp2_reg, off)); 461 + EMIT(PPC_RAW_STDX(src_reg, dst_reg, tmp2_reg)); 462 + } else { 463 + EMIT(PPC_RAW_STD(src_reg, dst_reg, off)); 464 + } 465 + break; 466 + } 467 + break; 468 + default: 469 + pr_err_ratelimited("unexpected atomic load/store op code %02x\n", 470 + imm); 471 + return -EINVAL; 472 + } 473 + 474 + return 0; 475 + } 476 + 412 477 /* Assemble the body code between the prologue & epilogue */ 413 478 int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx, 414 479 u32 *addrs, int pass, bool extra_pass) ··· 963 898 /* 964 899 * BPF_STX ATOMIC (atomic ops) 965 900 */ 901 + case BPF_STX | BPF_ATOMIC | BPF_B: 902 + case BPF_STX | BPF_ATOMIC | BPF_H: 966 903 case BPF_STX | BPF_ATOMIC | BPF_W: 967 904 case BPF_STX | BPF_ATOMIC | BPF_DW: 905 + if (bpf_atomic_is_load_store(&insn[i])) { 906 + ret = emit_atomic_ld_st(insn[i], ctx, image); 907 + if (ret) 908 + return ret; 909 + 910 + if (size != BPF_DW && insn_is_zext(&insn[i + 1])) 911 + addrs[++i] = ctx->idx * 4; 912 + break; 913 + } else if (size == BPF_B || size == BPF_H) { 914 + pr_err_ratelimited( 915 + "eBPF filter atomic op code %02x (@%d) unsupported\n", 916 + code, i); 917 + return -EOPNOTSUPP; 918 + } 919 + 968 920 save_reg = tmp2_reg; 969 921 ret_reg = src_reg; 970 922
+1
arch/riscv/Kconfig
··· 93 93 select CLINT_TIMER if RISCV_M_MODE 94 94 select CLONE_BACKWARDS 95 95 select COMMON_CLK 96 + select CPU_NO_EFFICIENT_FFS if !RISCV_ISA_ZBB 96 97 select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND 97 98 select DYNAMIC_FTRACE if FUNCTION_TRACER 98 99 select EDAC_SUPPORT
+21 -14
arch/riscv/include/asm/bug.h
··· 31 31 32 32 #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS 33 33 #define __BUG_ENTRY_ADDR RISCV_INT " 1b - ." 34 - #define __BUG_ENTRY_FILE RISCV_INT " %0 - ." 34 + #define __BUG_ENTRY_FILE(file) RISCV_INT " " file " - ." 35 35 #else 36 36 #define __BUG_ENTRY_ADDR RISCV_PTR " 1b" 37 - #define __BUG_ENTRY_FILE RISCV_PTR " %0" 37 + #define __BUG_ENTRY_FILE(file) RISCV_PTR " " file 38 38 #endif 39 39 40 40 #ifdef CONFIG_DEBUG_BUGVERBOSE 41 - #define __BUG_ENTRY \ 41 + #define __BUG_ENTRY(file, line, flags) \ 42 42 __BUG_ENTRY_ADDR "\n\t" \ 43 - __BUG_ENTRY_FILE "\n\t" \ 44 - RISCV_SHORT " %1\n\t" \ 45 - RISCV_SHORT " %2" 43 + __BUG_ENTRY_FILE(file) "\n\t" \ 44 + RISCV_SHORT " " line "\n\t" \ 45 + RISCV_SHORT " " flags 46 46 #else 47 - #define __BUG_ENTRY \ 48 - __BUG_ENTRY_ADDR "\n\t" \ 49 - RISCV_SHORT " %2" 47 + #define __BUG_ENTRY(file, line, flags) \ 48 + __BUG_ENTRY_ADDR "\n\t" \ 49 + RISCV_SHORT " " flags 50 50 #endif 51 51 52 52 #ifdef CONFIG_GENERIC_BUG 53 - #define __BUG_FLAGS(flags) \ 54 - do { \ 55 - __asm__ __volatile__ ( \ 53 + 54 + #define ARCH_WARN_ASM(file, line, flags, size) \ 56 55 "1:\n\t" \ 57 56 "ebreak\n" \ 58 57 ".pushsection __bug_table,\"aw\"\n\t" \ 59 58 "2:\n\t" \ 60 - __BUG_ENTRY "\n\t" \ 61 - ".org 2b + %3\n\t" \ 59 + __BUG_ENTRY(file, line, flags) "\n\t" \ 60 + ".org 2b + " size "\n\t" \ 62 61 ".popsection" \ 62 + 63 + #define __BUG_FLAGS(flags) \ 64 + do { \ 65 + __asm__ __volatile__ ( \ 66 + ARCH_WARN_ASM("%0", "%1", "%2", "%3") \ 63 67 : \ 64 68 : "i" (__FILE__), "i" (__LINE__), \ 65 69 "i" (flags), \ 66 70 "i" (sizeof(struct bug_entry))); \ 67 71 } while (0) 72 + 68 73 #else /* CONFIG_GENERIC_BUG */ 69 74 #define __BUG_FLAGS(flags) do { \ 70 75 __asm__ __volatile__ ("ebreak\n"); \ ··· 82 77 } while (0) 83 78 84 79 #define __WARN_FLAGS(flags) __BUG_FLAGS(BUGFLAG_WARNING|(flags)) 80 + 81 + #define ARCH_WARN_REACHABLE 85 82 86 83 #define HAVE_ARCH_BUG 87 84
+1
arch/riscv/kernel/kexec_elf.c
··· 95 95 kbuf.buf_align = PMD_SIZE; 96 96 kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 97 97 kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); 98 + kbuf.cma = NULL; 98 99 kbuf.top_down = false; 99 100 ret = arch_kexec_locate_mem_hole(&kbuf); 100 101 if (!ret) {
+5
arch/riscv/kernel/setup.c
··· 21 21 #include <linux/efi.h> 22 22 #include <linux/crash_dump.h> 23 23 #include <linux/panic_notifier.h> 24 + #include <linux/jump_label.h> 25 + #include <linux/gcd.h> 24 26 25 27 #include <asm/acpi.h> 26 28 #include <asm/alternative.h> ··· 364 362 365 363 riscv_user_isa_enable(); 366 364 riscv_spinlock_init(); 365 + 366 + if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB)) 367 + static_branch_disable(&efficient_ffs_key); 367 368 } 368 369 369 370 bool arch_cpu_is_hotpluggable(int cpu)
+1 -1
arch/riscv/mm/init.c
··· 1408 1408 1409 1409 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 1410 1410 &crash_size, &crash_base, 1411 - &low_size, &high); 1411 + &low_size, NULL, &high); 1412 1412 if (ret) 1413 1413 return; 1414 1414
+1 -1
arch/s390/kernel/setup.c
··· 605 605 int rc; 606 606 607 607 rc = parse_crashkernel(boot_command_line, ident_map_size, 608 - &crash_size, &crash_base, NULL, NULL); 608 + &crash_size, &crash_base, NULL, NULL, NULL); 609 609 610 610 crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN); 611 611 crash_size = ALIGN(crash_size, KEXEC_CRASH_MEM_ALIGN);
+1 -1
arch/sh/kernel/machine_kexec.c
··· 146 146 return; 147 147 148 148 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 149 - &crash_size, &crash_base, NULL, NULL); 149 + &crash_size, &crash_base, NULL, NULL, NULL); 150 150 if (ret == 0 && crash_size > 0) { 151 151 crashk_res.start = crash_base; 152 152 crashk_res.end = crash_base + crash_size - 1;
+28 -28
arch/x86/include/asm/bug.h
··· 32 32 #ifdef CONFIG_GENERIC_BUG 33 33 34 34 #ifdef CONFIG_X86_32 35 - # define __BUG_REL(val) ".long " __stringify(val) 35 + # define __BUG_REL(val) ".long " val 36 36 #else 37 - # define __BUG_REL(val) ".long " __stringify(val) " - ." 37 + # define __BUG_REL(val) ".long " val " - ." 38 38 #endif 39 39 40 40 #ifdef CONFIG_DEBUG_BUGVERBOSE 41 + #define __BUG_ENTRY(file, line, flags) \ 42 + "2:\t" __BUG_REL("1b") "\t# bug_entry::bug_addr\n" \ 43 + "\t" __BUG_REL(file) "\t# bug_entry::file\n" \ 44 + "\t.word " line "\t# bug_entry::line\n" \ 45 + "\t.word " flags "\t# bug_entry::flags\n" 46 + #else 47 + #define __BUG_ENTRY(file, line, flags) \ 48 + "2:\t" __BUG_REL("1b") "\t# bug_entry::bug_addr\n" \ 49 + "\t.word " flags "\t# bug_entry::flags\n" 50 + #endif 51 + 52 + #define _BUG_FLAGS_ASM(ins, file, line, flags, size, extra) \ 53 + "1:\t" ins "\n" \ 54 + ".pushsection __bug_table,\"aw\"\n" \ 55 + __BUG_ENTRY(file, line, flags) \ 56 + "\t.org 2b + " size "\n" \ 57 + ".popsection\n" \ 58 + extra 41 59 42 60 #define _BUG_FLAGS(ins, flags, extra) \ 43 61 do { \ 44 - asm_inline volatile("1:\t" ins "\n" \ 45 - ".pushsection __bug_table,\"aw\"\n" \ 46 - "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \ 47 - "\t" __BUG_REL(%c0) "\t# bug_entry::file\n" \ 48 - "\t.word %c1" "\t# bug_entry::line\n" \ 49 - "\t.word %c2" "\t# bug_entry::flags\n" \ 50 - "\t.org 2b+%c3\n" \ 51 - ".popsection\n" \ 52 - extra \ 62 + asm_inline volatile(_BUG_FLAGS_ASM(ins, "%c0", \ 63 + "%c1", "%c2", "%c3", extra) \ 53 64 : : "i" (__FILE__), "i" (__LINE__), \ 54 65 "i" (flags), \ 55 66 "i" (sizeof(struct bug_entry))); \ 56 67 } while (0) 57 68 58 - #else /* !CONFIG_DEBUG_BUGVERBOSE */ 59 - 60 - #define _BUG_FLAGS(ins, flags, extra) \ 61 - do { \ 62 - asm_inline volatile("1:\t" ins "\n" \ 63 - ".pushsection __bug_table,\"aw\"\n" \ 64 - "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \ 65 - "\t.word %c0" "\t# bug_entry::flags\n" \ 66 - "\t.org 2b+%c1\n" \ 67 - ".popsection\n" \ 68 - extra \ 69 - : : "i" (flags), \ 70 - "i" (sizeof(struct bug_entry))); \ 71 - } while (0) 72 - 73 - #endif /* CONFIG_DEBUG_BUGVERBOSE */ 69 + #define ARCH_WARN_ASM(file, line, flags, size) \ 70 + _BUG_FLAGS_ASM(ASM_UD2, file, line, flags, size, "") 74 71 75 72 #else 76 73 ··· 89 92 * were to trigger, we'd rather wreck the machine in an attempt to get the 90 93 * message out than not know about it. 91 94 */ 95 + 96 + #define ARCH_WARN_REACHABLE ANNOTATE_REACHABLE(1b) 97 + 92 98 #define __WARN_FLAGS(flags) \ 93 99 do { \ 94 100 __auto_type __flags = BUGFLAG_WARNING|(flags); \ 95 101 instrumentation_begin(); \ 96 - _BUG_FLAGS(ASM_UD2, __flags, ANNOTATE_REACHABLE(1b)); \ 102 + _BUG_FLAGS(ASM_UD2, __flags, ARCH_WARN_REACHABLE); \ 97 103 instrumentation_end(); \ 98 104 } while (0) 99 105
+1 -2
arch/x86/kernel/alternative.c
··· 120 120 121 121 static void *__its_alloc(struct its_array *pages) 122 122 { 123 - void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE); 123 + void *page __free(execmem) = execmem_alloc_rw(EXECMEM_MODULE_TEXT, PAGE_SIZE); 124 124 if (!page) 125 125 return NULL; 126 126 ··· 237 237 if (!page) 238 238 return NULL; 239 239 240 - execmem_make_temp_rw(page, PAGE_SIZE); 241 240 if (pages == &its_pages) 242 241 set_memory_x((unsigned long)page, 1); 243 242
+22 -4
arch/x86/kernel/crash.c
··· 163 163 return NULL; 164 164 165 165 /* 166 - * Exclusion of crash region and/or crashk_low_res may cause 167 - * another range split. So add extra two slots here. 166 + * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges 167 + * may cause range splits. So add extra slots here. 168 168 */ 169 - nr_ranges += 2; 169 + nr_ranges += 2 + crashk_cma_cnt; 170 170 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges)); 171 171 if (!cmem) 172 172 return NULL; ··· 184 184 static int elf_header_exclude_ranges(struct crash_mem *cmem) 185 185 { 186 186 int ret = 0; 187 + int i; 187 188 188 189 /* Exclude the low 1M because it is always reserved */ 189 190 ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1); ··· 199 198 if (crashk_low_res.end) 200 199 ret = crash_exclude_mem_range(cmem, crashk_low_res.start, 201 200 crashk_low_res.end); 201 + if (ret) 202 + return ret; 202 203 203 - return ret; 204 + for (i = 0; i < crashk_cma_cnt; ++i) { 205 + ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start, 206 + crashk_cma_ranges[i].end); 207 + if (ret) 208 + return ret; 209 + } 210 + 211 + return 0; 204 212 } 205 213 206 214 static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) ··· 380 370 if (ei.size < PAGE_SIZE) 381 371 continue; 382 372 ei.addr = cmem->ranges[i].start; 373 + ei.type = E820_TYPE_RAM; 374 + add_e820_entry(params, &ei); 375 + } 376 + 377 + for (i = 0; i < crashk_cma_cnt; ++i) { 378 + ei.addr = crashk_cma_ranges[i].start; 379 + ei.size = crashk_cma_ranges[i].end - 380 + crashk_cma_ranges[i].start + 1; 383 381 ei.type = E820_TYPE_RAM; 384 382 add_e820_entry(params, &ei); 385 383 }
+1 -1
arch/x86/kernel/ftrace.c
··· 263 263 264 264 static inline void *alloc_tramp(unsigned long size) 265 265 { 266 - return execmem_alloc(EXECMEM_FTRACE, size); 266 + return execmem_alloc_rw(EXECMEM_FTRACE, size); 267 267 } 268 268 static inline void tramp_free(void *tramp) 269 269 {
-18
arch/x86/kernel/kprobes/core.c
··· 481 481 return len; 482 482 } 483 483 484 - /* Make page to RO mode when allocate it */ 485 - void *alloc_insn_page(void) 486 - { 487 - void *page; 488 - 489 - page = execmem_alloc(EXECMEM_KPROBES, PAGE_SIZE); 490 - if (!page) 491 - return NULL; 492 - 493 - /* 494 - * TODO: Once additional kernel code protection mechanisms are set, ensure 495 - * that the page was not maliciously altered and it is still zeroed. 496 - */ 497 - set_memory_rox((unsigned long)page, 1); 498 - 499 - return page; 500 - } 501 - 502 484 /* Kprobe x86 instruction emulation - only regs->ip or IF flag modifiers */ 503 485 504 486 static void kprobe_emulate_ifmodifiers(struct kprobe *p, struct pt_regs *regs)
+3 -2
arch/x86/kernel/setup.c
··· 603 603 604 604 static void __init arch_reserve_crashkernel(void) 605 605 { 606 - unsigned long long crash_base, crash_size, low_size = 0; 606 + unsigned long long crash_base, crash_size, low_size = 0, cma_size = 0; 607 607 bool high = false; 608 608 int ret; 609 609 ··· 612 612 613 613 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), 614 614 &crash_size, &crash_base, 615 - &low_size, &high); 615 + &low_size, &cma_size, &high); 616 616 if (ret) 617 617 return; 618 618 ··· 622 622 } 623 623 624 624 reserve_crashkernel_generic(crash_size, crash_base, low_size, high); 625 + reserve_crashkernel_cma(cma_size); 625 626 } 626 627 627 628 static struct resource standard_io_resources[] = {
+2 -2
arch/x86/kvm/i8254.c
··· 641 641 kvm_pit_reset_reinject(pit); 642 642 } 643 643 644 - static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask) 644 + static void pit_mask_notifier(struct kvm_irq_mask_notifier *kimn, bool mask) 645 645 { 646 646 struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier); 647 647 ··· 763 763 764 764 pit_state->irq_ack_notifier.gsi = 0; 765 765 pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; 766 - pit->mask_notifier.func = pit_mask_notifer; 766 + pit->mask_notifier.func = pit_mask_notifier; 767 767 768 768 kvm_pit_reset(pit); 769 769
+17 -7
arch/x86/mm/init.c
··· 1063 1063 static struct execmem_info execmem_info __ro_after_init; 1064 1064 1065 1065 #ifdef CONFIG_ARCH_HAS_EXECMEM_ROX 1066 - void execmem_fill_trapping_insns(void *ptr, size_t size, bool writeable) 1066 + void execmem_fill_trapping_insns(void *ptr, size_t size) 1067 1067 { 1068 - /* fill memory with INT3 instructions */ 1069 - if (writeable) 1070 - memset(ptr, INT3_INSN_OPCODE, size); 1071 - else 1072 - text_poke_set(ptr, INT3_INSN_OPCODE, size); 1068 + memset(ptr, INT3_INSN_OPCODE, size); 1073 1069 } 1074 1070 #endif 1075 1071 ··· 1098 1102 .pgprot = pgprot, 1099 1103 .alignment = MODULE_ALIGN, 1100 1104 }, 1101 - [EXECMEM_KPROBES ... EXECMEM_BPF] = { 1105 + [EXECMEM_KPROBES] = { 1106 + .flags = flags, 1107 + .start = start, 1108 + .end = MODULES_END, 1109 + .pgprot = PAGE_KERNEL_ROX, 1110 + .alignment = MODULE_ALIGN, 1111 + }, 1112 + [EXECMEM_FTRACE] = { 1113 + .flags = flags, 1114 + .start = start, 1115 + .end = MODULES_END, 1116 + .pgprot = pgprot, 1117 + .alignment = MODULE_ALIGN, 1118 + }, 1119 + [EXECMEM_BPF] = { 1102 1120 .flags = EXECMEM_KASAN_SHADOW, 1103 1121 .start = start, 1104 1122 .end = MODULES_END,
+1 -1
crypto/async_tx/async_pq.c
··· 119 119 for (i = 0; i < disks; i++) { 120 120 if (blocks[i] == NULL) { 121 121 BUG_ON(i > disks - 3); /* P or Q can't be zero */ 122 - srcs[i] = (void*)raid6_empty_zero_page; 122 + srcs[i] = raid6_get_zero_page(); 123 123 } else { 124 124 srcs[i] = page_address(blocks[i]) + offsets[i]; 125 125
+2 -2
crypto/async_tx/async_raid6_recov.c
··· 414 414 async_tx_quiesce(&submit->depend_tx); 415 415 for (i = 0; i < disks; i++) 416 416 if (blocks[i] == NULL) 417 - ptrs[i] = (void *) raid6_empty_zero_page; 417 + ptrs[i] = raid6_get_zero_page(); 418 418 else 419 419 ptrs[i] = page_address(blocks[i]) + offs[i]; 420 420 ··· 497 497 async_tx_quiesce(&submit->depend_tx); 498 498 for (i = 0; i < disks; i++) 499 499 if (blocks[i] == NULL) 500 - ptrs[i] = (void*)raid6_empty_zero_page; 500 + ptrs[i] = raid6_get_zero_page(); 501 501 else 502 502 ptrs[i] = page_address(blocks[i]) + offs[i]; 503 503
+1
drivers/ata/ata_piix.c
··· 1089 1089 }; 1090 1090 1091 1091 static struct attribute *piix_sidpr_shost_attrs[] = { 1092 + &dev_attr_link_power_management_supported.attr, 1092 1093 &dev_attr_link_power_management_policy.attr, 1093 1094 NULL 1094 1095 };
+1
drivers/ata/libahci.c
··· 111 111 static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL); 112 112 113 113 static struct attribute *ahci_shost_attrs[] = { 114 + &dev_attr_link_power_management_supported.attr, 114 115 &dev_attr_link_power_management_policy.attr, 115 116 &dev_attr_em_message_type.attr, 116 117 &dev_attr_em_message.attr,
+1 -1
drivers/ata/libata-core.c
··· 4602 4602 return AC_ERR_INVALID; 4603 4603 4604 4604 /* set up init dev params taskfile */ 4605 - ata_dev_dbg(dev, "init dev params \n"); 4605 + ata_dev_dbg(dev, "init dev params\n"); 4606 4606 4607 4607 ata_tf_init(dev, &tf); 4608 4608 tf.command = ATA_CMD_INIT_DEV_PARAMS;
+41 -12
drivers/ata/libata-sata.c
··· 900 900 [ATA_LPM_MIN_POWER] = "min_power", 901 901 }; 902 902 903 + /* 904 + * Check if a port supports link power management. 905 + * Must be called with the port locked. 906 + */ 907 + static bool ata_scsi_lpm_supported(struct ata_port *ap) 908 + { 909 + struct ata_link *link; 910 + struct ata_device *dev; 911 + 912 + if (ap->flags & ATA_FLAG_NO_LPM) 913 + return false; 914 + 915 + ata_for_each_link(link, ap, EDGE) { 916 + ata_for_each_dev(dev, &ap->link, ENABLED) { 917 + if (dev->quirks & ATA_QUIRK_NOLPM) 918 + return false; 919 + } 920 + } 921 + 922 + return true; 923 + } 924 + 925 + static ssize_t ata_scsi_lpm_supported_show(struct device *dev, 926 + struct device_attribute *attr, char *buf) 927 + { 928 + struct Scsi_Host *shost = class_to_shost(dev); 929 + struct ata_port *ap = ata_shost_to_port(shost); 930 + unsigned long flags; 931 + bool supported; 932 + 933 + spin_lock_irqsave(ap->lock, flags); 934 + supported = ata_scsi_lpm_supported(ap); 935 + spin_unlock_irqrestore(ap->lock, flags); 936 + 937 + return sysfs_emit(buf, "%d\n", supported); 938 + } 939 + DEVICE_ATTR(link_power_management_supported, S_IRUGO, 940 + ata_scsi_lpm_supported_show, NULL); 941 + EXPORT_SYMBOL_GPL(dev_attr_link_power_management_supported); 942 + 903 943 static ssize_t ata_scsi_lpm_store(struct device *device, 904 944 struct device_attribute *attr, 905 945 const char *buf, size_t count) 906 946 { 907 947 struct Scsi_Host *shost = class_to_shost(device); 908 948 struct ata_port *ap = ata_shost_to_port(shost); 909 - struct ata_link *link; 910 - struct ata_device *dev; 911 949 enum ata_lpm_policy policy; 912 950 unsigned long flags; 913 951 ··· 962 924 963 925 spin_lock_irqsave(ap->lock, flags); 964 926 965 - if (ap->flags & ATA_FLAG_NO_LPM) { 927 + if (!ata_scsi_lpm_supported(ap)) { 966 928 count = -EOPNOTSUPP; 967 929 goto out_unlock; 968 - } 969 - 970 - ata_for_each_link(link, ap, EDGE) { 971 - ata_for_each_dev(dev, &ap->link, ENABLED) { 972 - if (dev->quirks & ATA_QUIRK_NOLPM) { 973 - count = -EOPNOTSUPP; 974 - goto out_unlock; 975 - } 976 - } 977 930 } 978 931 979 932 ap->target_lpm_policy = policy;
+19 -19
drivers/ata/libata-scsi.c
··· 859 859 {0xFF, 0xFF, 0xFF, 0xFF}, // END mark 860 860 }; 861 861 static const unsigned char stat_table[][4] = { 862 - /* Must be first because BUSY means no other bits valid */ 863 - {0x80, ABORTED_COMMAND, 0x47, 0x00}, 864 - // Busy, fake parity for now 865 - {0x40, ILLEGAL_REQUEST, 0x21, 0x04}, 866 - // Device ready, unaligned write command 867 - {0x20, HARDWARE_ERROR, 0x44, 0x00}, 868 - // Device fault, internal target failure 869 - {0x08, ABORTED_COMMAND, 0x47, 0x00}, 870 - // Timed out in xfer, fake parity for now 871 - {0x04, RECOVERED_ERROR, 0x11, 0x00}, 872 - // Recovered ECC error Medium error, recovered 873 - {0xFF, 0xFF, 0xFF, 0xFF}, // END mark 862 + /* Busy: must be first because BUSY means no other bits valid */ 863 + { ATA_BUSY, ABORTED_COMMAND, 0x00, 0x00 }, 864 + /* Device fault: INTERNAL TARGET FAILURE */ 865 + { ATA_DF, HARDWARE_ERROR, 0x44, 0x00 }, 866 + /* Corrected data error */ 867 + { ATA_CORR, RECOVERED_ERROR, 0x00, 0x00 }, 868 + 869 + { 0xFF, 0xFF, 0xFF, 0xFF }, /* END mark */ 874 870 }; 875 871 876 872 /* ··· 938 942 if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { 939 943 ata_dev_dbg(dev, 940 944 "missing result TF: can't generate ATA PT sense data\n"); 945 + if (qc->err_mask) 946 + ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); 941 947 return; 942 948 } 943 949 ··· 994 996 995 997 if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) { 996 998 ata_dev_dbg(dev, 997 - "missing result TF: can't generate sense data\n"); 998 - return; 999 + "Missing result TF: reporting aborted command\n"); 1000 + goto aborted; 999 1001 } 1000 1002 1001 1003 /* Use ata_to_sense_error() to map status register bits ··· 1006 1008 ata_to_sense_error(tf->status, tf->error, 1007 1009 &sense_key, &asc, &ascq); 1008 1010 ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq); 1009 - } else { 1010 - /* Could not decode error */ 1011 - ata_dev_warn(dev, "could not decode error status 0x%x err_mask 0x%x\n", 1012 - tf->status, qc->err_mask); 1013 - ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); 1014 1011 return; 1015 1012 } 1013 + 1014 + /* Could not decode error */ 1015 + ata_dev_warn(dev, 1016 + "Could not decode error 0x%x, status 0x%x (err_mask=0x%x)\n", 1017 + tf->error, tf->status, qc->err_mask); 1018 + aborted: 1019 + ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); 1016 1020 } 1017 1021 1018 1022 void ata_scsi_sdev_config(struct scsi_device *sdev)
+1 -1
drivers/ata/pata_macio.c
··· 758 758 759 759 static void pata_macio_reset_hw(struct pata_macio_priv *priv, int resume) 760 760 { 761 - dev_dbg(priv->dev, "Enabling & resetting... \n"); 761 + dev_dbg(priv->dev, "Enabling & resetting...\n"); 762 762 763 763 if (priv->mediabay) 764 764 return;
+6 -6
drivers/ata/pata_pdc2027x.c
··· 295 295 } 296 296 297 297 /* Set the PIO timing registers using value table for 133MHz */ 298 - ata_port_dbg(ap, "Set pio regs... \n"); 298 + ata_port_dbg(ap, "Set PIO regs...\n"); 299 299 300 300 ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); 301 301 ctcr0 &= 0xffff0000; ··· 308 308 ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24); 309 309 iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); 310 310 311 - ata_port_dbg(ap, "Set to pio mode[%u] \n", pio); 311 + ata_port_dbg(ap, "Set to PIO mode[%u]\n", pio); 312 312 } 313 313 314 314 /** ··· 341 341 iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); 342 342 } 343 343 344 - ata_port_dbg(ap, "Set udma regs... \n"); 344 + ata_port_dbg(ap, "Set UDMA regs...\n"); 345 345 346 346 ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1)); 347 347 ctcr1 &= 0xff000000; ··· 350 350 (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16); 351 351 iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); 352 352 353 - ata_port_dbg(ap, "Set to udma mode[%u] \n", udma_mode); 353 + ata_port_dbg(ap, "Set to UDMA mode[%u]\n", udma_mode); 354 354 355 355 } else if ((dma_mode >= XFER_MW_DMA_0) && 356 356 (dma_mode <= XFER_MW_DMA_2)) { 357 357 /* Set the MDMA timing registers with value table for 133MHz */ 358 358 unsigned int mdma_mode = dma_mode & 0x07; 359 359 360 - ata_port_dbg(ap, "Set mdma regs... \n"); 360 + ata_port_dbg(ap, "Set MDMA regs...\n"); 361 361 ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0)); 362 362 363 363 ctcr0 &= 0x0000ffff; ··· 366 366 367 367 iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); 368 368 369 - ata_port_dbg(ap, "Set to mdma mode[%u] \n", mdma_mode); 369 + ata_port_dbg(ap, "Set to MDMA mode[%u]\n", mdma_mode); 370 370 } else { 371 371 ata_port_err(ap, "Unknown dma mode [%u] ignored\n", dma_mode); 372 372 }
+4 -4
drivers/char/ipmi/ipmi_msghandler.c
··· 4607 4607 * The NetFN and Command in the response is not even 4608 4608 * marginally correct. 4609 4609 */ 4610 - dev_warn(intf->si_dev, 4611 - "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n", 4612 - (msg->data[0] >> 2) | 1, msg->data[1], 4613 - msg->rsp[0] >> 2, msg->rsp[1]); 4610 + dev_warn_ratelimited(intf->si_dev, 4611 + "BMC returned incorrect response, expected netfn %x cmd %x, got netfn %x cmd %x\n", 4612 + (msg->data[0] >> 2) | 1, msg->data[1], 4613 + msg->rsp[0] >> 2, msg->rsp[1]); 4614 4614 4615 4615 goto return_unspecified; 4616 4616 }
-4
drivers/char/ipmi/ipmi_si_intf.c
··· 2108 2108 static int __init init_ipmi_si(void) 2109 2109 { 2110 2110 struct smi_info *e, *e2; 2111 - enum ipmi_addr_src type = SI_INVALID; 2112 2111 2113 2112 if (initialized) 2114 2113 return 0; ··· 2188 2189 2189 2190 initialized = true; 2190 2191 mutex_unlock(&smi_infos_lock); 2191 - 2192 - if (type) 2193 - return 0; 2194 2192 2195 2193 mutex_lock(&smi_infos_lock); 2196 2194 if (unload_when_empty && list_empty(&smi_infos)) {
+42 -17
drivers/char/ipmi/ipmi_watchdog.c
··· 1146 1146 .smi_gone = ipmi_smi_gone 1147 1147 }; 1148 1148 1149 - static int action_op(const char *inval, char *outval) 1149 + static int action_op_set_val(const char *inval) 1150 1150 { 1151 - if (outval) 1152 - strcpy(outval, action); 1153 - 1154 - if (!inval) 1155 - return 0; 1156 - 1157 1151 if (strcmp(inval, "reset") == 0) 1158 1152 action_val = WDOG_TIMEOUT_RESET; 1159 1153 else if (strcmp(inval, "none") == 0) ··· 1158 1164 action_val = WDOG_TIMEOUT_POWER_DOWN; 1159 1165 else 1160 1166 return -EINVAL; 1161 - strcpy(action, inval); 1162 1167 return 0; 1163 1168 } 1164 1169 1165 - static int preaction_op(const char *inval, char *outval) 1170 + static int action_op(const char *inval, char *outval) 1166 1171 { 1172 + int rv; 1173 + 1167 1174 if (outval) 1168 - strcpy(outval, preaction); 1175 + strcpy(outval, action); 1169 1176 1170 1177 if (!inval) 1171 1178 return 0; 1179 + rv = action_op_set_val(inval); 1180 + if (!rv) 1181 + strcpy(action, inval); 1182 + return rv; 1183 + } 1172 1184 1185 + static int preaction_op_set_val(const char *inval) 1186 + { 1173 1187 if (strcmp(inval, "pre_none") == 0) 1174 1188 preaction_val = WDOG_PRETIMEOUT_NONE; 1175 1189 else if (strcmp(inval, "pre_smi") == 0) ··· 1190 1188 preaction_val = WDOG_PRETIMEOUT_MSG_INT; 1191 1189 else 1192 1190 return -EINVAL; 1193 - strcpy(preaction, inval); 1194 1191 return 0; 1195 1192 } 1196 1193 1197 - static int preop_op(const char *inval, char *outval) 1194 + static int preaction_op(const char *inval, char *outval) 1198 1195 { 1196 + int rv; 1197 + 1199 1198 if (outval) 1200 - strcpy(outval, preop); 1199 + strcpy(outval, preaction); 1201 1200 1202 1201 if (!inval) 1203 1202 return 0; 1203 + rv = preaction_op_set_val(inval); 1204 + if (!rv) 1205 + strcpy(preaction, inval); 1206 + return 0; 1207 + } 1204 1208 1209 + static int preop_op_set_val(const char *inval) 1210 + { 1205 1211 if (strcmp(inval, "preop_none") == 0) 1206 1212 preop_val = WDOG_PREOP_NONE; 1207 1213 else if (strcmp(inval, "preop_panic") == 0) ··· 1218 1208 preop_val = WDOG_PREOP_GIVE_DATA; 1219 1209 else 1220 1210 return -EINVAL; 1221 - strcpy(preop, inval); 1211 + return 0; 1212 + } 1213 + 1214 + static int preop_op(const char *inval, char *outval) 1215 + { 1216 + int rv; 1217 + 1218 + if (outval) 1219 + strcpy(outval, preop); 1220 + 1221 + if (!inval) 1222 + return 0; 1223 + 1224 + rv = preop_op_set_val(inval); 1225 + if (!rv) 1226 + strcpy(preop, inval); 1222 1227 return 0; 1223 1228 } 1224 1229 ··· 1270 1245 { 1271 1246 int rv; 1272 1247 1273 - if (action_op(action, NULL)) { 1248 + if (action_op_set_val(action)) { 1274 1249 action_op("reset", NULL); 1275 1250 pr_info("Unknown action '%s', defaulting to reset\n", action); 1276 1251 } 1277 1252 1278 - if (preaction_op(preaction, NULL)) { 1253 + if (preaction_op_set_val(preaction)) { 1279 1254 preaction_op("pre_none", NULL); 1280 1255 pr_info("Unknown preaction '%s', defaulting to none\n", 1281 1256 preaction); 1282 1257 } 1283 1258 1284 - if (preop_op(preop, NULL)) { 1259 + if (preop_op_set_val(preop)) { 1285 1260 preop_op("preop_none", NULL); 1286 1261 pr_info("Unknown preop '%s', defaulting to none\n", preop); 1287 1262 }
+2 -3
drivers/cpufreq/rcpufreq_dt.rs
··· 9 9 cpumask::CpumaskVar, 10 10 device::{Core, Device}, 11 11 error::code::*, 12 - fmt, 13 12 macros::vtable, 14 13 module_platform_driver, of, opp, platform, 15 14 prelude::*, ··· 18 19 19 20 /// Finds exact supply name from the OF node. 20 21 fn find_supply_name_exact(dev: &Device, name: &str) -> Option<CString> { 21 - let prop_name = CString::try_from_fmt(fmt!("{}-supply", name)).ok()?; 22 + let prop_name = CString::try_from_fmt(fmt!("{name}-supply")).ok()?; 22 23 dev.fwnode()? 23 24 .property_present(&prop_name) 24 25 .then(|| CString::try_from_fmt(fmt!("{name}")).ok()) ··· 220 221 module_platform_driver! { 221 222 type: CPUFreqDTDriver, 222 223 name: "cpufreq-dt", 223 - author: "Viresh Kumar <viresh.kumar@linaro.org>", 224 + authors: ["Viresh Kumar <viresh.kumar@linaro.org>"], 224 225 description: "Generic CPUFreq DT driver", 225 226 license: "GPL v2", 226 227 }
+1 -1
drivers/cxl/core/mce.h
··· 7 7 8 8 #ifdef CONFIG_CXL_MCE 9 9 int devm_cxl_register_mce_notifier(struct device *dev, 10 - struct notifier_block *mce_notifer); 10 + struct notifier_block *mce_notifier); 11 11 #else 12 12 static inline int 13 13 devm_cxl_register_mce_notifier(struct device *dev,
+2 -2
drivers/gpu/drm/drm_panic_qr.rs
··· 404 404 let mut out = 0; 405 405 let mut exp = 1; 406 406 for i in 0..poplen { 407 - out += self.decimals[self.len + i] as u16 * exp; 407 + out += u16::from(self.decimals[self.len + i]) * exp; 408 408 exp *= 10; 409 409 } 410 410 Some((out, NUM_CHARS_BITS[poplen])) ··· 425 425 match self.segment { 426 426 Segment::Binary(data) => { 427 427 if self.offset < data.len() { 428 - let byte = data[self.offset] as u16; 428 + let byte = u16::from(data[self.offset]); 429 429 self.offset += 1; 430 430 Some((byte, 8)) 431 431 } else {
+1 -2
drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
··· 220 220 */ 221 221 static int subbuf_start_callback(struct rchan_buf *buf, 222 222 void *subbuf, 223 - void *prev_subbuf, 224 - size_t prev_padding) 223 + void *prev_subbuf) 225 224 { 226 225 /* 227 226 * Use no-overwrite mode by default, where relay will stop accepting
+1 -1
drivers/gpu/drm/nova/nova.rs
··· 12 12 kernel::module_auxiliary_driver! { 13 13 type: NovaDriver, 14 14 name: "Nova", 15 - author: "Danilo Krummrich", 15 + authors: ["Danilo Krummrich"], 16 16 description: "Nova GPU driver", 17 17 license: "GPL v2", 18 18 }
+1 -1
drivers/gpu/drm/xe/xe_vm_types.h
··· 266 266 * up for revalidation. Protected from access with the 267 267 * @invalidated_lock. Removing items from the list 268 268 * additionally requires @lock in write mode, and adding 269 - * items to the list requires either the @userptr.notifer_lock in 269 + * items to the list requires either the @userptr.notifier_lock in 270 270 * write mode, OR @lock in write mode. 271 271 */ 272 272 struct list_head invalidated;
+1 -1
drivers/gpu/nova-core/driver.rs
··· 19 19 MODULE_PCI_TABLE, 20 20 <NovaCore as pci::Driver>::IdInfo, 21 21 [( 22 - pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_NVIDIA, bindings::PCI_ANY_ID as _), 22 + pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_NVIDIA, bindings::PCI_ANY_ID as u32), 23 23 () 24 24 )] 25 25 );
+3 -2
drivers/gpu/nova-core/firmware.rs
··· 30 30 31 31 impl Firmware { 32 32 pub(crate) fn new(dev: &device::Device, chipset: Chipset, ver: &str) -> Result<Firmware> { 33 - let mut chip_name = CString::try_from_fmt(fmt!("{}", chipset))?; 33 + let mut chip_name = CString::try_from_fmt(fmt!("{chipset}"))?; 34 34 chip_name.make_ascii_lowercase(); 35 + let chip_name = &*chip_name; 35 36 36 37 let request = |name_| { 37 - CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver)) 38 + CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{name_}-{ver}.bin")) 38 39 .and_then(|path| firmware::Firmware::request(&path, dev)) 39 40 }; 40 41
+1 -1
drivers/gpu/nova-core/nova_core.rs
··· 18 18 kernel::module_pci_driver! { 19 19 type: driver::NovaCore, 20 20 name: "NovaCore", 21 - author: "Danilo Krummrich", 21 + authors: ["Danilo Krummrich"], 22 22 description: "Nova Core GPU driver", 23 23 license: "GPL v2", 24 24 firmware: [],
+1 -1
drivers/gpu/nova-core/regs.rs
··· 36 36 pub(crate) fn chipset(self) -> Result<Chipset> { 37 37 self.architecture() 38 38 .map(|arch| { 39 - ((arch as u32) << Self::IMPLEMENTATION.len()) | self.implementation() as u32 39 + ((arch as u32) << Self::IMPLEMENTATION.len()) | u32::from(self.implementation()) 40 40 }) 41 41 .and_then(Chipset::try_from) 42 42 }
+1 -1
drivers/gpu/nova-core/regs/macros.rs
··· 307 307 pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { 308 308 const MASK: u32 = $name::[<$field:upper _MASK>]; 309 309 const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 310 - let value = ((value as u32) << SHIFT) & MASK; 310 + let value = (u32::from(value) << SHIFT) & MASK; 311 311 self.0 = (self.0 & !MASK) | value; 312 312 313 313 self
+2 -2
drivers/gpu/nova-core/util.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 3 use kernel::prelude::*; 4 - use kernel::time::{Delta, Instant}; 4 + use kernel::time::{Delta, Instant, Monotonic}; 5 5 6 6 pub(crate) const fn to_lowercase_bytes<const N: usize>(s: &str) -> [u8; N] { 7 7 let src = s.as_bytes(); ··· 33 33 /// TODO[DLAY]: replace with `read_poll_timeout` once it is available. 34 34 /// (https://lore.kernel.org/lkml/20250220070611.214262-8-fujita.tomonori@gmail.com/) 35 35 pub(crate) fn wait_on<R, F: Fn() -> Option<R>>(timeout: Delta, cond: F) -> Result<R> { 36 - let start_time = Instant::now(); 36 + let start_time = Instant::<Monotonic>::now(); 37 37 38 38 loop { 39 39 if let Some(ret) = cond() {
+2
drivers/hid/hid-debug.c
··· 3291 3291 [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", 3292 3292 [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", 3293 3293 [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", 3294 + [BTN_GRIPL] = "BtnGripL", [BTN_GRIPR] = "BtnGripR", 3295 + [BTN_GRIPL2] = "BtnGripL2", [BTN_GRIPR2] = "BtnGripR2", 3294 3296 [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", 3295 3297 [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", 3296 3298 [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger",
+16 -19
drivers/hid/hid-steam.c
··· 755 755 input_set_capability(input, EV_KEY, BTN_THUMBL); 756 756 input_set_capability(input, EV_KEY, BTN_THUMB); 757 757 input_set_capability(input, EV_KEY, BTN_THUMB2); 758 + input_set_capability(input, EV_KEY, BTN_GRIPL); 759 + input_set_capability(input, EV_KEY, BTN_GRIPR); 758 760 if (steam->quirks & STEAM_QUIRK_DECK) { 759 761 input_set_capability(input, EV_KEY, BTN_BASE); 760 - input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY1); 761 - input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY2); 762 - input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY3); 763 - input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY4); 764 - } else { 765 - input_set_capability(input, EV_KEY, BTN_GEAR_DOWN); 766 - input_set_capability(input, EV_KEY, BTN_GEAR_UP); 762 + input_set_capability(input, EV_KEY, BTN_GRIPL2); 763 + input_set_capability(input, EV_KEY, BTN_GRIPR2); 767 764 } 768 765 769 766 input_set_abs_params(input, ABS_X, -32767, 32767, 0, 0); ··· 1416 1419 * 9.4 | BTN_SELECT | menu left 1417 1420 * 9.5 | BTN_MODE | steam logo 1418 1421 * 9.6 | BTN_START | menu right 1419 - * 9.7 | BTN_GEAR_DOWN | left back lever 1420 - * 10.0 | BTN_GEAR_UP | right back lever 1422 + * 9.7 | BTN_GRIPL | left back lever 1423 + * 10.0 | BTN_GRIPR | right back lever 1421 1424 * 10.1 | -- | left-pad clicked 1422 1425 * 10.2 | BTN_THUMBR | right-pad clicked 1423 1426 * 10.3 | BTN_THUMB | left-pad touched (but see explanation below) ··· 1482 1485 input_event(input, EV_KEY, BTN_SELECT, !!(b9 & BIT(4))); 1483 1486 input_event(input, EV_KEY, BTN_MODE, !!(b9 & BIT(5))); 1484 1487 input_event(input, EV_KEY, BTN_START, !!(b9 & BIT(6))); 1485 - input_event(input, EV_KEY, BTN_GEAR_DOWN, !!(b9 & BIT(7))); 1486 - input_event(input, EV_KEY, BTN_GEAR_UP, !!(b10 & BIT(0))); 1488 + input_event(input, EV_KEY, BTN_GRIPL, !!(b9 & BIT(7))); 1489 + input_event(input, EV_KEY, BTN_GRIPR, !!(b10 & BIT(0))); 1487 1490 input_event(input, EV_KEY, BTN_THUMBR, !!(b10 & BIT(2))); 1488 1491 input_event(input, EV_KEY, BTN_THUMBL, !!(b10 & BIT(6))); 1489 1492 input_event(input, EV_KEY, BTN_THUMB, lpad_touched || lpad_and_joy); ··· 1544 1547 * 9.4 | BTN_SELECT | menu left 1545 1548 * 9.5 | BTN_MODE | steam logo 1546 1549 * 9.6 | BTN_START | menu right 1547 - * 9.7 | BTN_TRIGGER_HAPPY3 | left bottom grip button 1548 - * 10.0 | BTN_TRIGGER_HAPPY4 | right bottom grip button 1550 + * 9.7 | BTN_GRIPL2 | left bottom grip button 1551 + * 10.0 | BTN_GRIPR2 | right bottom grip button 1549 1552 * 10.1 | BTN_THUMB | left pad pressed 1550 1553 * 10.2 | BTN_THUMB2 | right pad pressed 1551 1554 * 10.3 | -- | left pad touched ··· 1570 1573 * 12.6 | -- | unknown 1571 1574 * 12.7 | -- | unknown 1572 1575 * 13.0 | -- | unknown 1573 - * 13.1 | BTN_TRIGGER_HAPPY1 | left top grip button 1574 - * 13.2 | BTN_TRIGGER_HAPPY2 | right top grip button 1576 + * 13.1 | BTN_GRIPL | left top grip button 1577 + * 13.2 | BTN_GRIPR | right top grip button 1575 1578 * 13.3 | -- | unknown 1576 1579 * 13.4 | -- | unknown 1577 1580 * 13.5 | -- | unknown ··· 1656 1659 input_event(input, EV_KEY, BTN_SELECT, !!(b9 & BIT(4))); 1657 1660 input_event(input, EV_KEY, BTN_MODE, !!(b9 & BIT(5))); 1658 1661 input_event(input, EV_KEY, BTN_START, !!(b9 & BIT(6))); 1659 - input_event(input, EV_KEY, BTN_TRIGGER_HAPPY3, !!(b9 & BIT(7))); 1660 - input_event(input, EV_KEY, BTN_TRIGGER_HAPPY4, !!(b10 & BIT(0))); 1662 + input_event(input, EV_KEY, BTN_GRIPL2, !!(b9 & BIT(7))); 1663 + input_event(input, EV_KEY, BTN_GRIPR2, !!(b10 & BIT(0))); 1661 1664 input_event(input, EV_KEY, BTN_THUMBL, !!(b10 & BIT(6))); 1662 1665 input_event(input, EV_KEY, BTN_THUMBR, !!(b11 & BIT(2))); 1663 1666 input_event(input, EV_KEY, BTN_DPAD_UP, !!(b9 & BIT(0))); ··· 1666 1669 input_event(input, EV_KEY, BTN_DPAD_DOWN, !!(b9 & BIT(3))); 1667 1670 input_event(input, EV_KEY, BTN_THUMB, !!(b10 & BIT(1))); 1668 1671 input_event(input, EV_KEY, BTN_THUMB2, !!(b10 & BIT(2))); 1669 - input_event(input, EV_KEY, BTN_TRIGGER_HAPPY1, !!(b13 & BIT(1))); 1670 - input_event(input, EV_KEY, BTN_TRIGGER_HAPPY2, !!(b13 & BIT(2))); 1672 + input_event(input, EV_KEY, BTN_GRIPL, !!(b13 & BIT(1))); 1673 + input_event(input, EV_KEY, BTN_GRIPR, !!(b13 & BIT(2))); 1671 1674 input_event(input, EV_KEY, BTN_BASE, !!(b14 & BIT(2))); 1672 1675 1673 1676 input_sync(input);
-1
drivers/i2c/busses/Kconfig
··· 992 992 tristate "Apple SMBus platform driver" 993 993 depends on !I2C_PASEMI 994 994 depends on ARCH_APPLE || COMPILE_TEST 995 - default ARCH_APPLE 996 995 help 997 996 Say Y here if you want to use the I2C controller present on Apple 998 997 Silicon chips such as the M1.
+3 -3
drivers/i2c/busses/i2c-qcom-geni.c
··· 155 155 156 156 /* source_clock = 32 MHz */ 157 157 static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { 158 - { I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 40 }, 159 - { I2C_MAX_FAST_MODE_FREQ, 4, 3, 11, 20 }, 160 - { I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 6, 15 }, 158 + { I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 38 }, 159 + { I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 }, 160 + { I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 5, 15 }, 161 161 {} 162 162 }; 163 163
+21 -11
drivers/i2c/busses/i2c-stm32f7.c
··· 742 742 { 743 743 struct stm32f7_i2c_dev *i2c_dev = arg; 744 744 struct stm32_i2c_dma *dma = i2c_dev->dma; 745 + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 745 746 746 747 stm32f7_i2c_disable_dma_req(i2c_dev); 747 748 dmaengine_terminate_async(dma->chan_using); 748 749 dma_unmap_single(i2c_dev->dev, dma->dma_buf, dma->dma_len, 749 750 dma->dma_data_dir); 751 + if (!f7_msg->smbus) 752 + i2c_put_dma_safe_msg_buf(f7_msg->buf, i2c_dev->msg, true); 750 753 complete(&dma->dma_complete); 751 754 } 752 755 ··· 885 882 { 886 883 struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 887 884 void __iomem *base = i2c_dev->base; 885 + u8 *dma_buf; 888 886 u32 cr1, cr2; 889 887 int ret; 890 888 ··· 935 931 936 932 /* Configure DMA or enable RX/TX interrupt */ 937 933 i2c_dev->use_dma = false; 938 - if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN 939 - && !i2c_dev->atomic) { 940 - ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, 941 - msg->flags & I2C_M_RD, 942 - f7_msg->count, f7_msg->buf, 943 - stm32f7_i2c_dma_callback, 944 - i2c_dev); 945 - if (!ret) 946 - i2c_dev->use_dma = true; 947 - else 948 - dev_warn(i2c_dev->dev, "can't use DMA\n"); 934 + if (i2c_dev->dma && !i2c_dev->atomic) { 935 + dma_buf = i2c_get_dma_safe_msg_buf(msg, STM32F7_I2C_DMA_LEN_MIN); 936 + if (dma_buf) { 937 + f7_msg->buf = dma_buf; 938 + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, 939 + msg->flags & I2C_M_RD, 940 + f7_msg->count, f7_msg->buf, 941 + stm32f7_i2c_dma_callback, 942 + i2c_dev); 943 + if (ret) { 944 + dev_warn(i2c_dev->dev, "can't use DMA\n"); 945 + i2c_put_dma_safe_msg_buf(f7_msg->buf, msg, false); 946 + f7_msg->buf = msg->buf; 947 + } else { 948 + i2c_dev->use_dma = true; 949 + } 950 + } 949 951 } 950 952 951 953 if (!i2c_dev->use_dma) {
+44 -20
drivers/i2c/busses/i2c-tegra.c
··· 134 134 #define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16) 135 135 #define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0) 136 136 137 + #define I2C_MASTER_RESET_CNTRL 0x0a8 138 + 137 139 /* configuration load timeout in microseconds */ 138 140 #define I2C_CONFIG_LOAD_TIMEOUT 1000000 139 141 ··· 186 184 * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that 187 185 * provides additional features and allows for longer messages to 188 186 * be transferred in one go. 187 + * @has_mst_reset: The I2C controller contains MASTER_RESET_CTRL register which 188 + * provides an alternative to controller reset when configured as 189 + * I2C master 189 190 * @quirks: I2C adapter quirks for limiting write/read transfer size and not 190 191 * allowing 0 length transfers. 191 192 * @supports_bus_clear: Bus Clear support to recover from bus hang during ··· 218 213 bool has_multi_master_mode; 219 214 bool has_slcg_override_reg; 220 215 bool has_mst_fifo; 216 + bool has_mst_reset; 221 217 const struct i2c_adapter_quirks *quirks; 222 218 bool supports_bus_clear; 223 219 bool has_apb_dma; ··· 611 605 return 0; 612 606 } 613 607 608 + static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev) 609 + { 610 + if (!i2c_dev->hw->has_mst_reset) 611 + return -EOPNOTSUPP; 612 + 613 + /* 614 + * Writing 1 to I2C_MASTER_RESET_CNTRL will reset all internal state of 615 + * Master logic including FIFOs. Clear this bit to 0 for normal operation. 616 + * SW needs to wait for 2us after assertion and de-assertion of this soft 617 + * reset. 618 + */ 619 + i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL); 620 + fsleep(2); 621 + 622 + i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL); 623 + fsleep(2); 624 + 625 + return 0; 626 + } 627 + 614 628 static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) 615 629 { 616 630 u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode; 617 631 struct i2c_timings *t = &i2c_dev->timings; 618 632 int err; 633 + 634 + /* 635 + * Reset the controller before initializing it. 636 + * In case if device_reset() returns -ENOENT, i.e. when the reset is 637 + * not available, the internal software reset will be used if it is 638 + * supported by the controller. 639 + */ 640 + err = device_reset(i2c_dev->dev); 641 + if (err == -ENOENT) 642 + err = tegra_i2c_master_reset(i2c_dev); 619 643 620 644 /* 621 645 * The reset shouldn't ever fail in practice. The failure will be a ··· 655 619 * emit a noisy warning on error, which won't stay unnoticed and 656 620 * won't hose machine entirely. 657 621 */ 658 - err = device_reset(i2c_dev->dev); 659 622 WARN_ON_ONCE(err); 660 623 661 624 if (IS_DVC(i2c_dev)) ··· 1301 1266 1302 1267 if (i2c_dev->dma_mode) { 1303 1268 if (i2c_dev->msg_read) { 1304 - dma_sync_single_for_device(i2c_dev->dma_dev, 1305 - i2c_dev->dma_phys, 1306 - xfer_size, DMA_FROM_DEVICE); 1307 - 1308 1269 err = tegra_i2c_dma_submit(i2c_dev, xfer_size); 1309 1270 if (err) 1310 1271 return err; 1311 - } else { 1312 - dma_sync_single_for_cpu(i2c_dev->dma_dev, 1313 - i2c_dev->dma_phys, 1314 - xfer_size, DMA_TO_DEVICE); 1315 1272 } 1316 1273 } 1317 1274 ··· 1313 1286 if (i2c_dev->dma_mode) { 1314 1287 memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE, 1315 1288 msg->buf, i2c_dev->msg_len); 1316 - 1317 - dma_sync_single_for_device(i2c_dev->dma_dev, 1318 - i2c_dev->dma_phys, 1319 - xfer_size, DMA_TO_DEVICE); 1320 - 1321 1289 err = tegra_i2c_dma_submit(i2c_dev, xfer_size); 1322 1290 if (err) 1323 1291 return err; ··· 1353 1331 return -ETIMEDOUT; 1354 1332 } 1355 1333 1356 - if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) { 1357 - dma_sync_single_for_cpu(i2c_dev->dma_dev, 1358 - i2c_dev->dma_phys, 1359 - xfer_size, DMA_FROM_DEVICE); 1360 - 1334 + if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) 1361 1335 memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, i2c_dev->msg_len); 1362 - } 1363 1336 } 1364 1337 1365 1338 time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, ··· 1485 1468 .has_multi_master_mode = false, 1486 1469 .has_slcg_override_reg = false, 1487 1470 .has_mst_fifo = false, 1471 + .has_mst_reset = false, 1488 1472 .quirks = &tegra_i2c_quirks, 1489 1473 .supports_bus_clear = false, 1490 1474 .has_apb_dma = true, ··· 1510 1492 .has_multi_master_mode = false, 1511 1493 .has_slcg_override_reg = false, 1512 1494 .has_mst_fifo = false, 1495 + .has_mst_reset = false, 1513 1496 .quirks = &tegra_i2c_quirks, 1514 1497 .supports_bus_clear = false, 1515 1498 .has_apb_dma = true, ··· 1535 1516 .has_multi_master_mode = false, 1536 1517 .has_slcg_override_reg = false, 1537 1518 .has_mst_fifo = false, 1519 + .has_mst_reset = false, 1538 1520 .quirks = &tegra_i2c_quirks, 1539 1521 .supports_bus_clear = true, 1540 1522 .has_apb_dma = true, ··· 1560 1540 .has_multi_master_mode = false, 1561 1541 .has_slcg_override_reg = true, 1562 1542 .has_mst_fifo = false, 1543 + .has_mst_reset = false, 1563 1544 .quirks = &tegra_i2c_quirks, 1564 1545 .supports_bus_clear = true, 1565 1546 .has_apb_dma = true, ··· 1585 1564 .has_multi_master_mode = false, 1586 1565 .has_slcg_override_reg = true, 1587 1566 .has_mst_fifo = false, 1567 + .has_mst_reset = false, 1588 1568 .quirks = &tegra_i2c_quirks, 1589 1569 .supports_bus_clear = true, 1590 1570 .has_apb_dma = true, ··· 1610 1588 .has_multi_master_mode = false, 1611 1589 .has_slcg_override_reg = true, 1612 1590 .has_mst_fifo = false, 1591 + .has_mst_reset = false, 1613 1592 .quirks = &tegra_i2c_quirks, 1614 1593 .supports_bus_clear = true, 1615 1594 .has_apb_dma = false, ··· 1635 1612 .has_multi_master_mode = true, 1636 1613 .has_slcg_override_reg = true, 1637 1614 .has_mst_fifo = true, 1615 + .has_mst_reset = true, 1638 1616 .quirks = &tegra194_i2c_quirks, 1639 1617 .supports_bus_clear = true, 1640 1618 .has_apb_dma = false,
+1
drivers/i2c/i2c-core-acpi.c
··· 370 370 * the device works without issues on Windows at what is expected to be 371 371 * a 400KHz frequency. The root cause of the issue is not known. 372 372 */ 373 + { "DLL0945", 0 }, 373 374 { "ELAN06FA", 0 }, 374 375 {} 375 376 };
+1 -2
drivers/i2c/muxes/i2c-mux-mule.c
··· 47 47 struct mule_i2c_reg_mux *priv; 48 48 struct i2c_client *client; 49 49 struct i2c_mux_core *muxc; 50 - struct device_node *dev; 51 50 unsigned int readback; 52 51 int ndev, ret; 53 52 bool old_fw; ··· 94 95 "Failed to register mux remove\n"); 95 96 96 97 /* Create device adapters */ 97 - for_each_child_of_node(mux_dev->of_node, dev) { 98 + for_each_child_of_node_scoped(mux_dev->of_node, dev) { 98 99 u32 reg; 99 100 100 101 ret = of_property_read_u32(dev, "reg", &reg);
+6 -5
drivers/i3c/device.c
··· 26 26 * 27 27 * This function can sleep and thus cannot be called in atomic context. 28 28 * 29 - * Return: 0 in case of success, a negative error core otherwise. 30 - * -EAGAIN: controller lost address arbitration. Target 31 - * (IBI, HJ or controller role request) win the bus. Client 32 - * driver needs to resend the 'xfers' some time later. 33 - * See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3. 29 + * Return: 30 + * * 0 in case of success, a negative error core otherwise. 31 + * * -EAGAIN: controller lost address arbitration. Target (IBI, HJ or 32 + * controller role request) win the bus. Client driver needs to resend the 33 + * 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section: 34 + * 5.1.2.2.3. 34 35 */ 35 36 int i3c_device_do_priv_xfers(struct i3c_device *dev, 36 37 struct i3c_priv_xfer *xfers,
+38
drivers/i3c/internals.h
··· 9 9 #define I3C_INTERNALS_H 10 10 11 11 #include <linux/i3c/master.h> 12 + #include <linux/io.h> 12 13 13 14 void i3c_bus_normaluse_lock(struct i3c_bus *bus); 14 15 void i3c_bus_normaluse_unlock(struct i3c_bus *bus); ··· 23 22 int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev, 24 23 const struct i3c_ibi_setup *req); 25 24 void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev); 25 + 26 + /** 27 + * i3c_writel_fifo - Write data buffer to 32bit FIFO 28 + * @addr: FIFO Address to write to 29 + * @buf: Pointer to the data bytes to write 30 + * @nbytes: Number of bytes to write 31 + */ 32 + static inline void i3c_writel_fifo(void __iomem *addr, const void *buf, 33 + int nbytes) 34 + { 35 + writesl(addr, buf, nbytes / 4); 36 + if (nbytes & 3) { 37 + u32 tmp = 0; 38 + 39 + memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3); 40 + writel(tmp, addr); 41 + } 42 + } 43 + 44 + /** 45 + * i3c_readl_fifo - Read data buffer from 32bit FIFO 46 + * @addr: FIFO Address to read from 47 + * @buf: Pointer to the buffer to store read bytes 48 + * @nbytes: Number of bytes to read 49 + */ 50 + static inline void i3c_readl_fifo(const void __iomem *addr, void *buf, 51 + int nbytes) 52 + { 53 + readsl(addr, buf, nbytes / 4); 54 + if (nbytes & 3) { 55 + u32 tmp; 56 + 57 + tmp = readl(addr); 58 + memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3); 59 + } 60 + } 61 + 26 62 #endif /* I3C_INTERNAL_H */
+20 -18
drivers/i3c/master.c
··· 141 141 142 142 i3c_bus_normaluse_lock(bus); 143 143 desc = dev_to_i3cdesc(dev); 144 - ret = sprintf(buf, "%x\n", desc->info.bcr); 144 + ret = sprintf(buf, "0x%02x\n", desc->info.bcr); 145 145 i3c_bus_normaluse_unlock(bus); 146 146 147 147 return ret; ··· 158 158 159 159 i3c_bus_normaluse_lock(bus); 160 160 desc = dev_to_i3cdesc(dev); 161 - ret = sprintf(buf, "%x\n", desc->info.dcr); 161 + ret = sprintf(buf, "0x%02x\n", desc->info.dcr); 162 162 i3c_bus_normaluse_unlock(bus); 163 163 164 164 return ret; ··· 727 727 switch (i3cbus->mode) { 728 728 case I3C_BUS_MODE_PURE: 729 729 if (!i3cbus->scl_rate.i3c) 730 - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; 730 + i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE; 731 731 break; 732 732 case I3C_BUS_MODE_MIXED_FAST: 733 733 case I3C_BUS_MODE_MIXED_LIMITED: 734 734 if (!i3cbus->scl_rate.i3c) 735 - i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; 735 + i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE; 736 736 if (!i3cbus->scl_rate.i2c) 737 737 i3cbus->scl_rate.i2c = max_i2c_scl_rate; 738 738 break; ··· 754 754 * I3C/I2C frequency may have been overridden, check that user-provided 755 755 * values are not exceeding max possible frequency. 756 756 */ 757 - if (i3cbus->scl_rate.i3c > I3C_BUS_MAX_I3C_SCL_RATE || 758 - i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_RATE) 757 + if (i3cbus->scl_rate.i3c > I3C_BUS_I3C_SCL_MAX_RATE || 758 + i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE) 759 759 return -EINVAL; 760 760 761 761 return 0; ··· 837 837 return -EINVAL; 838 838 839 839 if (!master->ops->send_ccc_cmd) 840 - return -ENOTSUPP; 840 + return -EOPNOTSUPP; 841 841 842 842 if ((cmd->id & I3C_CCC_DIRECT) && (!cmd->dests || !cmd->ndests)) 843 843 return -EINVAL; 844 844 845 845 if (master->ops->supports_ccc_cmd && 846 846 !master->ops->supports_ccc_cmd(master, cmd)) 847 - return -ENOTSUPP; 847 + return -EOPNOTSUPP; 848 848 849 849 ret = master->ops->send_ccc_cmd(master, cmd); 850 850 if (ret) { ··· 1439 1439 1440 1440 if (dev->info.bcr & I3C_BCR_HDR_CAP) { 1441 1441 ret = i3c_master_gethdrcap_locked(master, &dev->info); 1442 - if (ret) 1442 + if (ret && ret != -EOPNOTSUPP) 1443 1443 return ret; 1444 1444 } 1445 1445 ··· 2210 2210 */ 2211 2211 if (boardinfo->base.flags & I2C_CLIENT_TEN) { 2212 2212 dev_err(dev, "I2C device with 10 bit address not supported."); 2213 - return -ENOTSUPP; 2213 + return -EOPNOTSUPP; 2214 2214 } 2215 2215 2216 2216 /* LVR is encoded in reg[2]. */ ··· 2340 2340 return -EINVAL; 2341 2341 2342 2342 if (!master->ops->i2c_xfers) 2343 - return -ENOTSUPP; 2343 + return -EOPNOTSUPP; 2344 2344 2345 2345 /* Doing transfers to different devices is not supported. */ 2346 2346 addr = xfers[0].addr; 2347 2347 for (i = 1; i < nxfers; i++) { 2348 2348 if (addr != xfers[i].addr) 2349 - return -ENOTSUPP; 2349 + return -EOPNOTSUPP; 2350 2350 } 2351 2351 2352 2352 i3c_bus_normaluse_lock(&master->bus); ··· 2467 2467 case BUS_NOTIFY_DEL_DEVICE: 2468 2468 ret = i3c_master_i2c_detach(adap, client); 2469 2469 break; 2470 + default: 2471 + ret = -EINVAL; 2470 2472 } 2471 2473 i3c_bus_maintenance_unlock(&master->bus); 2472 2474 ··· 2768 2766 * controller) 2769 2767 * @ops: the master controller operations 2770 2768 * @secondary: true if you are registering a secondary master. Will return 2771 - * -ENOTSUPP if set to true since secondary masters are not yet 2769 + * -EOPNOTSUPP if set to true since secondary masters are not yet 2772 2770 * supported 2773 2771 * 2774 2772 * This function takes care of everything for you: ··· 2787 2785 const struct i3c_master_controller_ops *ops, 2788 2786 bool secondary) 2789 2787 { 2790 - unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; 2788 + unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE; 2791 2789 struct i3c_bus *i3cbus = i3c_master_get_bus(master); 2792 2790 enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; 2793 2791 struct i2c_dev_boardinfo *i2cbi; ··· 2795 2793 2796 2794 /* We do not support secondary masters yet. */ 2797 2795 if (secondary) 2798 - return -ENOTSUPP; 2796 + return -EOPNOTSUPP; 2799 2797 2800 2798 ret = i3c_master_check_ops(ops); 2801 2799 if (ret) ··· 2846 2844 } 2847 2845 2848 2846 if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE) 2849 - i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE; 2847 + i2c_scl_rate = I3C_BUS_I2C_FM_SCL_MAX_RATE; 2850 2848 } 2851 2849 2852 2850 ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate); ··· 2956 2954 return -EINVAL; 2957 2955 2958 2956 if (!master->ops->priv_xfers) 2959 - return -ENOTSUPP; 2957 + return -EOPNOTSUPP; 2960 2958 2961 2959 return master->ops->priv_xfers(dev, xfers, nxfers); 2962 2960 } ··· 3006 3004 int ret; 3007 3005 3008 3006 if (!master->ops->request_ibi) 3009 - return -ENOTSUPP; 3007 + return -EOPNOTSUPP; 3010 3008 3011 3009 if (dev->ibi) 3012 3010 return -EBUSY;
+10
drivers/i3c/master/Kconfig
··· 64 64 65 65 This driver can also be built as a module. If so, the module will be 66 66 called mipi-i3c-hci-pci. 67 + 68 + config RENESAS_I3C 69 + tristate "Renesas I3C controller driver" 70 + depends on HAS_IOMEM 71 + depends on ARCH_RENESAS || COMPILE_TEST 72 + help 73 + Support the Renesas I3C controller as found in some RZ variants. 74 + 75 + This driver can also be built as a module. If so, the module will be 76 + called renesas-i3c.
+1
drivers/i3c/master/Makefile
··· 4 4 obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o 5 5 obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o 6 6 obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/ 7 + obj-$(CONFIG_RENESAS_I3C) += renesas-i3c.o
+11 -36
drivers/i3c/master/dw-i3c-master.c
··· 23 23 #include <linux/reset.h> 24 24 #include <linux/slab.h> 25 25 26 + #include "../internals.h" 26 27 #include "dw-i3c-master.h" 27 28 28 29 #define DEVICE_CTRL 0x0 ··· 337 336 static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master, 338 337 const u8 *bytes, int nbytes) 339 338 { 340 - writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4); 341 - if (nbytes & 3) { 342 - u32 tmp = 0; 343 - 344 - memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3); 345 - writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1); 346 - } 347 - } 348 - 349 - static void dw_i3c_master_read_fifo(struct dw_i3c_master *master, 350 - int reg, u8 *bytes, int nbytes) 351 - { 352 - readsl(master->regs + reg, bytes, nbytes / 4); 353 - if (nbytes & 3) { 354 - u32 tmp; 355 - 356 - readsl(master->regs + reg, &tmp, 1); 357 - memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3); 358 - } 339 + i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes); 359 340 } 360 341 361 342 static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master, 362 343 u8 *bytes, int nbytes) 363 344 { 364 - return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes); 345 + i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes); 365 346 } 366 347 367 348 static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master, 368 349 u8 *bytes, int nbytes) 369 350 { 370 - return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes); 351 + i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes); 371 352 } 372 353 373 354 static struct dw_i3c_xfer * ··· 605 622 core_period = DIV_ROUND_UP(1000000000, core_rate); 606 623 607 624 lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period); 608 - hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt; 625 + hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE) - lcnt; 609 626 scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) | 610 627 SCL_I2C_FMP_TIMING_LCNT(lcnt); 611 628 writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING); 612 629 master->i2c_fmp_timing = scl_timing; 613 630 614 631 lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period); 615 - hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt; 632 + hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_MAX_RATE) - lcnt; 616 633 scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) | 617 634 SCL_I2C_FM_TIMING_LCNT(lcnt); 618 635 writel(scl_timing, master->regs + SCL_I2C_FM_TIMING); ··· 682 699 dw_i3c_master_enable(master); 683 700 684 701 rpm_out: 685 - pm_runtime_mark_last_busy(master->dev); 686 702 pm_runtime_put_autosuspend(master->dev); 687 703 return ret; 688 704 } ··· 811 829 else 812 830 ret = dw_i3c_ccc_set(master, ccc); 813 831 814 - pm_runtime_mark_last_busy(master->dev); 815 832 pm_runtime_put_autosuspend(master->dev); 816 833 return ret; 817 834 } ··· 893 912 dw_i3c_master_free_xfer(xfer); 894 913 895 914 rpm_out: 896 - pm_runtime_mark_last_busy(master->dev); 897 915 pm_runtime_put_autosuspend(master->dev); 898 916 return ret; 899 917 } ··· 912 932 return 0; 913 933 914 934 if (i3c_nxfers > master->caps.cmdfifodepth) 915 - return -ENOTSUPP; 935 + return -EOPNOTSUPP; 916 936 917 937 for (i = 0; i < i3c_nxfers; i++) { 918 938 if (i3c_xfers[i].rnw) ··· 923 943 924 944 if (ntxwords > master->caps.datafifodepth || 925 945 nrxwords > master->caps.datafifodepth) 926 - return -ENOTSUPP; 946 + return -EOPNOTSUPP; 927 947 928 948 xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); 929 949 if (!xfer) ··· 978 998 ret = xfer->ret; 979 999 dw_i3c_master_free_xfer(xfer); 980 1000 981 - pm_runtime_mark_last_busy(master->dev); 982 1001 pm_runtime_put_autosuspend(master->dev); 983 1002 return ret; 984 1003 } ··· 1072 1093 return 0; 1073 1094 1074 1095 if (i2c_nxfers > master->caps.cmdfifodepth) 1075 - return -ENOTSUPP; 1096 + return -EOPNOTSUPP; 1076 1097 1077 1098 for (i = 0; i < i2c_nxfers; i++) { 1078 1099 if (i2c_xfers[i].flags & I2C_M_RD) ··· 1083 1104 1084 1105 if (ntxwords > master->caps.datafifodepth || 1085 1106 nrxwords > master->caps.datafifodepth) 1086 - return -ENOTSUPP; 1107 + return -EOPNOTSUPP; 1087 1108 1088 1109 xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers); 1089 1110 if (!xfer) ··· 1121 1142 } 1122 1143 1123 1144 dw_i3c_master_enqueue_xfer(master, xfer); 1124 - if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT)) 1145 + if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout)) 1125 1146 dw_i3c_master_dequeue_xfer(master, xfer); 1126 1147 1127 1148 ret = xfer->ret; 1128 1149 dw_i3c_master_free_xfer(xfer); 1129 1150 1130 - pm_runtime_mark_last_busy(master->dev); 1131 1151 pm_runtime_put_autosuspend(master->dev); 1132 1152 return ret; 1133 1153 } ··· 1294 1316 writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK, 1295 1317 master->regs + DEVICE_CTRL); 1296 1318 1297 - pm_runtime_mark_last_busy(master->dev); 1298 1319 pm_runtime_put_autosuspend(master->dev); 1299 1320 return 0; 1300 1321 } ··· 1319 1342 1320 1343 if (rc) { 1321 1344 dw_i3c_master_set_sir_enabled(master, dev, data->index, false); 1322 - pm_runtime_mark_last_busy(master->dev); 1323 1345 pm_runtime_put_autosuspend(master->dev); 1324 1346 } 1325 1347 ··· 1338 1362 1339 1363 dw_i3c_master_set_sir_enabled(master, dev, data->index, false); 1340 1364 1341 - pm_runtime_mark_last_busy(master->dev); 1342 1365 pm_runtime_put_autosuspend(master->dev); 1343 1366 return 0; 1344 1367 }
+24 -66
drivers/i3c/master/i3c-master-cdns.c
··· 23 23 #include <linux/spinlock.h> 24 24 #include <linux/workqueue.h> 25 25 26 + #include "../internals.h" 27 + 26 28 #define DEV_ID 0x0 27 29 #define DEV_ID_I3C_MASTER 0x5034 28 30 ··· 414 412 } xferqueue; 415 413 void __iomem *regs; 416 414 struct clk *sysclk; 417 - struct clk *pclk; 418 415 struct cdns_i3c_master_caps caps; 419 416 unsigned long i3c_scl_lim; 420 417 const struct cdns_i3c_data *devdata; ··· 428 427 static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master, 429 428 const u8 *bytes, int nbytes) 430 429 { 431 - writesl(master->regs + TX_FIFO, bytes, nbytes / 4); 432 - if (nbytes & 3) { 433 - u32 tmp = 0; 434 - 435 - memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3); 436 - writesl(master->regs + TX_FIFO, &tmp, 1); 437 - } 430 + i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes); 438 431 } 439 432 440 433 static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master, 441 434 u8 *bytes, int nbytes) 442 435 { 443 - readsl(master->regs + RX_FIFO, bytes, nbytes / 4); 444 - if (nbytes & 3) { 445 - u32 tmp; 446 - 447 - readsl(master->regs + RX_FIFO, &tmp, 1); 448 - memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3); 449 - } 436 + i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes); 450 437 } 451 438 452 439 static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m, ··· 731 742 732 743 for (i = 0; i < nxfers; i++) { 733 744 if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX) 734 - return -ENOTSUPP; 745 + return -EOPNOTSUPP; 735 746 } 736 747 737 748 if (!nxfers) ··· 739 750 740 751 if (nxfers > master->caps.cmdfifodepth || 741 752 nxfers > master->caps.cmdrfifodepth) 742 - return -ENOTSUPP; 753 + return -EOPNOTSUPP; 743 754 744 755 /* 745 756 * First make sure that all transactions (block of transfers separated ··· 754 765 755 766 if (rxslots > master->caps.rxfifodepth || 756 767 txslots > master->caps.txfifodepth) 757 - return -ENOTSUPP; 768 + return -EOPNOTSUPP; 758 769 759 770 cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers); 760 771 if (!cdns_xfer) ··· 811 822 int i, ret = 0; 812 823 813 824 if (nxfers > master->caps.cmdfifodepth) 814 - return -ENOTSUPP; 825 + return -EOPNOTSUPP; 815 826 816 827 for (i = 0; i < nxfers; i++) { 817 828 if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX) 818 - return -ENOTSUPP; 829 + return -EOPNOTSUPP; 819 830 820 831 if (xfers[i].flags & I2C_M_RD) 821 832 nrxwords += DIV_ROUND_UP(xfers[i].len, 4); ··· 825 836 826 837 if (ntxwords > master->caps.txfifodepth || 827 838 nrxwords > master->caps.rxfifodepth) 828 - return -ENOTSUPP; 839 + return -EOPNOTSUPP; 829 840 830 841 xfer = cdns_i3c_master_alloc_xfer(master, nxfers); 831 842 if (!xfer) ··· 852 863 } 853 864 854 865 cdns_i3c_master_queue_xfer(master, xfer); 855 - if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) 866 + if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout)) 856 867 cdns_i3c_master_unqueue_xfer(master, xfer); 857 868 858 869 ret = xfer->ret; ··· 1319 1330 buf = slot->data; 1320 1331 1321 1332 nbytes = IBIR_XFER_BYTES(ibir); 1322 - readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4); 1323 - if (nbytes % 3) { 1324 - u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO); 1325 - 1326 - memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3); 1327 - } 1333 + i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes); 1328 1334 1329 1335 slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir), 1330 1336 dev->ibi->max_payload_len); ··· 1550 1566 static int cdns_i3c_master_probe(struct platform_device *pdev) 1551 1567 { 1552 1568 struct cdns_i3c_master *master; 1569 + struct clk *pclk; 1553 1570 int ret, irq; 1554 1571 u32 val; 1555 1572 ··· 1566 1581 if (IS_ERR(master->regs)) 1567 1582 return PTR_ERR(master->regs); 1568 1583 1569 - master->pclk = devm_clk_get(&pdev->dev, "pclk"); 1570 - if (IS_ERR(master->pclk)) 1571 - return PTR_ERR(master->pclk); 1584 + pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); 1585 + if (IS_ERR(pclk)) 1586 + return PTR_ERR(pclk); 1572 1587 1573 - master->sysclk = devm_clk_get(&pdev->dev, "sysclk"); 1588 + master->sysclk = devm_clk_get_enabled(&pdev->dev, "sysclk"); 1574 1589 if (IS_ERR(master->sysclk)) 1575 1590 return PTR_ERR(master->sysclk); 1576 1591 ··· 1578 1593 if (irq < 0) 1579 1594 return irq; 1580 1595 1581 - ret = clk_prepare_enable(master->pclk); 1582 - if (ret) 1583 - return ret; 1584 - 1585 - ret = clk_prepare_enable(master->sysclk); 1586 - if (ret) 1587 - goto err_disable_pclk; 1588 - 1589 - if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) { 1590 - ret = -EINVAL; 1591 - goto err_disable_sysclk; 1592 - } 1596 + if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) 1597 + return -EINVAL; 1593 1598 1594 1599 spin_lock_init(&master->xferqueue.lock); 1595 1600 INIT_LIST_HEAD(&master->xferqueue.list); ··· 1590 1615 ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0, 1591 1616 dev_name(&pdev->dev), master); 1592 1617 if (ret) 1593 - goto err_disable_sysclk; 1618 + return ret; 1594 1619 1595 1620 platform_set_drvdata(pdev, master); 1596 1621 ··· 1612 1637 master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots, 1613 1638 sizeof(*master->ibi.slots), 1614 1639 GFP_KERNEL); 1615 - if (!master->ibi.slots) { 1616 - ret = -ENOMEM; 1617 - goto err_disable_sysclk; 1618 - } 1640 + if (!master->ibi.slots) 1641 + return -ENOMEM; 1619 1642 1620 1643 writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL); 1621 1644 writel(MST_INT_IBIR_THR, master->regs + MST_IER); 1622 1645 writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL); 1623 1646 1624 - ret = i3c_master_register(&master->base, &pdev->dev, 1625 - &cdns_i3c_master_ops, false); 1626 - if (ret) 1627 - goto err_disable_sysclk; 1628 - 1629 - return 0; 1630 - 1631 - err_disable_sysclk: 1632 - clk_disable_unprepare(master->sysclk); 1633 - 1634 - err_disable_pclk: 1635 - clk_disable_unprepare(master->pclk); 1636 - 1637 - return ret; 1647 + return i3c_master_register(&master->base, &pdev->dev, 1648 + &cdns_i3c_master_ops, false); 1638 1649 } 1639 1650 1640 1651 static void cdns_i3c_master_remove(struct platform_device *pdev) ··· 1629 1668 1630 1669 cancel_work_sync(&master->hj_work); 1631 1670 i3c_master_unregister(&master->base); 1632 - 1633 - clk_disable_unprepare(master->sysclk); 1634 - clk_disable_unprepare(master->pclk); 1635 1671 } 1636 1672 1637 1673 static struct platform_driver cdns_i3c_master = {
+1 -1
drivers/i3c/master/mipi-i3c-hci/core.c
··· 395 395 ret = hci->io->queue_xfer(hci, xfer, nxfers); 396 396 if (ret) 397 397 goto out; 398 - if (!wait_for_completion_timeout(&done, HZ) && 398 + if (!wait_for_completion_timeout(&done, m->i2c.timeout) && 399 399 hci->io->dequeue_xfer(hci, xfer, nxfers)) { 400 400 ret = -ETIME; 401 401 goto out;
+1404
drivers/i3c/master/renesas-i3c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Renesas I3C Controller driver 4 + * Copyright (C) 2023-25 Renesas Electronics Corp. 5 + * 6 + * TODO: IBI support, HotJoin support, Target support 7 + */ 8 + 9 + #include <linux/bitfield.h> 10 + #include <linux/bitops.h> 11 + #include <linux/clk.h> 12 + #include <linux/completion.h> 13 + #include <linux/err.h> 14 + #include <linux/errno.h> 15 + #include <linux/i2c.h> 16 + #include <linux/i3c/master.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/ioport.h> 19 + #include <linux/iopoll.h> 20 + #include <linux/list.h> 21 + #include <linux/module.h> 22 + #include <linux/of.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/reset.h> 25 + #include <linux/slab.h> 26 + #include "../internals.h" 27 + 28 + #define PRTS 0x00 29 + #define PRTS_PRTMD BIT(0) 30 + 31 + #define BCTL 0x14 32 + #define BCTL_INCBA BIT(0) 33 + #define BCTL_HJACKCTL BIT(8) 34 + #define BCTL_ABT BIT(29) 35 + #define BCTL_BUSE BIT(31) 36 + 37 + #define MSDVAD 0x18 38 + #define MSDVAD_MDYAD(x) FIELD_PREP(GENMASK(21, 16), x) 39 + #define MSDVAD_MDYADV BIT(31) 40 + 41 + #define RSTCTL 0x20 42 + #define RSTCTL_RI3CRST BIT(0) 43 + #define RSTCTL_INTLRST BIT(16) 44 + 45 + #define INST 0x30 46 + 47 + #define IBINCTL 0x58 48 + #define IBINCTL_NRHJCTL BIT(0) 49 + #define IBINCTL_NRMRCTL BIT(1) 50 + #define IBINCTL_NRSIRCTL BIT(3) 51 + 52 + #define SVCTL 0x64 53 + 54 + #define REFCKCTL 0x70 55 + #define REFCKCTL_IREFCKS(x) FIELD_PREP(GENMASK(2, 0), x) 56 + 57 + #define STDBR 0x74 58 + #define STDBR_SBRLO(cond, x) FIELD_PREP(GENMASK(7, 0), (x) >> (cond)) 59 + #define STDBR_SBRHO(cond, x) FIELD_PREP(GENMASK(15, 8), (x) >> (cond)) 60 + #define STDBR_SBRLP(x) FIELD_PREP(GENMASK(21, 16), x) 61 + #define STDBR_SBRHP(x) FIELD_PREP(GENMASK(29, 24), x) 62 + #define STDBR_DSBRPO BIT(31) 63 + 64 + #define EXTBR 0x78 65 + #define EXTBR_EBRLO(x) FIELD_PREP(GENMASK(7, 0), x) 66 + #define EXTBR_EBRHO(x) FIELD_PREP(GENMASK(15, 8), x) 67 + #define EXTBR_EBRLP(x) FIELD_PREP(GENMASK(21, 16), x) 68 + #define EXTBR_EBRHP(x) FIELD_PREP(GENMASK(29, 24), x) 69 + 70 + #define BFRECDT 0x7c 71 + #define BFRECDT_FRECYC(x) FIELD_PREP(GENMASK(8, 0), x) 72 + 73 + #define BAVLCDT 0x80 74 + #define BAVLCDT_AVLCYC(x) FIELD_PREP(GENMASK(8, 0), x) 75 + 76 + #define BIDLCDT 0x84 77 + #define BIDLCDT_IDLCYC(x) FIELD_PREP(GENMASK(17, 0), x) 78 + 79 + #define ACKCTL 0xa0 80 + #define ACKCTL_ACKT BIT(1) 81 + #define ACKCTL_ACKTWP BIT(2) 82 + 83 + #define SCSTRCTL 0xa4 84 + #define SCSTRCTL_ACKTWE BIT(0) 85 + #define SCSTRCTL_RWE BIT(1) 86 + 87 + #define SCSTLCTL 0xb0 88 + 89 + #define CNDCTL 0x140 90 + #define CNDCTL_STCND BIT(0) 91 + #define CNDCTL_SRCND BIT(1) 92 + #define CNDCTL_SPCND BIT(2) 93 + 94 + #define NCMDQP 0x150 /* Normal Command Queue */ 95 + #define NCMDQP_CMD_ATTR(x) FIELD_PREP(GENMASK(2, 0), x) 96 + #define NCMDQP_IMMED_XFER 0x01 97 + #define NCMDQP_ADDR_ASSGN 0x02 98 + #define NCMDQP_TID(x) FIELD_PREP(GENMASK(6, 3), x) 99 + #define NCMDQP_CMD(x) FIELD_PREP(GENMASK(14, 7), x) 100 + #define NCMDQP_CP BIT(15) 101 + #define NCMDQP_DEV_INDEX(x) FIELD_PREP(GENMASK(20, 16), x) 102 + #define NCMDQP_BYTE_CNT(x) FIELD_PREP(GENMASK(25, 23), x) 103 + #define NCMDQP_DEV_COUNT(x) FIELD_PREP(GENMASK(29, 26), x) 104 + #define NCMDQP_MODE(x) FIELD_PREP(GENMASK(28, 26), x) 105 + #define NCMDQP_RNW(x) FIELD_PREP(GENMASK(29, 29), x) 106 + #define NCMDQP_ROC BIT(30) 107 + #define NCMDQP_TOC BIT(31) 108 + #define NCMDQP_DATA_LENGTH(x) FIELD_PREP(GENMASK(31, 16), x) 109 + 110 + #define NRSPQP 0x154 /* Normal Respone Queue */ 111 + #define NRSPQP_NO_ERROR 0 112 + #define NRSPQP_ERROR_CRC 1 113 + #define NRSPQP_ERROR_PARITY 2 114 + #define NRSPQP_ERROR_FRAME 3 115 + #define NRSPQP_ERROR_IBA_NACK 4 116 + #define NRSPQP_ERROR_ADDRESS_NACK 5 117 + #define NRSPQP_ERROR_OVER_UNDER_FLOW 6 118 + #define NRSPQP_ERROR_TRANSF_ABORT 8 119 + #define NRSPQP_ERROR_I2C_W_NACK_ERR 9 120 + #define NRSPQP_ERROR_UNSUPPORTED 10 121 + #define NRSPQP_DATA_LEN(x) FIELD_GET(GENMASK(15, 0), x) 122 + #define NRSPQP_ERR_STATUS(x) FIELD_GET(GENMASK(31, 28), x) 123 + 124 + #define NTDTBP0 0x158 /* Normal Transfer Data Buffer */ 125 + #define NTDTBP0_DEPTH 16 126 + 127 + #define NQTHCTL 0x190 128 + #define NQTHCTL_CMDQTH(x) FIELD_PREP(GENMASK(1, 0), x) 129 + #define NQTHCTL_IBIDSSZ(x) FIELD_PREP(GENMASK(23, 16), x) 130 + 131 + #define NTBTHCTL0 0x194 132 + 133 + #define NRQTHCTL 0x1c0 134 + 135 + #define BST 0x1d0 136 + #define BST_STCNDDF BIT(0) 137 + #define BST_SPCNDDF BIT(1) 138 + #define BST_NACKDF BIT(4) 139 + #define BST_TENDF BIT(8) 140 + 141 + #define BSTE 0x1d4 142 + #define BSTE_STCNDDE BIT(0) 143 + #define BSTE_SPCNDDE BIT(1) 144 + #define BSTE_NACKDE BIT(4) 145 + #define BSTE_TENDE BIT(8) 146 + #define BSTE_ALE BIT(16) 147 + #define BSTE_TODE BIT(20) 148 + #define BSTE_WUCNDDE BIT(24) 149 + #define BSTE_ALL_FLAG (BSTE_STCNDDE | BSTE_SPCNDDE |\ 150 + BSTE_NACKDE | BSTE_TENDE |\ 151 + BSTE_ALE | BSTE_TODE | BSTE_WUCNDDE) 152 + 153 + #define BIE 0x1d8 154 + #define BIE_STCNDDIE BIT(0) 155 + #define BIE_SPCNDDIE BIT(1) 156 + #define BIE_NACKDIE BIT(4) 157 + #define BIE_TENDIE BIT(8) 158 + 159 + #define NTST 0x1e0 160 + #define NTST_TDBEF0 BIT(0) 161 + #define NTST_RDBFF0 BIT(1) 162 + #define NTST_CMDQEF BIT(3) 163 + #define NTST_RSPQFF BIT(4) 164 + #define NTST_TABTF BIT(5) 165 + #define NTST_TEF BIT(9) 166 + 167 + #define NTSTE 0x1e4 168 + #define NTSTE_TDBEE0 BIT(0) 169 + #define NTSTE_RDBFE0 BIT(1) 170 + #define NTSTE_IBIQEFE BIT(2) 171 + #define NTSTE_CMDQEE BIT(3) 172 + #define NTSTE_RSPQFE BIT(4) 173 + #define NTSTE_TABTE BIT(5) 174 + #define NTSTE_TEE BIT(9) 175 + #define NTSTE_RSQFE BIT(20) 176 + #define NTSTE_ALL_FLAG (NTSTE_TDBEE0 | NTSTE_RDBFE0 |\ 177 + NTSTE_IBIQEFE | NTSTE_CMDQEE |\ 178 + NTSTE_RSPQFE | NTSTE_TABTE |\ 179 + NTSTE_TEE | NTSTE_RSQFE) 180 + 181 + #define NTIE 0x1e8 182 + #define NTIE_TDBEIE0 BIT(0) 183 + #define NTIE_RDBFIE0 BIT(1) 184 + #define NTIE_IBIQEFIE BIT(2) 185 + #define NTIE_RSPQFIE BIT(4) 186 + #define NTIE_RSQFIE BIT(20) 187 + 188 + #define BCST 0x210 189 + #define BCST_BFREF BIT(0) 190 + 191 + #define DATBAS(x) (0x224 + 0x8 * (x)) 192 + #define DATBAS_DVSTAD(x) FIELD_PREP(GENMASK(6, 0), x) 193 + #define DATBAS_DVDYAD(x) FIELD_PREP(GENMASK(23, 16), x) 194 + 195 + #define NDBSTLV0 0x398 196 + #define NDBSTLV0_RDBLV(x) FIELD_GET(GENMASK(15, 8), x) 197 + 198 + #define RENESAS_I3C_MAX_DEVS 8 199 + #define I2C_INIT_MSG -1 200 + 201 + enum i3c_internal_state { 202 + I3C_INTERNAL_STATE_DISABLED, 203 + I3C_INTERNAL_STATE_CONTROLLER_IDLE, 204 + I3C_INTERNAL_STATE_CONTROLLER_ENTDAA, 205 + I3C_INTERNAL_STATE_CONTROLLER_SETDASA, 206 + I3C_INTERNAL_STATE_CONTROLLER_WRITE, 207 + I3C_INTERNAL_STATE_CONTROLLER_READ, 208 + I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE, 209 + I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ, 210 + }; 211 + 212 + enum renesas_i3c_event { 213 + I3C_COMMAND_ADDRESS_ASSIGNMENT, 214 + I3C_WRITE, 215 + I3C_READ, 216 + I3C_COMMAND_WRITE, 217 + I3C_COMMAND_READ, 218 + }; 219 + 220 + struct renesas_i3c_cmd { 221 + u32 cmd0; 222 + u32 len; 223 + const void *tx_buf; 224 + u32 tx_count; 225 + void *rx_buf; 226 + u32 rx_count; 227 + u32 err; 228 + u8 rnw; 229 + /* i2c xfer */ 230 + int i2c_bytes_left; 231 + int i2c_is_last; 232 + u8 *i2c_buf; 233 + const struct i2c_msg *msg; 234 + }; 235 + 236 + struct renesas_i3c_xfer { 237 + struct list_head node; 238 + struct completion comp; 239 + int ret; 240 + bool is_i2c_xfer; 241 + unsigned int ncmds; 242 + struct renesas_i3c_cmd cmds[] __counted_by(ncmds); 243 + }; 244 + 245 + struct renesas_i3c_xferqueue { 246 + struct list_head list; 247 + struct renesas_i3c_xfer *cur; 248 + /* Lock for accessing the xfer queue */ 249 + spinlock_t lock; 250 + }; 251 + 252 + struct renesas_i3c { 253 + struct i3c_master_controller base; 254 + enum i3c_internal_state internal_state; 255 + u16 maxdevs; 256 + u32 free_pos; 257 + u32 i2c_STDBR; 258 + u32 i3c_STDBR; 259 + u8 addrs[RENESAS_I3C_MAX_DEVS]; 260 + struct renesas_i3c_xferqueue xferqueue; 261 + void __iomem *regs; 262 + struct clk *tclk; 263 + }; 264 + 265 + struct renesas_i3c_i2c_dev_data { 266 + u8 index; 267 + }; 268 + 269 + struct renesas_i3c_irq_desc { 270 + const char *name; 271 + irq_handler_t isr; 272 + const char *desc; 273 + }; 274 + 275 + struct renesas_i3c_config { 276 + unsigned int has_pclkrw:1; 277 + }; 278 + 279 + static inline void renesas_i3c_reg_update(void __iomem *reg, u32 mask, u32 val) 280 + { 281 + u32 data = readl(reg); 282 + 283 + data &= ~mask; 284 + data |= (val & mask); 285 + writel(data, reg); 286 + } 287 + 288 + static inline u32 renesas_readl(void __iomem *base, u32 reg) 289 + { 290 + return readl(base + reg); 291 + } 292 + 293 + static inline void renesas_writel(void __iomem *base, u32 reg, u32 val) 294 + { 295 + writel(val, base + reg); 296 + } 297 + 298 + static void renesas_set_bit(void __iomem *base, u32 reg, u32 val) 299 + { 300 + renesas_i3c_reg_update(base + reg, val, val); 301 + } 302 + 303 + static void renesas_clear_bit(void __iomem *base, u32 reg, u32 val) 304 + { 305 + renesas_i3c_reg_update(base + reg, val, 0); 306 + } 307 + 308 + static inline struct renesas_i3c *to_renesas_i3c(struct i3c_master_controller *m) 309 + { 310 + return container_of(m, struct renesas_i3c, base); 311 + } 312 + 313 + static inline u32 datbas_dvdyad_with_parity(u8 addr) 314 + { 315 + return DATBAS_DVDYAD(addr | (parity8(addr) ? 0 : BIT(7))); 316 + } 317 + 318 + static int renesas_i3c_get_free_pos(struct renesas_i3c *i3c) 319 + { 320 + if (!(i3c->free_pos & GENMASK(i3c->maxdevs - 1, 0))) 321 + return -ENOSPC; 322 + 323 + return ffs(i3c->free_pos) - 1; 324 + } 325 + 326 + static int renesas_i3c_get_addr_pos(struct renesas_i3c *i3c, u8 addr) 327 + { 328 + int pos; 329 + 330 + for (pos = 0; pos < i3c->maxdevs; pos++) { 331 + if (addr == i3c->addrs[pos]) 332 + return pos; 333 + } 334 + 335 + return -EINVAL; 336 + } 337 + 338 + static struct renesas_i3c_xfer *renesas_i3c_alloc_xfer(struct renesas_i3c *i3c, 339 + unsigned int ncmds) 340 + { 341 + struct renesas_i3c_xfer *xfer; 342 + 343 + xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL); 344 + if (!xfer) 345 + return NULL; 346 + 347 + INIT_LIST_HEAD(&xfer->node); 348 + xfer->ncmds = ncmds; 349 + xfer->ret = -ETIMEDOUT; 350 + 351 + return xfer; 352 + } 353 + 354 + static void renesas_i3c_start_xfer_locked(struct renesas_i3c *i3c) 355 + { 356 + struct renesas_i3c_xfer *xfer = i3c->xferqueue.cur; 357 + struct renesas_i3c_cmd *cmd; 358 + u32 cmd1; 359 + 360 + if (!xfer) 361 + return; 362 + 363 + cmd = xfer->cmds; 364 + 365 + switch (i3c->internal_state) { 366 + case I3C_INTERNAL_STATE_CONTROLLER_ENTDAA: 367 + case I3C_INTERNAL_STATE_CONTROLLER_SETDASA: 368 + renesas_set_bit(i3c->regs, NTIE, NTIE_RSPQFIE); 369 + renesas_writel(i3c->regs, NCMDQP, cmd->cmd0); 370 + renesas_writel(i3c->regs, NCMDQP, 0); 371 + break; 372 + case I3C_INTERNAL_STATE_CONTROLLER_WRITE: 373 + case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE: 374 + renesas_set_bit(i3c->regs, NTIE, NTIE_RSPQFIE); 375 + if (cmd->len <= 4) { 376 + cmd->cmd0 |= NCMDQP_CMD_ATTR(NCMDQP_IMMED_XFER); 377 + cmd->cmd0 |= NCMDQP_BYTE_CNT(cmd->len); 378 + cmd->tx_count = cmd->len; 379 + cmd1 = cmd->len == 0 ? 0 : *(u32 *)cmd->tx_buf; 380 + } else { 381 + cmd1 = NCMDQP_DATA_LENGTH(cmd->len); 382 + } 383 + renesas_writel(i3c->regs, NCMDQP, cmd->cmd0); 384 + renesas_writel(i3c->regs, NCMDQP, cmd1); 385 + break; 386 + case I3C_INTERNAL_STATE_CONTROLLER_READ: 387 + case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ: 388 + renesas_set_bit(i3c->regs, NTIE, NTIE_RDBFIE0); 389 + cmd1 = NCMDQP_DATA_LENGTH(cmd->len); 390 + renesas_writel(i3c->regs, NCMDQP, cmd->cmd0); 391 + renesas_writel(i3c->regs, NCMDQP, cmd1); 392 + break; 393 + default: 394 + break; 395 + } 396 + 397 + /* Clear the command queue empty flag */ 398 + renesas_clear_bit(i3c->regs, NTST, NTST_CMDQEF); 399 + } 400 + 401 + static void renesas_i3c_dequeue_xfer_locked(struct renesas_i3c *i3c, 402 + struct renesas_i3c_xfer *xfer) 403 + { 404 + if (i3c->xferqueue.cur == xfer) 405 + i3c->xferqueue.cur = NULL; 406 + else 407 + list_del_init(&xfer->node); 408 + } 409 + 410 + static void renesas_i3c_dequeue_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer) 411 + { 412 + scoped_guard(spinlock_irqsave, &i3c->xferqueue.lock) 413 + renesas_i3c_dequeue_xfer_locked(i3c, xfer); 414 + } 415 + 416 + static void renesas_i3c_enqueue_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer) 417 + { 418 + reinit_completion(&xfer->comp); 419 + scoped_guard(spinlock_irqsave, &i3c->xferqueue.lock) { 420 + if (i3c->xferqueue.cur) { 421 + list_add_tail(&xfer->node, &i3c->xferqueue.list); 422 + } else { 423 + i3c->xferqueue.cur = xfer; 424 + if (!xfer->is_i2c_xfer) 425 + renesas_i3c_start_xfer_locked(i3c); 426 + } 427 + } 428 + } 429 + 430 + static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer) 431 + { 432 + unsigned long time_left; 433 + 434 + renesas_i3c_enqueue_xfer(i3c, xfer); 435 + 436 + time_left = wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)); 437 + if (!time_left) 438 + renesas_i3c_dequeue_xfer(i3c, xfer); 439 + } 440 + 441 + static void renesas_i3c_set_prts(struct renesas_i3c *i3c, u32 val) 442 + { 443 + /* Required sequence according to tnrza0140ae */ 444 + renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_INTLRST); 445 + renesas_writel(i3c->regs, PRTS, val); 446 + renesas_clear_bit(i3c->regs, RSTCTL, RSTCTL_INTLRST); 447 + } 448 + 449 + static void renesas_i3c_bus_enable(struct i3c_master_controller *m, bool i3c_mode) 450 + { 451 + struct renesas_i3c *i3c = to_renesas_i3c(m); 452 + 453 + /* Setup either I3C or I2C protocol */ 454 + if (i3c_mode) { 455 + renesas_i3c_set_prts(i3c, 0); 456 + /* Revisit: INCBA handling, especially after I2C transfers */ 457 + renesas_set_bit(i3c->regs, BCTL, BCTL_HJACKCTL | BCTL_INCBA); 458 + renesas_set_bit(i3c->regs, MSDVAD, MSDVAD_MDYADV); 459 + renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR); 460 + } else { 461 + renesas_i3c_set_prts(i3c, PRTS_PRTMD); 462 + renesas_writel(i3c->regs, STDBR, i3c->i2c_STDBR); 463 + } 464 + 465 + /* Enable I3C bus */ 466 + renesas_set_bit(i3c->regs, BCTL, BCTL_BUSE); 467 + } 468 + 469 + static int renesas_i3c_reset(struct renesas_i3c *i3c) 470 + { 471 + u32 val; 472 + 473 + renesas_writel(i3c->regs, BCTL, 0); 474 + renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_RI3CRST); 475 + 476 + return read_poll_timeout(renesas_readl, val, !(val & RSTCTL_RI3CRST), 477 + 0, 1000, false, i3c->regs, RSTCTL); 478 + } 479 + 480 + static int renesas_i3c_bus_init(struct i3c_master_controller *m) 481 + { 482 + struct renesas_i3c *i3c = to_renesas_i3c(m); 483 + struct i3c_bus *bus = i3c_master_get_bus(m); 484 + struct i3c_device_info info = {}; 485 + struct i2c_timings t; 486 + unsigned long rate; 487 + u32 double_SBR, val; 488 + int cks, pp_high_ticks, pp_low_ticks, i3c_total_ticks; 489 + int od_high_ticks, od_low_ticks, i2c_total_ticks; 490 + int ret; 491 + 492 + rate = clk_get_rate(i3c->tclk); 493 + if (!rate) 494 + return -EINVAL; 495 + 496 + ret = renesas_i3c_reset(i3c); 497 + if (ret) 498 + return ret; 499 + 500 + i2c_total_ticks = DIV_ROUND_UP(rate, bus->scl_rate.i2c); 501 + i3c_total_ticks = DIV_ROUND_UP(rate, bus->scl_rate.i3c); 502 + 503 + i2c_parse_fw_timings(&m->dev, &t, true); 504 + 505 + for (cks = 0; cks < 7; cks++) { 506 + /* SCL low-period calculation in Open-drain mode */ 507 + od_low_ticks = ((i2c_total_ticks * 6) / 10); 508 + 509 + /* SCL clock calculation in Push-Pull mode */ 510 + if (bus->mode == I3C_BUS_MODE_PURE) 511 + pp_high_ticks = ((i3c_total_ticks * 5) / 10); 512 + else 513 + pp_high_ticks = DIV_ROUND_UP(I3C_BUS_THIGH_MIXED_MAX_NS, 514 + NSEC_PER_SEC / rate); 515 + pp_low_ticks = i3c_total_ticks - pp_high_ticks; 516 + 517 + if ((od_low_ticks / 2) <= 0xFF && pp_low_ticks < 0x3F) 518 + break; 519 + 520 + i2c_total_ticks /= 2; 521 + i3c_total_ticks /= 2; 522 + rate /= 2; 523 + } 524 + 525 + /* SCL clock period calculation in Open-drain mode */ 526 + if ((od_low_ticks / 2) > 0xFF || pp_low_ticks > 0x3F) { 527 + dev_err(&m->dev, "invalid speed (i2c-scl = %lu Hz, i3c-scl = %lu Hz). Too slow.\n", 528 + (unsigned long)bus->scl_rate.i2c, (unsigned long)bus->scl_rate.i3c); 529 + return -EINVAL; 530 + } 531 + 532 + /* SCL high-period calculation in Open-drain mode */ 533 + od_high_ticks = i2c_total_ticks - od_low_ticks; 534 + 535 + /* Standard Bit Rate setting */ 536 + double_SBR = od_low_ticks > 0xFF ? 1 : 0; 537 + i3c->i3c_STDBR = (double_SBR ? STDBR_DSBRPO : 0) | 538 + STDBR_SBRLO(double_SBR, od_low_ticks) | 539 + STDBR_SBRHO(double_SBR, od_high_ticks) | 540 + STDBR_SBRLP(pp_low_ticks) | 541 + STDBR_SBRHP(pp_high_ticks); 542 + 543 + od_low_ticks -= t.scl_fall_ns / (NSEC_PER_SEC / rate) + 1; 544 + od_high_ticks -= t.scl_rise_ns / (NSEC_PER_SEC / rate) + 1; 545 + i3c->i2c_STDBR = (double_SBR ? STDBR_DSBRPO : 0) | 546 + STDBR_SBRLO(double_SBR, od_low_ticks) | 547 + STDBR_SBRHO(double_SBR, od_high_ticks) | 548 + STDBR_SBRLP(pp_low_ticks) | 549 + STDBR_SBRHP(pp_high_ticks); 550 + renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR); 551 + 552 + /* Extended Bit Rate setting */ 553 + renesas_writel(i3c->regs, EXTBR, EXTBR_EBRLO(od_low_ticks) | 554 + EXTBR_EBRHO(od_high_ticks) | 555 + EXTBR_EBRLP(pp_low_ticks) | 556 + EXTBR_EBRHP(pp_high_ticks)); 557 + 558 + renesas_writel(i3c->regs, REFCKCTL, REFCKCTL_IREFCKS(cks)); 559 + 560 + /* Disable Slave Mode */ 561 + renesas_writel(i3c->regs, SVCTL, 0); 562 + 563 + /* Initialize Queue/Buffer threshold */ 564 + renesas_writel(i3c->regs, NQTHCTL, NQTHCTL_IBIDSSZ(6) | 565 + NQTHCTL_CMDQTH(1)); 566 + 567 + /* The only supported configuration is two entries*/ 568 + renesas_writel(i3c->regs, NTBTHCTL0, 0); 569 + /* Interrupt when there is one entry in the queue */ 570 + renesas_writel(i3c->regs, NRQTHCTL, 0); 571 + 572 + /* Enable all Bus/Transfer Status Flags */ 573 + renesas_writel(i3c->regs, BSTE, BSTE_ALL_FLAG); 574 + renesas_writel(i3c->regs, NTSTE, NTSTE_ALL_FLAG); 575 + 576 + /* Interrupt enable settings */ 577 + renesas_writel(i3c->regs, BIE, BIE_NACKDIE | BIE_TENDIE); 578 + renesas_writel(i3c->regs, NTIE, 0); 579 + 580 + /* Clear Status register */ 581 + renesas_writel(i3c->regs, NTST, 0); 582 + renesas_writel(i3c->regs, INST, 0); 583 + renesas_writel(i3c->regs, BST, 0); 584 + 585 + /* Hot-Join Acknowlege setting. */ 586 + renesas_set_bit(i3c->regs, BCTL, BCTL_HJACKCTL); 587 + 588 + renesas_writel(i3c->regs, IBINCTL, IBINCTL_NRHJCTL | IBINCTL_NRMRCTL | 589 + IBINCTL_NRSIRCTL); 590 + 591 + renesas_writel(i3c->regs, SCSTLCTL, 0); 592 + renesas_set_bit(i3c->regs, SCSTRCTL, SCSTRCTL_ACKTWE); 593 + 594 + /* Bus condition timing */ 595 + val = DIV_ROUND_UP(I3C_BUS_TBUF_MIXED_FM_MIN_NS, NSEC_PER_SEC / rate); 596 + renesas_writel(i3c->regs, BFRECDT, BFRECDT_FRECYC(val)); 597 + 598 + val = DIV_ROUND_UP(I3C_BUS_TAVAL_MIN_NS, NSEC_PER_SEC / rate); 599 + renesas_writel(i3c->regs, BAVLCDT, BAVLCDT_AVLCYC(val)); 600 + 601 + val = DIV_ROUND_UP(I3C_BUS_TIDLE_MIN_NS, NSEC_PER_SEC / rate); 602 + renesas_writel(i3c->regs, BIDLCDT, BIDLCDT_IDLCYC(val)); 603 + 604 + ret = i3c_master_get_free_addr(m, 0); 605 + if (ret < 0) 606 + return ret; 607 + 608 + renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYAD(ret) | MSDVAD_MDYADV); 609 + 610 + memset(&info, 0, sizeof(info)); 611 + info.dyn_addr = ret; 612 + return i3c_master_set_info(&i3c->base, &info); 613 + } 614 + 615 + static void renesas_i3c_bus_cleanup(struct i3c_master_controller *m) 616 + { 617 + struct renesas_i3c *i3c = to_renesas_i3c(m); 618 + 619 + renesas_i3c_reset(i3c); 620 + } 621 + 622 + static int renesas_i3c_daa(struct i3c_master_controller *m) 623 + { 624 + struct renesas_i3c *i3c = to_renesas_i3c(m); 625 + struct renesas_i3c_cmd *cmd; 626 + u32 olddevs, newdevs; 627 + u8 last_addr = 0, pos; 628 + int ret; 629 + 630 + struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1); 631 + if (!xfer) 632 + return -ENOMEM; 633 + 634 + /* Enable I3C bus. */ 635 + renesas_i3c_bus_enable(m, true); 636 + 637 + olddevs = ~(i3c->free_pos); 638 + i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_ENTDAA; 639 + 640 + /* Setting DATBASn registers for target devices. */ 641 + for (pos = 0; pos < i3c->maxdevs; pos++) { 642 + if (olddevs & BIT(pos)) 643 + continue; 644 + 645 + ret = i3c_master_get_free_addr(m, last_addr + 1); 646 + if (ret < 0) 647 + return -ENOSPC; 648 + 649 + i3c->addrs[pos] = ret; 650 + last_addr = ret; 651 + 652 + renesas_writel(i3c->regs, DATBAS(pos), datbas_dvdyad_with_parity(ret)); 653 + } 654 + 655 + init_completion(&xfer->comp); 656 + cmd = xfer->cmds; 657 + cmd->rx_count = 0; 658 + 659 + ret = renesas_i3c_get_free_pos(i3c); 660 + if (ret < 0) 661 + return ret; 662 + 663 + /* 664 + * Setup the command descriptor to start the ENTDAA command 665 + * and starting at the selected device index. 666 + */ 667 + cmd->cmd0 = NCMDQP_CMD_ATTR(NCMDQP_ADDR_ASSGN) | NCMDQP_ROC | 668 + NCMDQP_TID(I3C_COMMAND_ADDRESS_ASSIGNMENT) | 669 + NCMDQP_CMD(I3C_CCC_ENTDAA) | NCMDQP_DEV_INDEX(ret) | 670 + NCMDQP_DEV_COUNT(i3c->maxdevs - ret) | NCMDQP_TOC; 671 + 672 + renesas_i3c_wait_xfer(i3c, xfer); 673 + 674 + newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0); 675 + newdevs &= ~olddevs; 676 + 677 + for (pos = 0; pos < i3c->maxdevs; pos++) { 678 + if (newdevs & BIT(pos)) 679 + i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos]); 680 + } 681 + 682 + return ret < 0 ? ret : 0; 683 + } 684 + 685 + static bool renesas_i3c_supports_ccc_cmd(struct i3c_master_controller *m, 686 + const struct i3c_ccc_cmd *cmd) 687 + { 688 + if (cmd->ndests > 1) 689 + return false; 690 + 691 + switch (cmd->id) { 692 + case I3C_CCC_ENEC(true): 693 + case I3C_CCC_ENEC(false): 694 + case I3C_CCC_DISEC(true): 695 + case I3C_CCC_DISEC(false): 696 + case I3C_CCC_ENTAS(0, true): 697 + case I3C_CCC_ENTAS(1, true): 698 + case I3C_CCC_ENTAS(2, true): 699 + case I3C_CCC_ENTAS(3, true): 700 + case I3C_CCC_ENTAS(0, false): 701 + case I3C_CCC_ENTAS(1, false): 702 + case I3C_CCC_ENTAS(2, false): 703 + case I3C_CCC_ENTAS(3, false): 704 + case I3C_CCC_RSTDAA(true): 705 + case I3C_CCC_RSTDAA(false): 706 + case I3C_CCC_ENTDAA: 707 + case I3C_CCC_DEFSLVS: 708 + case I3C_CCC_SETMWL(true): 709 + case I3C_CCC_SETMWL(false): 710 + case I3C_CCC_SETMRL(true): 711 + case I3C_CCC_SETMRL(false): 712 + case I3C_CCC_ENTTM: 713 + case I3C_CCC_SETDASA: 714 + case I3C_CCC_SETNEWDA: 715 + case I3C_CCC_GETMWL: 716 + case I3C_CCC_GETMRL: 717 + case I3C_CCC_GETPID: 718 + case I3C_CCC_GETBCR: 719 + case I3C_CCC_GETDCR: 720 + case I3C_CCC_GETSTATUS: 721 + case I3C_CCC_GETACCMST: 722 + case I3C_CCC_GETMXDS: 723 + return true; 724 + default: 725 + return false; 726 + } 727 + } 728 + 729 + static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m, 730 + struct i3c_ccc_cmd *ccc) 731 + { 732 + struct renesas_i3c *i3c = to_renesas_i3c(m); 733 + struct renesas_i3c_xfer *xfer; 734 + struct renesas_i3c_cmd *cmd; 735 + int ret, pos = 0; 736 + 737 + if (ccc->id & I3C_CCC_DIRECT) { 738 + pos = renesas_i3c_get_addr_pos(i3c, ccc->dests[0].addr); 739 + if (pos < 0) 740 + return pos; 741 + } 742 + 743 + xfer = renesas_i3c_alloc_xfer(i3c, 1); 744 + if (!xfer) 745 + return -ENOMEM; 746 + 747 + renesas_i3c_bus_enable(m, true); 748 + 749 + init_completion(&xfer->comp); 750 + cmd = xfer->cmds; 751 + cmd->rnw = ccc->rnw; 752 + cmd->cmd0 = 0; 753 + 754 + /* Calculate the command descriptor. */ 755 + switch (ccc->id) { 756 + case I3C_CCC_SETDASA: 757 + renesas_writel(i3c->regs, DATBAS(pos), 758 + DATBAS_DVSTAD(ccc->dests[0].addr) | 759 + DATBAS_DVDYAD(*(u8 *)ccc->dests[0].payload.data >> 1)); 760 + cmd->cmd0 = NCMDQP_CMD_ATTR(NCMDQP_ADDR_ASSGN) | NCMDQP_ROC | 761 + NCMDQP_TID(I3C_COMMAND_ADDRESS_ASSIGNMENT) | 762 + NCMDQP_CMD(I3C_CCC_SETDASA) | NCMDQP_DEV_INDEX(pos) | 763 + NCMDQP_DEV_COUNT(0) | NCMDQP_TOC; 764 + i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_SETDASA; 765 + break; 766 + default: 767 + /* Calculate the command descriptor. */ 768 + cmd->cmd0 = NCMDQP_TID(I3C_COMMAND_WRITE) | NCMDQP_MODE(0) | 769 + NCMDQP_RNW(ccc->rnw) | NCMDQP_CMD(ccc->id) | 770 + NCMDQP_ROC | NCMDQP_TOC | NCMDQP_CP | 771 + NCMDQP_DEV_INDEX(pos); 772 + 773 + if (ccc->rnw) { 774 + cmd->rx_buf = ccc->dests[0].payload.data; 775 + cmd->len = ccc->dests[0].payload.len; 776 + cmd->rx_count = 0; 777 + i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ; 778 + } else { 779 + cmd->tx_buf = ccc->dests[0].payload.data; 780 + cmd->len = ccc->dests[0].payload.len; 781 + cmd->tx_count = 0; 782 + i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE; 783 + } 784 + } 785 + 786 + renesas_i3c_wait_xfer(i3c, xfer); 787 + 788 + ret = xfer->ret; 789 + if (ret) 790 + ccc->err = I3C_ERROR_M2; 791 + 792 + kfree(xfer); 793 + 794 + return ret; 795 + } 796 + 797 + static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer *i3c_xfers, 798 + int i3c_nxfers) 799 + { 800 + struct i3c_master_controller *m = i3c_dev_get_master(dev); 801 + struct renesas_i3c *i3c = to_renesas_i3c(m); 802 + struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 803 + struct renesas_i3c_xfer *xfer; 804 + int i; 805 + 806 + /* Enable I3C bus. */ 807 + renesas_i3c_bus_enable(m, true); 808 + 809 + xfer = renesas_i3c_alloc_xfer(i3c, 1); 810 + if (!xfer) 811 + return -ENOMEM; 812 + 813 + init_completion(&xfer->comp); 814 + 815 + for (i = 0; i < i3c_nxfers; i++) { 816 + struct renesas_i3c_cmd *cmd = xfer->cmds; 817 + 818 + /* Calculate the Transfer Command Descriptor */ 819 + cmd->rnw = i3c_xfers[i].rnw; 820 + cmd->cmd0 = NCMDQP_DEV_INDEX(data->index) | NCMDQP_MODE(0) | 821 + NCMDQP_RNW(cmd->rnw) | NCMDQP_ROC | NCMDQP_TOC; 822 + 823 + if (i3c_xfers[i].rnw) { 824 + cmd->rx_count = 0; 825 + cmd->cmd0 |= NCMDQP_TID(I3C_READ); 826 + cmd->rx_buf = i3c_xfers[i].data.in; 827 + cmd->len = i3c_xfers[i].len; 828 + i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_READ; 829 + } else { 830 + cmd->tx_count = 0; 831 + cmd->cmd0 |= NCMDQP_TID(I3C_WRITE); 832 + cmd->tx_buf = i3c_xfers[i].data.out; 833 + cmd->len = i3c_xfers[i].len; 834 + i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_WRITE; 835 + } 836 + 837 + if (!i3c_xfers[i].rnw && i3c_xfers[i].len > 4) { 838 + i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len); 839 + if (cmd->len > NTDTBP0_DEPTH * sizeof(u32)) 840 + renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0); 841 + } 842 + 843 + renesas_i3c_wait_xfer(i3c, xfer); 844 + } 845 + 846 + return 0; 847 + } 848 + 849 + static int renesas_i3c_attach_i3c_dev(struct i3c_dev_desc *dev) 850 + { 851 + struct i3c_master_controller *m = i3c_dev_get_master(dev); 852 + struct renesas_i3c *i3c = to_renesas_i3c(m); 853 + struct renesas_i3c_i2c_dev_data *data; 854 + int pos; 855 + 856 + pos = renesas_i3c_get_free_pos(i3c); 857 + if (pos < 0) 858 + return pos; 859 + 860 + data = kzalloc(sizeof(*data), GFP_KERNEL); 861 + if (!data) 862 + return -ENOMEM; 863 + 864 + data->index = pos; 865 + i3c->addrs[pos] = dev->info.dyn_addr ? : dev->info.static_addr; 866 + i3c->free_pos &= ~BIT(pos); 867 + 868 + renesas_writel(i3c->regs, DATBAS(pos), DATBAS_DVSTAD(dev->info.static_addr) | 869 + datbas_dvdyad_with_parity(i3c->addrs[pos])); 870 + i3c_dev_set_master_data(dev, data); 871 + 872 + return 0; 873 + } 874 + 875 + static int renesas_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev, 876 + u8 old_dyn_addr) 877 + { 878 + struct i3c_master_controller *m = i3c_dev_get_master(dev); 879 + struct renesas_i3c *i3c = to_renesas_i3c(m); 880 + struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 881 + 882 + i3c->addrs[data->index] = dev->info.dyn_addr ? dev->info.dyn_addr : 883 + dev->info.static_addr; 884 + 885 + return 0; 886 + } 887 + 888 + static void renesas_i3c_detach_i3c_dev(struct i3c_dev_desc *dev) 889 + { 890 + struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); 891 + struct i3c_master_controller *m = i3c_dev_get_master(dev); 892 + struct renesas_i3c *i3c = to_renesas_i3c(m); 893 + 894 + i3c_dev_set_master_data(dev, NULL); 895 + i3c->addrs[data->index] = 0; 896 + i3c->free_pos |= BIT(data->index); 897 + kfree(data); 898 + } 899 + 900 + static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev, 901 + struct i2c_msg *i2c_xfers, 902 + int i2c_nxfers) 903 + { 904 + struct i3c_master_controller *m = i2c_dev_get_master(dev); 905 + struct renesas_i3c *i3c = to_renesas_i3c(m); 906 + struct renesas_i3c_cmd *cmd; 907 + u8 start_bit = CNDCTL_STCND; 908 + int i; 909 + 910 + struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1); 911 + if (!xfer) 912 + return -ENOMEM; 913 + 914 + if (!i2c_nxfers) 915 + return 0; 916 + 917 + renesas_i3c_bus_enable(m, false); 918 + 919 + init_completion(&xfer->comp); 920 + xfer->is_i2c_xfer = true; 921 + cmd = xfer->cmds; 922 + 923 + if (!(renesas_readl(i3c->regs, BCST) & BCST_BFREF)) { 924 + cmd->err = -EBUSY; 925 + return cmd->err; 926 + } 927 + 928 + renesas_writel(i3c->regs, BST, 0); 929 + 930 + renesas_i3c_enqueue_xfer(i3c, xfer); 931 + 932 + for (i = 0; i < i2c_nxfers; i++) { 933 + cmd->i2c_bytes_left = I2C_INIT_MSG; 934 + cmd->i2c_buf = i2c_xfers[i].buf; 935 + cmd->msg = &i2c_xfers[i]; 936 + cmd->i2c_is_last = (i == i2c_nxfers - 1); 937 + 938 + renesas_set_bit(i3c->regs, BIE, BIE_NACKDIE); 939 + renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0); 940 + renesas_set_bit(i3c->regs, BIE, BIE_STCNDDIE); 941 + 942 + /* Issue Start condition */ 943 + renesas_set_bit(i3c->regs, CNDCTL, start_bit); 944 + 945 + renesas_set_bit(i3c->regs, NTSTE, NTSTE_TDBEE0); 946 + 947 + wait_for_completion_timeout(&xfer->comp, m->i2c.timeout); 948 + 949 + if (cmd->err) 950 + break; 951 + 952 + start_bit = CNDCTL_SRCND; 953 + } 954 + 955 + renesas_i3c_dequeue_xfer(i3c, xfer); 956 + return cmd->err; 957 + } 958 + 959 + static int renesas_i3c_attach_i2c_dev(struct i2c_dev_desc *dev) 960 + { 961 + struct i3c_master_controller *m = i2c_dev_get_master(dev); 962 + struct renesas_i3c *i3c = to_renesas_i3c(m); 963 + struct renesas_i3c_i2c_dev_data *data; 964 + int pos; 965 + 966 + pos = renesas_i3c_get_free_pos(i3c); 967 + if (pos < 0) 968 + return pos; 969 + 970 + data = kzalloc(sizeof(*data), GFP_KERNEL); 971 + if (!data) 972 + return -ENOMEM; 973 + 974 + data->index = pos; 975 + i3c->addrs[pos] = dev->addr; 976 + i3c->free_pos &= ~BIT(pos); 977 + i2c_dev_set_master_data(dev, data); 978 + 979 + return 0; 980 + } 981 + 982 + static void renesas_i3c_detach_i2c_dev(struct i2c_dev_desc *dev) 983 + { 984 + struct renesas_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); 985 + struct i3c_master_controller *m = i2c_dev_get_master(dev); 986 + struct renesas_i3c *i3c = to_renesas_i3c(m); 987 + 988 + i2c_dev_set_master_data(dev, NULL); 989 + i3c->addrs[data->index] = 0; 990 + i3c->free_pos |= BIT(data->index); 991 + kfree(data); 992 + } 993 + 994 + static irqreturn_t renesas_i3c_tx_isr(int irq, void *data) 995 + { 996 + struct renesas_i3c *i3c = data; 997 + struct renesas_i3c_xfer *xfer; 998 + struct renesas_i3c_cmd *cmd; 999 + u8 val; 1000 + 1001 + scoped_guard(spinlock, &i3c->xferqueue.lock) { 1002 + xfer = i3c->xferqueue.cur; 1003 + cmd = xfer->cmds; 1004 + 1005 + if (xfer->is_i2c_xfer) { 1006 + if (!cmd->i2c_bytes_left) 1007 + return IRQ_NONE; 1008 + 1009 + if (cmd->i2c_bytes_left != I2C_INIT_MSG) { 1010 + val = *cmd->i2c_buf; 1011 + cmd->i2c_buf++; 1012 + cmd->i2c_bytes_left--; 1013 + renesas_writel(i3c->regs, NTDTBP0, val); 1014 + } 1015 + 1016 + if (cmd->i2c_bytes_left == 0) { 1017 + renesas_clear_bit(i3c->regs, NTIE, NTIE_TDBEIE0); 1018 + renesas_set_bit(i3c->regs, BIE, BIE_TENDIE); 1019 + } 1020 + 1021 + /* Clear the Transmit Buffer Empty status flag. */ 1022 + renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0); 1023 + } else { 1024 + i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len); 1025 + } 1026 + } 1027 + 1028 + return IRQ_HANDLED; 1029 + } 1030 + 1031 + static irqreturn_t renesas_i3c_resp_isr(int irq, void *data) 1032 + { 1033 + struct renesas_i3c *i3c = data; 1034 + struct renesas_i3c_xfer *xfer; 1035 + struct renesas_i3c_cmd *cmd; 1036 + u32 resp_descriptor = renesas_readl(i3c->regs, NRSPQP); 1037 + u32 bytes_remaining = 0; 1038 + u32 ntst, data_len; 1039 + int ret = 0; 1040 + 1041 + scoped_guard(spinlock, &i3c->xferqueue.lock) { 1042 + xfer = i3c->xferqueue.cur; 1043 + cmd = xfer->cmds; 1044 + 1045 + /* Clear the Respone Queue Full status flag*/ 1046 + renesas_clear_bit(i3c->regs, NTST, NTST_RSPQFF); 1047 + 1048 + data_len = NRSPQP_DATA_LEN(resp_descriptor); 1049 + 1050 + switch (i3c->internal_state) { 1051 + case I3C_INTERNAL_STATE_CONTROLLER_ENTDAA: 1052 + cmd->rx_count = data_len; 1053 + break; 1054 + case I3C_INTERNAL_STATE_CONTROLLER_WRITE: 1055 + case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE: 1056 + /* Disable the transmit IRQ if it hasn't been disabled already. */ 1057 + renesas_clear_bit(i3c->regs, NTIE, NTIE_TDBEIE0); 1058 + break; 1059 + case I3C_INTERNAL_STATE_CONTROLLER_READ: 1060 + case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ: 1061 + if (NDBSTLV0_RDBLV(renesas_readl(i3c->regs, NDBSTLV0)) && !cmd->err) 1062 + bytes_remaining = data_len - cmd->rx_count; 1063 + 1064 + i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, bytes_remaining); 1065 + renesas_clear_bit(i3c->regs, NTIE, NTIE_RDBFIE0); 1066 + break; 1067 + default: 1068 + break; 1069 + } 1070 + 1071 + switch (NRSPQP_ERR_STATUS(resp_descriptor)) { 1072 + case NRSPQP_NO_ERROR: 1073 + break; 1074 + case NRSPQP_ERROR_PARITY: 1075 + case NRSPQP_ERROR_IBA_NACK: 1076 + case NRSPQP_ERROR_TRANSF_ABORT: 1077 + case NRSPQP_ERROR_CRC: 1078 + case NRSPQP_ERROR_FRAME: 1079 + ret = -EIO; 1080 + break; 1081 + case NRSPQP_ERROR_OVER_UNDER_FLOW: 1082 + ret = -ENOSPC; 1083 + break; 1084 + case NRSPQP_ERROR_UNSUPPORTED: 1085 + ret = -EOPNOTSUPP; 1086 + break; 1087 + case NRSPQP_ERROR_I2C_W_NACK_ERR: 1088 + case NRSPQP_ERROR_ADDRESS_NACK: 1089 + default: 1090 + ret = -EINVAL; 1091 + break; 1092 + } 1093 + 1094 + /* 1095 + * If the transfer was aborted, then the abort flag must be cleared 1096 + * before notifying the application that a transfer has completed. 1097 + */ 1098 + ntst = renesas_readl(i3c->regs, NTST); 1099 + if (ntst & NTST_TABTF) 1100 + renesas_clear_bit(i3c->regs, BCTL, BCTL_ABT); 1101 + 1102 + /* Clear error status flags. */ 1103 + renesas_clear_bit(i3c->regs, NTST, NTST_TEF | NTST_TABTF); 1104 + 1105 + xfer->ret = ret; 1106 + complete(&xfer->comp); 1107 + 1108 + xfer = list_first_entry_or_null(&i3c->xferqueue.list, 1109 + struct renesas_i3c_xfer, node); 1110 + if (xfer) 1111 + list_del_init(&xfer->node); 1112 + 1113 + i3c->xferqueue.cur = xfer; 1114 + } 1115 + 1116 + return IRQ_HANDLED; 1117 + } 1118 + 1119 + static irqreturn_t renesas_i3c_tend_isr(int irq, void *data) 1120 + { 1121 + struct renesas_i3c *i3c = data; 1122 + struct renesas_i3c_xfer *xfer; 1123 + struct renesas_i3c_cmd *cmd; 1124 + 1125 + scoped_guard(spinlock, &i3c->xferqueue.lock) { 1126 + xfer = i3c->xferqueue.cur; 1127 + cmd = xfer->cmds; 1128 + 1129 + if (xfer->is_i2c_xfer) { 1130 + if (renesas_readl(i3c->regs, BST) & BST_NACKDF) { 1131 + /* We got a NACKIE */ 1132 + renesas_readl(i3c->regs, NTDTBP0); /* dummy read */ 1133 + renesas_clear_bit(i3c->regs, BST, BST_NACKDF); 1134 + cmd->err = -ENXIO; 1135 + } else if (cmd->i2c_bytes_left) { 1136 + renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0); 1137 + return IRQ_NONE; 1138 + } 1139 + 1140 + if (cmd->i2c_is_last || cmd->err) { 1141 + renesas_clear_bit(i3c->regs, BIE, BIE_TENDIE); 1142 + renesas_set_bit(i3c->regs, BIE, BIE_SPCNDDIE); 1143 + renesas_set_bit(i3c->regs, CNDCTL, CNDCTL_SPCND); 1144 + } else { 1145 + /* Transfer is complete, but do not send STOP */ 1146 + renesas_clear_bit(i3c->regs, NTSTE, NTSTE_TDBEE0); 1147 + renesas_clear_bit(i3c->regs, BIE, BIE_TENDIE); 1148 + xfer->ret = 0; 1149 + complete(&xfer->comp); 1150 + } 1151 + } 1152 + 1153 + /* Clear the Transmit Buffer Empty status flag. */ 1154 + renesas_clear_bit(i3c->regs, BST, BST_TENDF); 1155 + } 1156 + 1157 + return IRQ_HANDLED; 1158 + } 1159 + 1160 + static irqreturn_t renesas_i3c_rx_isr(int irq, void *data) 1161 + { 1162 + struct renesas_i3c *i3c = data; 1163 + struct renesas_i3c_xfer *xfer; 1164 + struct renesas_i3c_cmd *cmd; 1165 + int read_bytes; 1166 + 1167 + /* If resp_isr already read the data and updated 'xfer', we can just leave */ 1168 + if (!(renesas_readl(i3c->regs, NTIE) & NTIE_RDBFIE0)) 1169 + return IRQ_NONE; 1170 + 1171 + scoped_guard(spinlock, &i3c->xferqueue.lock) { 1172 + xfer = i3c->xferqueue.cur; 1173 + cmd = xfer->cmds; 1174 + 1175 + if (xfer->is_i2c_xfer) { 1176 + if (!cmd->i2c_bytes_left) 1177 + return IRQ_NONE; 1178 + 1179 + if (cmd->i2c_bytes_left == I2C_INIT_MSG) { 1180 + cmd->i2c_bytes_left = cmd->msg->len; 1181 + renesas_set_bit(i3c->regs, SCSTRCTL, SCSTRCTL_RWE); 1182 + renesas_readl(i3c->regs, NTDTBP0); /* dummy read */ 1183 + if (cmd->i2c_bytes_left == 1) 1184 + renesas_writel(i3c->regs, ACKCTL, ACKCTL_ACKT | ACKCTL_ACKTWP); 1185 + return IRQ_HANDLED; 1186 + } 1187 + 1188 + if (cmd->i2c_bytes_left == 1) { 1189 + /* STOP must come before we set ACKCTL! */ 1190 + if (cmd->i2c_is_last) { 1191 + renesas_set_bit(i3c->regs, BIE, BIE_SPCNDDIE); 1192 + renesas_clear_bit(i3c->regs, BST, BST_SPCNDDF); 1193 + renesas_set_bit(i3c->regs, CNDCTL, CNDCTL_SPCND); 1194 + } 1195 + renesas_writel(i3c->regs, ACKCTL, ACKCTL_ACKT | ACKCTL_ACKTWP); 1196 + } else { 1197 + renesas_writel(i3c->regs, ACKCTL, ACKCTL_ACKTWP); 1198 + } 1199 + 1200 + /* Reading acks the RIE interrupt */ 1201 + *cmd->i2c_buf = renesas_readl(i3c->regs, NTDTBP0); 1202 + cmd->i2c_buf++; 1203 + cmd->i2c_bytes_left--; 1204 + } else { 1205 + read_bytes = NDBSTLV0_RDBLV(renesas_readl(i3c->regs, NDBSTLV0)) * sizeof(u32); 1206 + i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, read_bytes); 1207 + cmd->rx_count = read_bytes; 1208 + } 1209 + 1210 + /* Clear the Read Buffer Full status flag. */ 1211 + renesas_clear_bit(i3c->regs, NTST, NTST_RDBFF0); 1212 + } 1213 + 1214 + return IRQ_HANDLED; 1215 + } 1216 + 1217 + static irqreturn_t renesas_i3c_stop_isr(int irq, void *data) 1218 + { 1219 + struct renesas_i3c *i3c = data; 1220 + struct renesas_i3c_xfer *xfer; 1221 + 1222 + scoped_guard(spinlock, &i3c->xferqueue.lock) { 1223 + xfer = i3c->xferqueue.cur; 1224 + 1225 + /* read back registers to confirm writes have fully propagated */ 1226 + renesas_writel(i3c->regs, BST, 0); 1227 + renesas_readl(i3c->regs, BST); 1228 + renesas_writel(i3c->regs, BIE, 0); 1229 + renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0 | NTST_RDBFF0); 1230 + renesas_clear_bit(i3c->regs, SCSTRCTL, SCSTRCTL_RWE); 1231 + 1232 + xfer->ret = 0; 1233 + complete(&xfer->comp); 1234 + } 1235 + 1236 + return IRQ_HANDLED; 1237 + } 1238 + 1239 + static irqreturn_t renesas_i3c_start_isr(int irq, void *data) 1240 + { 1241 + struct renesas_i3c *i3c = data; 1242 + struct renesas_i3c_xfer *xfer; 1243 + struct renesas_i3c_cmd *cmd; 1244 + u8 val; 1245 + 1246 + scoped_guard(spinlock, &i3c->xferqueue.lock) { 1247 + xfer = i3c->xferqueue.cur; 1248 + cmd = xfer->cmds; 1249 + 1250 + if (xfer->is_i2c_xfer) { 1251 + if (!cmd->i2c_bytes_left) 1252 + return IRQ_NONE; 1253 + 1254 + if (cmd->i2c_bytes_left == I2C_INIT_MSG) { 1255 + if (cmd->msg->flags & I2C_M_RD) { 1256 + /* On read, switch over to receive interrupt */ 1257 + renesas_clear_bit(i3c->regs, NTIE, NTIE_TDBEIE0); 1258 + renesas_set_bit(i3c->regs, NTIE, NTIE_RDBFIE0); 1259 + } else { 1260 + /* On write, initialize length */ 1261 + cmd->i2c_bytes_left = cmd->msg->len; 1262 + } 1263 + 1264 + val = i2c_8bit_addr_from_msg(cmd->msg); 1265 + renesas_writel(i3c->regs, NTDTBP0, val); 1266 + } 1267 + } 1268 + 1269 + renesas_clear_bit(i3c->regs, BIE, BIE_STCNDDIE); 1270 + renesas_clear_bit(i3c->regs, BST, BST_STCNDDF); 1271 + } 1272 + 1273 + return IRQ_HANDLED; 1274 + } 1275 + 1276 + static const struct i3c_master_controller_ops renesas_i3c_ops = { 1277 + .bus_init = renesas_i3c_bus_init, 1278 + .bus_cleanup = renesas_i3c_bus_cleanup, 1279 + .attach_i3c_dev = renesas_i3c_attach_i3c_dev, 1280 + .reattach_i3c_dev = renesas_i3c_reattach_i3c_dev, 1281 + .detach_i3c_dev = renesas_i3c_detach_i3c_dev, 1282 + .do_daa = renesas_i3c_daa, 1283 + .supports_ccc_cmd = renesas_i3c_supports_ccc_cmd, 1284 + .send_ccc_cmd = renesas_i3c_send_ccc_cmd, 1285 + .priv_xfers = renesas_i3c_priv_xfers, 1286 + .attach_i2c_dev = renesas_i3c_attach_i2c_dev, 1287 + .detach_i2c_dev = renesas_i3c_detach_i2c_dev, 1288 + .i2c_xfers = renesas_i3c_i2c_xfers, 1289 + }; 1290 + 1291 + static const struct renesas_i3c_irq_desc renesas_i3c_irqs[] = { 1292 + { .name = "resp", .isr = renesas_i3c_resp_isr, .desc = "i3c-resp" }, 1293 + { .name = "rx", .isr = renesas_i3c_rx_isr, .desc = "i3c-rx" }, 1294 + { .name = "tx", .isr = renesas_i3c_tx_isr, .desc = "i3c-tx" }, 1295 + { .name = "st", .isr = renesas_i3c_start_isr, .desc = "i3c-start" }, 1296 + { .name = "sp", .isr = renesas_i3c_stop_isr, .desc = "i3c-stop" }, 1297 + { .name = "tend", .isr = renesas_i3c_tend_isr, .desc = "i3c-tend" }, 1298 + { .name = "nack", .isr = renesas_i3c_tend_isr, .desc = "i3c-nack" }, 1299 + }; 1300 + 1301 + static int renesas_i3c_probe(struct platform_device *pdev) 1302 + { 1303 + struct renesas_i3c *i3c; 1304 + struct reset_control *reset; 1305 + struct clk *clk; 1306 + const struct renesas_i3c_config *config = of_device_get_match_data(&pdev->dev); 1307 + int ret, i; 1308 + 1309 + if (!config) 1310 + return -ENODATA; 1311 + 1312 + i3c = devm_kzalloc(&pdev->dev, sizeof(*i3c), GFP_KERNEL); 1313 + if (!i3c) 1314 + return -ENOMEM; 1315 + 1316 + i3c->regs = devm_platform_ioremap_resource(pdev, 0); 1317 + if (IS_ERR(i3c->regs)) 1318 + return PTR_ERR(i3c->regs); 1319 + 1320 + clk = devm_clk_get_enabled(&pdev->dev, "pclk"); 1321 + if (IS_ERR(clk)) 1322 + return PTR_ERR(clk); 1323 + 1324 + if (config->has_pclkrw) { 1325 + clk = devm_clk_get_enabled(&pdev->dev, "pclkrw"); 1326 + if (IS_ERR(clk)) 1327 + return PTR_ERR(clk); 1328 + } 1329 + 1330 + i3c->tclk = devm_clk_get_enabled(&pdev->dev, "tclk"); 1331 + if (IS_ERR(i3c->tclk)) 1332 + return PTR_ERR(i3c->tclk); 1333 + 1334 + reset = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "tresetn"); 1335 + if (IS_ERR(reset)) 1336 + return dev_err_probe(&pdev->dev, PTR_ERR(reset), 1337 + "Error: missing tresetn ctrl\n"); 1338 + 1339 + reset = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "presetn"); 1340 + if (IS_ERR(reset)) 1341 + return dev_err_probe(&pdev->dev, PTR_ERR(reset), 1342 + "Error: missing presetn ctrl\n"); 1343 + 1344 + spin_lock_init(&i3c->xferqueue.lock); 1345 + INIT_LIST_HEAD(&i3c->xferqueue.list); 1346 + 1347 + ret = renesas_i3c_reset(i3c); 1348 + if (ret) 1349 + return ret; 1350 + 1351 + for (i = 0; i < ARRAY_SIZE(renesas_i3c_irqs); i++) { 1352 + ret = platform_get_irq_byname(pdev, renesas_i3c_irqs[i].name); 1353 + if (ret < 0) 1354 + return ret; 1355 + 1356 + ret = devm_request_irq(&pdev->dev, ret, renesas_i3c_irqs[i].isr, 1357 + 0, renesas_i3c_irqs[i].desc, i3c); 1358 + if (ret) 1359 + return ret; 1360 + } 1361 + 1362 + platform_set_drvdata(pdev, i3c); 1363 + 1364 + i3c->maxdevs = RENESAS_I3C_MAX_DEVS; 1365 + i3c->free_pos = GENMASK(i3c->maxdevs - 1, 0); 1366 + 1367 + return i3c_master_register(&i3c->base, &pdev->dev, &renesas_i3c_ops, false); 1368 + } 1369 + 1370 + static void renesas_i3c_remove(struct platform_device *pdev) 1371 + { 1372 + struct renesas_i3c *i3c = platform_get_drvdata(pdev); 1373 + 1374 + i3c_master_unregister(&i3c->base); 1375 + } 1376 + 1377 + static const struct renesas_i3c_config empty_i3c_config = { 1378 + }; 1379 + 1380 + static const struct renesas_i3c_config r9a09g047_i3c_config = { 1381 + .has_pclkrw = 1, 1382 + }; 1383 + 1384 + static const struct of_device_id renesas_i3c_of_ids[] = { 1385 + { .compatible = "renesas,r9a08g045-i3c", .data = &empty_i3c_config }, 1386 + { .compatible = "renesas,r9a09g047-i3c", .data = &r9a09g047_i3c_config }, 1387 + { /* sentinel */ }, 1388 + }; 1389 + MODULE_DEVICE_TABLE(of, renesas_i3c_of_ids); 1390 + 1391 + static struct platform_driver renesas_i3c = { 1392 + .probe = renesas_i3c_probe, 1393 + .remove = renesas_i3c_remove, 1394 + .driver = { 1395 + .name = "renesas-i3c", 1396 + .of_match_table = renesas_i3c_of_ids, 1397 + }, 1398 + }; 1399 + module_platform_driver(renesas_i3c); 1400 + 1401 + MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>"); 1402 + MODULE_AUTHOR("Renesas BSP teams"); 1403 + MODULE_DESCRIPTION("Renesas I3C controller driver"); 1404 + MODULE_LICENSE("GPL");
+14 -16
drivers/i3c/master/svc-i3c-master.c
··· 104 104 #define SVC_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL GENMASK(5, 4) 105 105 #define SVC_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY 0 106 106 #define SVC_I3C_MDATACTRL_RXCOUNT(x) FIELD_GET(GENMASK(28, 24), (x)) 107 + #define SVC_I3C_MDATACTRL_TXCOUNT(x) FIELD_GET(GENMASK(20, 16), (x)) 107 108 #define SVC_I3C_MDATACTRL_TXFULL BIT(30) 108 109 #define SVC_I3C_MDATACTRL_RXEMPTY BIT(31) 109 110 ··· 665 664 } 666 665 667 666 rpm_out: 668 - pm_runtime_mark_last_busy(master->dev); 669 667 pm_runtime_put_autosuspend(master->dev); 670 668 671 669 return ret; ··· 779 779 goto rpm_out; 780 780 781 781 rpm_out: 782 - pm_runtime_mark_last_busy(master->dev); 783 782 pm_runtime_put_autosuspend(master->dev); 784 783 785 784 return ret; ··· 800 801 /* Disable master */ 801 802 writel(0, master->regs + SVC_I3C_MCONFIG); 802 803 803 - pm_runtime_mark_last_busy(master->dev); 804 804 pm_runtime_put_autosuspend(master->dev); 805 805 } 806 806 ··· 1205 1207 dev_err(master->dev, "Cannot handle such a list of devices"); 1206 1208 1207 1209 rpm_out: 1208 - pm_runtime_mark_last_busy(master->dev); 1209 1210 pm_runtime_put_autosuspend(master->dev); 1210 1211 1211 1212 return ret; ··· 1301 1304 * FIFO start filling as soon as possible after EmitStartAddr. 1302 1305 */ 1303 1306 if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) { 1304 - u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END; 1305 - u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE); 1307 + u32 space, end, len; 1306 1308 1307 - writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1); 1308 - /* Mark END bit if this is the last byte */ 1309 - writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB); 1310 - xfer_len -= len; 1311 - out += len; 1309 + reg = readl(master->regs + SVC_I3C_MDATACTRL); 1310 + space = SVC_I3C_FIFO_SIZE - SVC_I3C_MDATACTRL_TXCOUNT(reg); 1311 + if (space) { 1312 + end = xfer_len > space ? 0 : SVC_I3C_MWDATAB_END; 1313 + len = min_t(u32, xfer_len, space); 1314 + writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1); 1315 + /* Mark END bit if this is the last byte */ 1316 + writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB); 1317 + xfer_len -= len; 1318 + out += len; 1319 + } 1312 1320 } 1313 1321 1314 1322 ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg, ··· 1513 1511 } 1514 1512 spin_unlock_irqrestore(&master->xferqueue.lock, flags); 1515 1513 1516 - pm_runtime_mark_last_busy(master->dev); 1517 1514 pm_runtime_put_autosuspend(master->dev); 1518 1515 } 1519 1516 ··· 1709 1708 1710 1709 mutex_lock(&master->lock); 1711 1710 svc_i3c_master_enqueue_xfer(master, xfer); 1712 - if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) 1711 + if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout)) 1713 1712 svc_i3c_master_dequeue_xfer(master, xfer); 1714 1713 mutex_unlock(&master->lock); 1715 1714 ··· 1802 1801 1803 1802 ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); 1804 1803 1805 - pm_runtime_mark_last_busy(master->dev); 1806 1804 pm_runtime_put_autosuspend(master->dev); 1807 1805 1808 1806 return ret; ··· 1834 1834 if (!master->enabled_events) 1835 1835 svc_i3c_master_disable_interrupts(master); 1836 1836 1837 - pm_runtime_mark_last_busy(master->dev); 1838 1837 pm_runtime_put_autosuspend(master->dev); 1839 1838 1840 1839 return 0; ··· 1953 1954 if (ret) 1954 1955 goto rpm_disable; 1955 1956 1956 - pm_runtime_mark_last_busy(&pdev->dev); 1957 1957 pm_runtime_put_autosuspend(&pdev->dev); 1958 1958 1959 1959 return 0;
+2 -3
drivers/infiniband/sw/siw/siw_qp_tx.c
··· 340 340 if (!sendpage_ok(page[i])) 341 341 msg.msg_flags &= ~MSG_SPLICE_PAGES; 342 342 bvec_set_page(&bvec, page[i], bytes, offset); 343 - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); 343 + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, bytes); 344 344 345 345 try_page_again: 346 346 lock_sock(sk); 347 - rv = tcp_sendmsg_locked(sk, &msg, size); 347 + rv = tcp_sendmsg_locked(sk, &msg, bytes); 348 348 release_sock(sk); 349 349 350 350 if (rv > 0) { 351 351 size -= rv; 352 352 sent += rv; 353 353 if (rv != bytes) { 354 - offset += rv; 355 354 bytes -= rv; 356 355 goto try_page_again; 357 356 }
+1 -1
drivers/input/Makefile
··· 7 7 8 8 obj-$(CONFIG_INPUT) += input-core.o 9 9 input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o 10 - input-core-y += touchscreen.o 10 + input-core-y += touchscreen.o touch-overlay.o 11 11 12 12 obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o 13 13 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
+6 -2
drivers/input/evdev.c
··· 1408 1408 } 1409 1409 1410 1410 static const struct input_device_id evdev_ids[] = { 1411 - { .driver_info = 1 }, /* Matches all devices */ 1412 - { }, /* Terminating zero entry */ 1411 + { 1412 + /* Matches all devices */ 1413 + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 1414 + .evbit = { BIT_MASK(EV_SYN) }, 1415 + }, 1416 + { } /* Terminating zero entry */ 1413 1417 }; 1414 1418 1415 1419 MODULE_DEVICE_TABLE(input, evdev_ids);
+1 -1
drivers/input/input.c
··· 971 971 { 972 972 const struct input_device_id *id; 973 973 974 - for (id = handler->id_table; id->flags || id->driver_info; id++) { 974 + for (id = handler->id_table; id->flags; id++) { 975 975 if (input_match_device_id(dev, id) && 976 976 (!handler->match || handler->match(handler, dev))) { 977 977 return id;
+32 -32
drivers/input/joystick/xpad.c
··· 442 442 443 443 /* used when dpad is mapped to buttons */ 444 444 static const signed short xpad_btn_pad[] = { 445 - BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, /* d-pad left, right */ 446 - BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, /* d-pad up, down */ 445 + BTN_DPAD_LEFT, BTN_DPAD_RIGHT, /* d-pad left, right */ 446 + BTN_DPAD_UP, BTN_DPAD_DOWN, /* d-pad up, down */ 447 447 -1 /* terminating entry */ 448 448 }; 449 449 ··· 479 479 480 480 /* used when the controller has extra paddle buttons */ 481 481 static const signed short xpad_btn_paddles[] = { 482 - BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */ 483 - BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */ 482 + BTN_GRIPR, BTN_GRIPR2, /* paddle upper right, lower right */ 483 + BTN_GRIPL, BTN_GRIPL2, /* paddle upper left, lower left */ 484 484 -1 /* terminating entry */ 485 485 }; 486 486 ··· 840 840 /* digital pad */ 841 841 if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 842 842 /* dpad as buttons (left, right, up, down) */ 843 - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); 844 - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); 845 - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); 846 - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); 843 + input_report_key(dev, BTN_DPAD_LEFT, data[2] & BIT(2)); 844 + input_report_key(dev, BTN_DPAD_RIGHT, data[2] & BIT(3)); 845 + input_report_key(dev, BTN_DPAD_UP, data[2] & BIT(0)); 846 + input_report_key(dev, BTN_DPAD_DOWN, data[2] & BIT(1)); 847 847 } else { 848 848 input_report_abs(dev, ABS_HAT0X, 849 849 !!(data[2] & 0x08) - !!(data[2] & 0x04)); ··· 891 891 /* digital pad */ 892 892 if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 893 893 /* dpad as buttons (left, right, up, down) */ 894 - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); 895 - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); 896 - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); 897 - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); 894 + input_report_key(dev, BTN_DPAD_LEFT, data[2] & BIT(2)); 895 + input_report_key(dev, BTN_DPAD_RIGHT, data[2] & BIT(3)); 896 + input_report_key(dev, BTN_DPAD_UP, data[2] & BIT(0)); 897 + input_report_key(dev, BTN_DPAD_DOWN, data[2] & BIT(1)); 898 898 } 899 899 900 900 /* ··· 1075 1075 data[18] = 0; 1076 1076 1077 1077 /* Elite Series 2 split packet paddle bits */ 1078 - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); 1079 - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); 1080 - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); 1081 - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); 1078 + input_report_key(dev, BTN_GRIPR, data[18] & BIT(0)); 1079 + input_report_key(dev, BTN_GRIPR2, data[18] & BIT(1)); 1080 + input_report_key(dev, BTN_GRIPL, data[18] & BIT(2)); 1081 + input_report_key(dev, BTN_GRIPL2, data[18] & BIT(3)); 1082 1082 1083 1083 do_sync = true; 1084 1084 } ··· 1113 1113 /* digital pad */ 1114 1114 if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { 1115 1115 /* dpad as buttons (left, right, up, down) */ 1116 - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & BIT(2)); 1117 - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & BIT(3)); 1118 - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & BIT(0)); 1119 - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & BIT(1)); 1116 + input_report_key(dev, BTN_DPAD_LEFT, data[5] & BIT(2)); 1117 + input_report_key(dev, BTN_DPAD_RIGHT, data[5] & BIT(3)); 1118 + input_report_key(dev, BTN_DPAD_UP, data[5] & BIT(0)); 1119 + input_report_key(dev, BTN_DPAD_DOWN, data[5] & BIT(1)); 1120 1120 } else { 1121 1121 input_report_abs(dev, ABS_HAT0X, 1122 1122 !!(data[5] & 0x08) - !!(data[5] & 0x04)); ··· 1175 1175 data[32] = 0; 1176 1176 1177 1177 /* OG Elite Series Controller paddle bits */ 1178 - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & BIT(1)); 1179 - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & BIT(3)); 1180 - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & BIT(0)); 1181 - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & BIT(2)); 1178 + input_report_key(dev, BTN_GRIPR, data[32] & BIT(1)); 1179 + input_report_key(dev, BTN_GRIPR2, data[32] & BIT(3)); 1180 + input_report_key(dev, BTN_GRIPL, data[32] & BIT(0)); 1181 + input_report_key(dev, BTN_GRIPL2, data[32] & BIT(2)); 1182 1182 } else if (xpad->packet_type == PKT_XBE2_FW_OLD) { 1183 1183 /* Mute paddles if controller has a custom mapping applied. 1184 1184 * Checked by comparing the current mapping ··· 1188 1188 data[18] = 0; 1189 1189 1190 1190 /* Elite Series 2 4.x firmware paddle bits */ 1191 - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); 1192 - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); 1193 - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); 1194 - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); 1191 + input_report_key(dev, BTN_GRIPR, data[18] & BIT(0)); 1192 + input_report_key(dev, BTN_GRIPR2, data[18] & BIT(1)); 1193 + input_report_key(dev, BTN_GRIPL, data[18] & BIT(2)); 1194 + input_report_key(dev, BTN_GRIPL2, data[18] & BIT(3)); 1195 1195 } else if (xpad->packet_type == PKT_XBE2_FW_5_EARLY) { 1196 1196 /* Mute paddles if controller has a custom mapping applied. 1197 1197 * Checked by comparing the current mapping ··· 1203 1203 /* Elite Series 2 5.x firmware paddle bits 1204 1204 * (before the packet was split) 1205 1205 */ 1206 - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & BIT(0)); 1207 - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & BIT(1)); 1208 - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & BIT(2)); 1209 - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & BIT(3)); 1206 + input_report_key(dev, BTN_GRIPR, data[22] & BIT(0)); 1207 + input_report_key(dev, BTN_GRIPR2, data[22] & BIT(1)); 1208 + input_report_key(dev, BTN_GRIPL, data[22] & BIT(2)); 1209 + input_report_key(dev, BTN_GRIPL2, data[22] & BIT(3)); 1210 1210 } 1211 1211 } 1212 1212
+5 -4
drivers/input/keyboard/adp5588-keys.c
··· 232 232 return !!(val & bit); 233 233 } 234 234 235 - static void adp5588_gpio_set_value(struct gpio_chip *chip, 236 - unsigned int off, int val) 235 + static int adp5588_gpio_set_value(struct gpio_chip *chip, unsigned int off, 236 + int val) 237 237 { 238 238 struct adp5588_kpad *kpad = gpiochip_get_data(chip); 239 239 unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); ··· 246 246 else 247 247 kpad->dat_out[bank] &= ~bit; 248 248 249 - adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, kpad->dat_out[bank]); 249 + return adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, 250 + kpad->dat_out[bank]); 250 251 } 251 252 252 253 static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off, ··· 425 424 kpad->gc.direction_input = adp5588_gpio_direction_input; 426 425 kpad->gc.direction_output = adp5588_gpio_direction_output; 427 426 kpad->gc.get = adp5588_gpio_get_value; 428 - kpad->gc.set = adp5588_gpio_set_value; 427 + kpad->gc.set_rv = adp5588_gpio_set_value; 429 428 kpad->gc.set_config = adp5588_gpio_set_config; 430 429 kpad->gc.can_sleep = 1; 431 430
+6 -6
drivers/input/keyboard/atkbd.c
··· 84 84 #include "hpps2atkbd.h" /* include the keyboard scancodes */ 85 85 86 86 #else 87 - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, 88 - 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, 89 - 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, 90 - 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, 91 - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, 92 - 0, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0, 85, 87 + 0, 67, 65, 63, 61, 59, 60, 88,183, 68, 66, 64, 62, 15, 41,117, 88 + 184, 56, 42, 93, 29, 16, 2, 0,185, 0, 44, 31, 30, 17, 3, 0, 89 + 186, 46, 45, 32, 18, 5, 4, 95,187, 57, 47, 33, 20, 19, 6,183, 90 + 188, 49, 48, 35, 34, 21, 7,184,189, 0, 50, 36, 22, 8, 9,185, 91 + 190, 51, 37, 23, 24, 11, 10, 0,191, 52, 53, 38, 39, 25, 12, 0, 92 + 192, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0,194, 93 93 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, 94 94 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, 95 95
+17
drivers/input/keyboard/mtk-pmic-keys.c
··· 12 12 #include <linux/mfd/mt6331/registers.h> 13 13 #include <linux/mfd/mt6357/registers.h> 14 14 #include <linux/mfd/mt6358/registers.h> 15 + #include <linux/mfd/mt6359/registers.h> 15 16 #include <linux/mfd/mt6397/core.h> 16 17 #include <linux/mfd/mt6397/registers.h> 17 18 #include <linux/module.h> ··· 115 114 0x8, MT6358_PSC_TOP_INT_CON0, 0xa, 116 115 MTK_PMIC_HOMEKEY_RST), 117 116 .pmic_rst_reg = MT6358_TOP_RST_MISC, 117 + .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, 118 + }; 119 + 120 + static const struct mtk_pmic_regs mt6359_regs = { 121 + .keys_regs[MTK_PMIC_PWRKEY_INDEX] = 122 + MTK_PMIC_KEYS_REGS(MT6359_TOPSTATUS, 123 + 0x2, MT6359_PSC_TOP_INT_CON0, 0x5, 124 + MTK_PMIC_PWRKEY_RST), 125 + .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = 126 + MTK_PMIC_KEYS_REGS(MT6359_TOPSTATUS, 127 + 0x8, MT6359_PSC_TOP_INT_CON0, 0xa, 128 + MTK_PMIC_HOMEKEY_RST), 129 + .pmic_rst_reg = MT6359_TOP_RST_MISC, 118 130 .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, 119 131 }; 120 132 ··· 310 296 }, { 311 297 .compatible = "mediatek,mt6358-keys", 312 298 .data = &mt6358_regs, 299 + }, { 300 + .compatible = "mediatek,mt6359-keys", 301 + .data = &mt6359_regs, 313 302 }, { 314 303 /* sentinel */ 315 304 }
+64 -73
drivers/input/keyboard/samsung-keypad.c
··· 7 7 * Author: Donghwa Lee <dh09.lee@samsung.com> 8 8 */ 9 9 10 + #include <linux/bits.h> 10 11 #include <linux/clk.h> 11 12 #include <linux/delay.h> 12 13 #include <linux/err.h> ··· 30 29 #define SAMSUNG_KEYIFFC 0x10 31 30 32 31 /* SAMSUNG_KEYIFCON */ 33 - #define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0) 34 - #define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1) 35 - #define SAMSUNG_KEYIFCON_DF_EN (1 << 2) 36 - #define SAMSUNG_KEYIFCON_FC_EN (1 << 3) 37 - #define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4) 32 + #define SAMSUNG_KEYIFCON_INT_F_EN BIT(0) 33 + #define SAMSUNG_KEYIFCON_INT_R_EN BIT(1) 34 + #define SAMSUNG_KEYIFCON_DF_EN BIT(2) 35 + #define SAMSUNG_KEYIFCON_FC_EN BIT(3) 36 + #define SAMSUNG_KEYIFCON_WAKEUPEN BIT(4) 38 37 39 38 /* SAMSUNG_KEYIFSTSCLR */ 40 39 #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0) ··· 45 44 #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16 46 45 47 46 /* SAMSUNG_KEYIFCOL */ 48 - #define SAMSUNG_KEYIFCOL_MASK (0xff << 0) 49 - #define S5PV210_KEYIFCOLEN_MASK (0xff << 8) 47 + #define SAMSUNG_KEYIFCOL_MASK 0xff 50 48 51 49 /* SAMSUNG_KEYIFROW */ 52 50 #define SAMSUNG_KEYIFROW_MASK (0xff << 0) ··· 54 54 /* SAMSUNG_KEYIFFC */ 55 55 #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0) 56 56 57 - enum samsung_keypad_type { 58 - KEYPAD_TYPE_SAMSUNG, 59 - KEYPAD_TYPE_S5PV210, 57 + struct samsung_chip_info { 58 + unsigned int column_shift; 60 59 }; 61 60 62 61 struct samsung_keypad { 62 + const struct samsung_chip_info *chip; 63 63 struct input_dev *input_dev; 64 64 struct platform_device *pdev; 65 65 struct clk *clk; ··· 68 68 bool stopped; 69 69 bool wake_enabled; 70 70 int irq; 71 - enum samsung_keypad_type type; 72 71 unsigned int row_shift; 73 72 unsigned int rows; 74 73 unsigned int cols; ··· 82 83 unsigned int val; 83 84 84 85 for (col = 0; col < keypad->cols; col++) { 85 - if (keypad->type == KEYPAD_TYPE_S5PV210) { 86 - val = S5PV210_KEYIFCOLEN_MASK; 87 - val &= ~(1 << col) << 8; 88 - } else { 89 - val = SAMSUNG_KEYIFCOL_MASK; 90 - val &= ~(1 << col); 91 - } 86 + val = SAMSUNG_KEYIFCOL_MASK & ~BIT(col); 87 + val <<= keypad->chip->column_shift; 92 88 93 89 writel(val, keypad->base + SAMSUNG_KEYIFCOL); 94 90 mdelay(1); 95 91 96 92 val = readl(keypad->base + SAMSUNG_KEYIFROW); 97 - row_state[col] = ~val & ((1 << keypad->rows) - 1); 93 + row_state[col] = ~val & GENMASK(keypad->rows - 1, 0); 98 94 } 99 95 100 96 /* KEYIFCOL reg clear */ ··· 113 119 continue; 114 120 115 121 for (row = 0; row < keypad->rows; row++) { 116 - if (!(changed & (1 << row))) 122 + if (!(changed & BIT(row))) 117 123 continue; 118 124 119 - pressed = row_state[col] & (1 << row); 125 + pressed = row_state[col] & BIT(row); 120 126 121 127 dev_dbg(&keypad->input_dev->dev, 122 128 "key %s, row: %d, col: %d\n", ··· 308 314 { 309 315 const struct samsung_keypad_platdata *pdata; 310 316 const struct matrix_keymap_data *keymap_data; 317 + const struct platform_device_id *id; 311 318 struct samsung_keypad *keypad; 312 319 struct resource *res; 313 320 struct input_dev *input_dev; 314 321 unsigned int row_shift; 315 - unsigned int keymap_size; 316 322 int error; 317 323 318 324 pdata = dev_get_platdata(&pdev->dev); ··· 339 345 pdata->cfg_gpio(pdata->rows, pdata->cols); 340 346 341 347 row_shift = get_count_order(pdata->cols); 342 - keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); 343 348 344 - keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad) + keymap_size, 349 + keypad = devm_kzalloc(&pdev->dev, 350 + struct_size(keypad, keycodes, 351 + pdata->rows << row_shift), 345 352 GFP_KERNEL); 353 + if (!keypad) 354 + return -ENOMEM; 355 + 346 356 input_dev = devm_input_allocate_device(&pdev->dev); 347 - if (!keypad || !input_dev) 357 + if (!input_dev) 348 358 return -ENOMEM; 349 359 350 360 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ··· 359 361 if (!keypad->base) 360 362 return -EBUSY; 361 363 362 - keypad->clk = devm_clk_get(&pdev->dev, "keypad"); 364 + keypad->clk = devm_clk_get_prepared(&pdev->dev, "keypad"); 363 365 if (IS_ERR(keypad->clk)) { 364 366 dev_err(&pdev->dev, "failed to get keypad clk\n"); 365 367 return PTR_ERR(keypad->clk); 366 - } 367 - 368 - error = clk_prepare(keypad->clk); 369 - if (error) { 370 - dev_err(&pdev->dev, "keypad clock prepare failed\n"); 371 - return error; 372 368 } 373 369 374 370 keypad->input_dev = input_dev; ··· 373 381 keypad->stopped = true; 374 382 init_waitqueue_head(&keypad->wait); 375 383 376 - if (pdev->dev.of_node) 377 - keypad->type = of_device_is_compatible(pdev->dev.of_node, 378 - "samsung,s5pv210-keypad"); 379 - else 380 - keypad->type = platform_get_device_id(pdev)->driver_data; 384 + keypad->chip = device_get_match_data(&pdev->dev); 385 + if (!keypad->chip) { 386 + id = platform_get_device_id(pdev); 387 + if (id) 388 + keypad->chip = (const void *)id->driver_data; 389 + } 390 + 391 + if (!keypad->chip) { 392 + dev_err(&pdev->dev, "Unable to determine chip type"); 393 + return -EINVAL; 394 + } 381 395 382 396 input_dev->name = pdev->name; 383 397 input_dev->id.bustype = BUS_HOST; 384 - input_dev->dev.parent = &pdev->dev; 385 398 386 399 input_dev->open = samsung_keypad_open; 387 400 input_dev->close = samsung_keypad_close; ··· 396 399 keypad->keycodes, input_dev); 397 400 if (error) { 398 401 dev_err(&pdev->dev, "failed to build keymap\n"); 399 - goto err_unprepare_clk; 402 + return error; 400 403 } 401 404 402 405 input_set_capability(input_dev, EV_MSC, MSC_SCAN); ··· 408 411 keypad->irq = platform_get_irq(pdev, 0); 409 412 if (keypad->irq < 0) { 410 413 error = keypad->irq; 411 - goto err_unprepare_clk; 414 + return error; 412 415 } 413 416 414 417 error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL, ··· 416 419 dev_name(&pdev->dev), keypad); 417 420 if (error) { 418 421 dev_err(&pdev->dev, "failed to register keypad interrupt\n"); 419 - goto err_unprepare_clk; 422 + return error; 420 423 } 421 424 422 425 device_init_wakeup(&pdev->dev, pdata->wakeup); 423 426 platform_set_drvdata(pdev, keypad); 424 - pm_runtime_enable(&pdev->dev); 427 + 428 + error = devm_pm_runtime_enable(&pdev->dev); 429 + if (error) 430 + return error; 425 431 426 432 error = input_register_device(keypad->input_dev); 427 433 if (error) 428 - goto err_disable_runtime_pm; 434 + return error; 429 435 430 436 if (pdev->dev.of_node) { 431 437 devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); ··· 436 436 devm_kfree(&pdev->dev, (void *)pdata); 437 437 } 438 438 return 0; 439 - 440 - err_disable_runtime_pm: 441 - pm_runtime_disable(&pdev->dev); 442 - err_unprepare_clk: 443 - clk_unprepare(keypad->clk); 444 - return error; 445 - } 446 - 447 - static void samsung_keypad_remove(struct platform_device *pdev) 448 - { 449 - struct samsung_keypad *keypad = platform_get_drvdata(pdev); 450 - 451 - pm_runtime_disable(&pdev->dev); 452 - 453 - input_unregister_device(keypad->input_dev); 454 - 455 - clk_unprepare(keypad->clk); 456 439 } 457 440 458 441 static int samsung_keypad_runtime_suspend(struct device *dev) ··· 511 528 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 512 529 struct input_dev *input_dev = keypad->input_dev; 513 530 514 - mutex_lock(&input_dev->mutex); 531 + guard(mutex)(&input_dev->mutex); 515 532 516 533 if (input_device_enabled(input_dev)) 517 534 samsung_keypad_stop(keypad); 518 535 519 536 samsung_keypad_toggle_wakeup(keypad, true); 520 - 521 - mutex_unlock(&input_dev->mutex); 522 537 523 538 return 0; 524 539 } ··· 527 546 struct samsung_keypad *keypad = platform_get_drvdata(pdev); 528 547 struct input_dev *input_dev = keypad->input_dev; 529 548 530 - mutex_lock(&input_dev->mutex); 549 + guard(mutex)(&input_dev->mutex); 531 550 532 551 samsung_keypad_toggle_wakeup(keypad, false); 533 552 534 553 if (input_device_enabled(input_dev)) 535 554 samsung_keypad_start(keypad); 536 - 537 - mutex_unlock(&input_dev->mutex); 538 555 539 556 return 0; 540 557 } ··· 543 564 samsung_keypad_runtime_resume, NULL) 544 565 }; 545 566 567 + static const struct samsung_chip_info samsung_s3c6410_chip_info = { 568 + .column_shift = 0, 569 + }; 570 + 571 + static const struct samsung_chip_info samsung_s5pv210_chip_info = { 572 + .column_shift = 8, 573 + }; 574 + 546 575 #ifdef CONFIG_OF 547 576 static const struct of_device_id samsung_keypad_dt_match[] = { 548 - { .compatible = "samsung,s3c6410-keypad" }, 549 - { .compatible = "samsung,s5pv210-keypad" }, 550 - {}, 577 + { 578 + .compatible = "samsung,s3c6410-keypad", 579 + .data = &samsung_s3c6410_chip_info, 580 + }, { 581 + .compatible = "samsung,s5pv210-keypad", 582 + .data = &samsung_s5pv210_chip_info, 583 + }, 584 + { } 551 585 }; 552 586 MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); 553 587 #endif ··· 568 576 static const struct platform_device_id samsung_keypad_driver_ids[] = { 569 577 { 570 578 .name = "samsung-keypad", 571 - .driver_data = KEYPAD_TYPE_SAMSUNG, 579 + .driver_data = (kernel_ulong_t)&samsung_s3c6410_chip_info, 572 580 }, { 573 581 .name = "s5pv210-keypad", 574 - .driver_data = KEYPAD_TYPE_S5PV210, 582 + .driver_data = (kernel_ulong_t)&samsung_s5pv210_chip_info, 575 583 }, 576 - { }, 584 + { } 577 585 }; 578 586 MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); 579 587 580 588 static struct platform_driver samsung_keypad_driver = { 581 589 .probe = samsung_keypad_probe, 582 - .remove = samsung_keypad_remove, 583 590 .driver = { 584 591 .name = "samsung-keypad", 585 592 .of_match_table = of_match_ptr(samsung_keypad_dt_match),
-7
drivers/input/misc/Kconfig
··· 584 584 To compile this driver as a module, choose M here. The module will 585 585 be called palmas_pwrbutton. 586 586 587 - config INPUT_PCF50633_PMU 588 - tristate "PCF50633 PMU events" 589 - depends on MFD_PCF50633 590 - help 591 - Say Y to include support for delivering PMU events via input 592 - layer on NXP PCF50633. 593 - 594 587 config INPUT_PCF8574 595 588 tristate "PCF8574 Keypad input device" 596 589 depends on I2C
-1
drivers/input/misc/Makefile
··· 59 59 obj-$(CONFIG_INPUT_MMA8450) += mma8450.o 60 60 obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o 61 61 obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o 62 - obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o 63 62 obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o 64 63 obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o 65 64 obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o
-1
drivers/input/misc/cs40l50-vibra.c
··· 482 482 483 483 static void cs40l50_remove_wq(void *data) 484 484 { 485 - flush_workqueue(data); 486 485 destroy_workqueue(data); 487 486 } 488 487
+18 -23
drivers/input/misc/max77693-haptic.c
··· 68 68 69 69 static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) 70 70 { 71 - struct pwm_args pargs; 72 - int delta; 71 + struct pwm_state state; 73 72 int error; 74 73 75 - pwm_get_args(haptic->pwm_dev, &pargs); 76 - delta = (pargs.period + haptic->pwm_duty) / 2; 77 - error = pwm_config(haptic->pwm_dev, delta, pargs.period); 74 + pwm_init_state(haptic->pwm_dev, &state); 75 + state.duty_cycle = (state.period + haptic->pwm_duty) / 2; 76 + 77 + error = pwm_apply_might_sleep(haptic->pwm_dev, &state); 78 78 if (error) { 79 - dev_err(haptic->dev, "failed to configure pwm: %d\n", error); 79 + dev_err(haptic->dev, 80 + "failed to set pwm duty cycle: %d\n", error); 80 81 return error; 81 82 } 82 83 ··· 167 166 168 167 static void max77693_haptic_enable(struct max77693_haptic *haptic) 169 168 { 169 + struct pwm_state state; 170 170 int error; 171 171 172 172 if (haptic->enabled) 173 173 return; 174 174 175 - error = pwm_enable(haptic->pwm_dev); 175 + pwm_init_state(haptic->pwm_dev, &state); 176 + state.duty_cycle = (state.period + haptic->pwm_duty) / 2; 177 + state.enabled = true; 178 + 179 + error = pwm_apply_might_sleep(haptic->pwm_dev, &state); 176 180 if (error) { 177 181 dev_err(haptic->dev, 178 182 "failed to enable haptic pwm device: %d\n", error); ··· 230 224 { 231 225 struct max77693_haptic *haptic = 232 226 container_of(work, struct max77693_haptic, work); 233 - int error; 234 227 235 - error = max77693_haptic_set_duty_cycle(haptic); 236 - if (error) { 237 - dev_err(haptic->dev, "failed to set duty cycle: %d\n", error); 238 - return; 239 - } 240 - 241 - if (haptic->magnitude) 242 - max77693_haptic_enable(haptic); 243 - else 228 + if (!haptic->magnitude) 244 229 max77693_haptic_disable(haptic); 230 + else if (haptic->enabled) 231 + max77693_haptic_set_duty_cycle(haptic); 232 + else 233 + max77693_haptic_enable(haptic); 245 234 } 246 235 247 236 static int max77693_haptic_play_effect(struct input_dev *dev, void *data, ··· 340 339 dev_err(&pdev->dev, "failed to get pwm device\n"); 341 340 return PTR_ERR(haptic->pwm_dev); 342 341 } 343 - 344 - /* 345 - * FIXME: pwm_apply_args() should be removed when switching to the 346 - * atomic PWM API. 347 - */ 348 - pwm_apply_args(haptic->pwm_dev); 349 342 350 343 haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic"); 351 344 if (IS_ERR(haptic->motor_reg)) {
+48 -50
drivers/input/misc/max8997_haptic.c
··· 53 53 unsigned int pattern_signal_period; 54 54 }; 55 55 56 - static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip) 56 + static void max8997_haptic_set_internal_duty_cycle(struct max8997_haptic *chip) 57 57 { 58 - int ret = 0; 58 + u8 duty_index = DIV_ROUND_UP(chip->level * 64, 100); 59 59 60 - if (chip->mode == MAX8997_EXTERNAL_MODE) { 61 - unsigned int duty = chip->pwm_period * chip->level / 100; 62 - ret = pwm_config(chip->pwm, duty, chip->pwm_period); 63 - } else { 64 - u8 duty_index = 0; 65 - 66 - duty_index = DIV_ROUND_UP(chip->level * 64, 100); 67 - 68 - switch (chip->internal_mode_pattern) { 69 - case 0: 70 - max8997_write_reg(chip->client, 71 - MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index); 72 - break; 73 - case 1: 74 - max8997_write_reg(chip->client, 75 - MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index); 76 - break; 77 - case 2: 78 - max8997_write_reg(chip->client, 79 - MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index); 80 - break; 81 - case 3: 82 - max8997_write_reg(chip->client, 83 - MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index); 84 - break; 85 - default: 86 - break; 87 - } 60 + switch (chip->internal_mode_pattern) { 61 + case 0: 62 + max8997_write_reg(chip->client, 63 + MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index); 64 + break; 65 + case 1: 66 + max8997_write_reg(chip->client, 67 + MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index); 68 + break; 69 + case 2: 70 + max8997_write_reg(chip->client, 71 + MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index); 72 + break; 73 + case 3: 74 + max8997_write_reg(chip->client, 75 + MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index); 76 + break; 77 + default: 78 + break; 88 79 } 89 - return ret; 90 80 } 91 81 92 82 static void max8997_haptic_configure(struct max8997_haptic *chip) ··· 145 155 146 156 guard(mutex)(&chip->mutex); 147 157 148 - error = max8997_haptic_set_duty_cycle(chip); 149 - if (error) { 150 - dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error); 151 - return; 152 - } 158 + if (chip->mode != MAX8997_EXTERNAL_MODE) 159 + max8997_haptic_set_internal_duty_cycle(chip); 153 160 154 161 if (!chip->enabled) { 155 162 error = regulator_enable(chip->regulator); ··· 155 168 return; 156 169 } 157 170 max8997_haptic_configure(chip); 158 - if (chip->mode == MAX8997_EXTERNAL_MODE) { 159 - error = pwm_enable(chip->pwm); 160 - if (error) { 161 - dev_err(chip->dev, "Failed to enable PWM\n"); 162 - regulator_disable(chip->regulator); 163 - return; 164 - } 165 - } 166 - chip->enabled = true; 167 171 } 172 + 173 + /* 174 + * It would be more straight forward to configure the external PWM 175 + * earlier i.e. when the internal duty_cycle is setup in internal mode. 176 + * But historically this is done only after the regulator was enabled 177 + * and max8997_haptic_configure() set the enable bit in 178 + * MAX8997_HAPTIC_REG_CONF2. So better keep it this way. 179 + */ 180 + if (chip->mode == MAX8997_EXTERNAL_MODE) { 181 + struct pwm_state state; 182 + 183 + pwm_init_state(chip->pwm, &state); 184 + state.period = chip->pwm_period; 185 + state.duty_cycle = chip->pwm_period * chip->level / 100; 186 + state.enabled = true; 187 + 188 + error = pwm_apply_might_sleep(chip->pwm, &state); 189 + if (error) { 190 + dev_err(chip->dev, "Failed to enable PWM\n"); 191 + regulator_disable(chip->regulator); 192 + return; 193 + } 194 + } 195 + 196 + chip->enabled = true; 168 197 } 169 198 170 199 static void max8997_haptic_disable(struct max8997_haptic *chip) ··· 285 282 goto err_free_mem; 286 283 } 287 284 288 - /* 289 - * FIXME: pwm_apply_args() should be removed when switching to 290 - * the atomic PWM API. 291 - */ 292 - pwm_apply_args(chip->pwm); 293 285 break; 294 286 295 287 default:
-113
drivers/input/misc/pcf50633-input.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* NXP PCF50633 Input Driver 3 - * 4 - * (C) 2006-2008 by Openmoko, Inc. 5 - * Author: Balaji Rao <balajirrao@openmoko.org> 6 - * All rights reserved. 7 - * 8 - * Broken down from monstrous PCF50633 driver mainly by 9 - * Harald Welte, Andy Green and Werner Almesberger 10 - */ 11 - 12 - #include <linux/kernel.h> 13 - #include <linux/module.h> 14 - #include <linux/device.h> 15 - #include <linux/platform_device.h> 16 - #include <linux/input.h> 17 - #include <linux/slab.h> 18 - 19 - #include <linux/mfd/pcf50633/core.h> 20 - 21 - #define PCF50633_OOCSTAT_ONKEY 0x01 22 - #define PCF50633_REG_OOCSTAT 0x12 23 - #define PCF50633_REG_OOCMODE 0x10 24 - 25 - struct pcf50633_input { 26 - struct pcf50633 *pcf; 27 - struct input_dev *input_dev; 28 - }; 29 - 30 - static void 31 - pcf50633_input_irq(int irq, void *data) 32 - { 33 - struct pcf50633_input *input; 34 - int onkey_released; 35 - 36 - input = data; 37 - 38 - /* We report only one event depending on the key press status */ 39 - onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT) 40 - & PCF50633_OOCSTAT_ONKEY; 41 - 42 - if (irq == PCF50633_IRQ_ONKEYF && !onkey_released) 43 - input_report_key(input->input_dev, KEY_POWER, 1); 44 - else if (irq == PCF50633_IRQ_ONKEYR && onkey_released) 45 - input_report_key(input->input_dev, KEY_POWER, 0); 46 - 47 - input_sync(input->input_dev); 48 - } 49 - 50 - static int pcf50633_input_probe(struct platform_device *pdev) 51 - { 52 - struct pcf50633_input *input; 53 - struct input_dev *input_dev; 54 - int ret; 55 - 56 - 57 - input = kzalloc(sizeof(*input), GFP_KERNEL); 58 - if (!input) 59 - return -ENOMEM; 60 - 61 - input_dev = input_allocate_device(); 62 - if (!input_dev) { 63 - kfree(input); 64 - return -ENOMEM; 65 - } 66 - 67 - platform_set_drvdata(pdev, input); 68 - input->pcf = dev_to_pcf50633(pdev->dev.parent); 69 - input->input_dev = input_dev; 70 - 71 - input_dev->name = "PCF50633 PMU events"; 72 - input_dev->id.bustype = BUS_I2C; 73 - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR); 74 - set_bit(KEY_POWER, input_dev->keybit); 75 - 76 - ret = input_register_device(input_dev); 77 - if (ret) { 78 - input_free_device(input_dev); 79 - kfree(input); 80 - return ret; 81 - } 82 - pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR, 83 - pcf50633_input_irq, input); 84 - pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF, 85 - pcf50633_input_irq, input); 86 - 87 - return 0; 88 - } 89 - 90 - static void pcf50633_input_remove(struct platform_device *pdev) 91 - { 92 - struct pcf50633_input *input = platform_get_drvdata(pdev); 93 - 94 - pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR); 95 - pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF); 96 - 97 - input_unregister_device(input->input_dev); 98 - kfree(input); 99 - } 100 - 101 - static struct platform_driver pcf50633_input_driver = { 102 - .driver = { 103 - .name = "pcf50633-input", 104 - }, 105 - .probe = pcf50633_input_probe, 106 - .remove = pcf50633_input_remove, 107 - }; 108 - module_platform_driver(pcf50633_input_driver); 109 - 110 - MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); 111 - MODULE_DESCRIPTION("PCF50633 input driver"); 112 - MODULE_LICENSE("GPL"); 113 - MODULE_ALIAS("platform:pcf50633-input");
+15
drivers/input/rmi4/Kconfig
··· 82 82 touchpads. For sensors that support relative pointing, F12 also 83 83 provides mouse input. 84 84 85 + config RMI4_F1A 86 + bool "RMI4 Function 1A (0D pointing)" 87 + help 88 + Say Y here if you want to add support for RMI4 function 1A. 89 + 90 + Function 1A provides capacitive keys support for RMI4 devices. 91 + 92 + config RMI4_F21 93 + bool "RMI4 Function 21 (PRESSURE)" 94 + help 95 + Say Y here if you want to add support for RMI4 function 21. 96 + 97 + Function 21 provides buttons/pressure handling for RMI4 devices. 98 + This includes support for buttons/pressure on PressurePad. 99 + 85 100 config RMI4_F30 86 101 bool "RMI4 Function 30 (GPIO LED)" 87 102 help
+2
drivers/input/rmi4/Makefile
··· 8 8 rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o 9 9 rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o 10 10 rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o 11 + rmi_core-$(CONFIG_RMI4_F1A) += rmi_f1a.o 12 + rmi_core-$(CONFIG_RMI4_F21) += rmi_f21.o 11 13 rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o 12 14 rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o 13 15 rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o
+6
drivers/input/rmi4/rmi_bus.c
··· 360 360 #ifdef CONFIG_RMI4_F12 361 361 &rmi_f12_handler, 362 362 #endif 363 + #ifdef CONFIG_RMI4_F1A 364 + &rmi_f1a_handler, 365 + #endif 366 + #ifdef CONFIG_RMI4_F21 367 + &rmi_f21_handler, 368 + #endif 363 369 #ifdef CONFIG_RMI4_F30 364 370 &rmi_f30_handler, 365 371 #endif
+2
drivers/input/rmi4/rmi_driver.h
··· 133 133 extern struct rmi_function_handler rmi_f03_handler; 134 134 extern struct rmi_function_handler rmi_f11_handler; 135 135 extern struct rmi_function_handler rmi_f12_handler; 136 + extern struct rmi_function_handler rmi_f1a_handler; 137 + extern struct rmi_function_handler rmi_f21_handler; 136 138 extern struct rmi_function_handler rmi_f30_handler; 137 139 extern struct rmi_function_handler rmi_f34_handler; 138 140 extern struct rmi_function_handler rmi_f3a_handler;
+143
drivers/input/rmi4/rmi_f1a.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2025 André Apitzsch <git@apitzsch.eu> 4 + */ 5 + 6 + #include <linux/input.h> 7 + #include <linux/property.h> 8 + #include "rmi_driver.h" 9 + 10 + struct f1a_data { 11 + struct input_dev *input; 12 + 13 + u32 *keymap; 14 + unsigned int num_keys; 15 + }; 16 + 17 + static int rmi_f1a_parse_device_properties(struct rmi_function *fn, struct f1a_data *f1a) 18 + { 19 + static const char buttons_property[] = "linux,keycodes"; 20 + struct device *dev = &fn->dev; 21 + u32 *buttonmap; 22 + int n_keys; 23 + int error; 24 + 25 + if (!device_property_present(dev, buttons_property)) 26 + return 0; 27 + 28 + n_keys = device_property_count_u32(dev, buttons_property); 29 + if (n_keys <= 0) { 30 + error = n_keys < 0 ? n_keys : -EINVAL; 31 + dev_err(dev, "Invalid/malformed '%s' property: %d\n", 32 + buttons_property, error); 33 + return error; 34 + } 35 + 36 + buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap), 37 + GFP_KERNEL); 38 + if (!buttonmap) 39 + return -ENOMEM; 40 + 41 + error = device_property_read_u32_array(dev, buttons_property, 42 + buttonmap, n_keys); 43 + if (error) { 44 + dev_err(dev, "Failed to parse '%s' property: %d\n", 45 + buttons_property, error); 46 + return error; 47 + } 48 + 49 + f1a->keymap = buttonmap; 50 + f1a->num_keys = n_keys; 51 + 52 + return 0; 53 + } 54 + 55 + static irqreturn_t rmi_f1a_attention(int irq, void *ctx) 56 + { 57 + struct rmi_function *fn = ctx; 58 + struct f1a_data *f1a = dev_get_drvdata(&fn->dev); 59 + char button_bitmask; 60 + int key; 61 + int error; 62 + 63 + error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, 64 + &button_bitmask, sizeof(button_bitmask)); 65 + if (error) { 66 + dev_err(&fn->dev, "Failed to read object data. Code: %d.\n", 67 + error); 68 + return IRQ_RETVAL(error); 69 + } 70 + 71 + for (key = 0; key < f1a->num_keys; key++) 72 + input_report_key(f1a->input, f1a->keymap[key], 73 + button_bitmask & BIT(key)); 74 + 75 + return IRQ_HANDLED; 76 + } 77 + 78 + static int rmi_f1a_config(struct rmi_function *fn) 79 + { 80 + struct f1a_data *f1a = dev_get_drvdata(&fn->dev); 81 + struct rmi_driver *drv = fn->rmi_dev->driver; 82 + 83 + if (f1a->num_keys) 84 + drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); 85 + 86 + return 0; 87 + } 88 + 89 + static int rmi_f1a_initialize(struct rmi_function *fn, struct f1a_data *f1a) 90 + { 91 + int error; 92 + int i; 93 + 94 + error = rmi_f1a_parse_device_properties(fn, f1a); 95 + if (error) 96 + return error; 97 + 98 + for (i = 0; i < f1a->num_keys; i++) 99 + input_set_capability(f1a->input, EV_KEY, f1a->keymap[i]); 100 + 101 + f1a->input->keycode = f1a->keymap; 102 + f1a->input->keycodemax = f1a->num_keys; 103 + f1a->input->keycodesize = sizeof(f1a->keymap[0]); 104 + 105 + return 0; 106 + } 107 + 108 + static int rmi_f1a_probe(struct rmi_function *fn) 109 + { 110 + struct rmi_device *rmi_dev = fn->rmi_dev; 111 + struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); 112 + struct f1a_data *f1a; 113 + int error; 114 + 115 + if (!drv_data->input) { 116 + dev_info(&fn->dev, "F1A: no input device found, ignoring\n"); 117 + return -ENXIO; 118 + } 119 + 120 + f1a = devm_kzalloc(&fn->dev, sizeof(*f1a), GFP_KERNEL); 121 + if (!f1a) 122 + return -ENOMEM; 123 + 124 + f1a->input = drv_data->input; 125 + 126 + error = rmi_f1a_initialize(fn, f1a); 127 + if (error) 128 + return error; 129 + 130 + dev_set_drvdata(&fn->dev, f1a); 131 + 132 + return 0; 133 + } 134 + 135 + struct rmi_function_handler rmi_f1a_handler = { 136 + .driver = { 137 + .name = "rmi4_f1a", 138 + }, 139 + .func = 0x1a, 140 + .probe = rmi_f1a_probe, 141 + .config = rmi_f1a_config, 142 + .attention = rmi_f1a_attention, 143 + };
+179
drivers/input/rmi4/rmi_f21.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2012-2025 Synaptics Incorporated 4 + */ 5 + 6 + #include <linux/bits.h> 7 + #include <linux/dev_printk.h> 8 + #include <linux/kernel.h> 9 + #include <linux/rmi.h> 10 + #include <linux/input.h> 11 + #include <linux/slab.h> 12 + #include "rmi_driver.h" 13 + 14 + #define RMI_F21_SENSOR_COUNT_MASK GENMASK(3, 0) 15 + #define RMI_F21_FINGER_COUNT_PRESENT BIT(5) 16 + #define RMI_F21_NEW_REPORT_FORMAT BIT(6) 17 + 18 + #define RMI_F21_FINGER_COUNT_MASK GENMASK(3, 0) 19 + 20 + #define RMI_F21_MAX_SENSORS 16 21 + #define RMI_F21_MAX_FINGERS 16 22 + #define RMI_F21_DATA_REGS_MAX_SIZE (RMI_F21_MAX_SENSORS * 2 + \ 23 + RMI_F21_MAX_FINGERS * 2 + 1) 24 + 25 + #define RMI_F21_FORCE_CLICK_BIT BIT(0) 26 + 27 + #define RMI_F21_FORCEPAD_BUTTON_COUNT 1 28 + 29 + struct f21_data { 30 + struct input_dev *input; 31 + u16 key_code; 32 + 33 + unsigned int attn_data_size; 34 + unsigned int attn_data_button_offset; 35 + 36 + unsigned int data_reg_size; 37 + unsigned int data_reg_button_offset; 38 + u8 data_regs[RMI_F21_DATA_REGS_MAX_SIZE]; 39 + }; 40 + 41 + static irqreturn_t rmi_f21_attention(int irq, void *ctx) 42 + { 43 + struct rmi_function *fn = ctx; 44 + struct f21_data *f21 = dev_get_drvdata(&fn->dev); 45 + struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); 46 + u8 *pdata; 47 + int error; 48 + bool pressed; 49 + 50 + if (drvdata->attn_data.data) { 51 + if (drvdata->attn_data.size < f21->attn_data_size) { 52 + dev_warn(&fn->dev, "f21 interrupt, but data is missing\n"); 53 + return IRQ_HANDLED; 54 + } 55 + 56 + pdata = drvdata->attn_data.data + f21->attn_data_button_offset; 57 + 58 + drvdata->attn_data.data += f21->attn_data_size; 59 + drvdata->attn_data.size -= f21->attn_data_size; 60 + } else { 61 + error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, 62 + f21->data_regs, f21->data_reg_size); 63 + if (error) { 64 + dev_err(&fn->dev, "failed to read f21 data registers: %d\n", 65 + error); 66 + return IRQ_RETVAL(error); 67 + } 68 + 69 + pdata = f21->data_regs + f21->data_reg_button_offset; 70 + } 71 + 72 + pressed = *pdata & RMI_F21_FORCE_CLICK_BIT; 73 + input_report_key(f21->input, f21->key_code, pressed); 74 + 75 + return IRQ_HANDLED; 76 + } 77 + 78 + static int rmi_f21_config(struct rmi_function *fn) 79 + { 80 + struct rmi_driver *drv = fn->rmi_dev->driver; 81 + 82 + drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); 83 + 84 + return 0; 85 + } 86 + 87 + static int rmi_f21_initialize(struct rmi_function *fn, struct f21_data *f21) 88 + { 89 + struct input_dev *input = f21->input; 90 + 91 + f21->key_code = BTN_LEFT; 92 + 93 + input->keycode = &f21->key_code; 94 + input->keycodesize = sizeof(f21->key_code); 95 + input->keycodemax = RMI_F21_FORCEPAD_BUTTON_COUNT; 96 + 97 + input_set_capability(input, EV_KEY, f21->key_code); 98 + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 99 + 100 + return 0; 101 + } 102 + 103 + static int rmi_f21_probe(struct rmi_function *fn) 104 + { 105 + struct rmi_device *rmi_dev = fn->rmi_dev; 106 + struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); 107 + struct f21_data *f21; 108 + unsigned int sensor_count; 109 + unsigned int max_fingers; 110 + unsigned int query15_offset; 111 + u8 query15_data; 112 + int error; 113 + 114 + if (!drv_data->input) { 115 + dev_info(&fn->dev, "f21: no input device found, ignoring\n"); 116 + return -ENXIO; 117 + } 118 + 119 + f21 = devm_kzalloc(&fn->dev, sizeof(*f21), GFP_KERNEL); 120 + if (!f21) 121 + return -ENOMEM; 122 + 123 + f21->input = drv_data->input; 124 + 125 + error = rmi_f21_initialize(fn, f21); 126 + if (error) 127 + return error; 128 + 129 + dev_set_drvdata(&fn->dev, f21); 130 + 131 + sensor_count = fn->fd.query_base_addr & RMI_F21_SENSOR_COUNT_MASK; 132 + if (fn->fd.query_base_addr & RMI_F21_FINGER_COUNT_PRESENT) { 133 + query15_offset = fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT ? 2 : 1; 134 + error = rmi_read_block(fn->rmi_dev, 135 + fn->fd.query_base_addr + query15_offset, 136 + &query15_data, sizeof(query15_data)); 137 + if (error) 138 + return dev_err_probe(&fn->dev, error, 139 + "failed to read 'query15' data"); 140 + 141 + max_fingers = query15_data & RMI_F21_FINGER_COUNT_MASK; 142 + } else { 143 + max_fingers = 5; 144 + } 145 + 146 + if (fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT) { 147 + /* Each finger uses one byte, and the button state uses one byte.*/ 148 + f21->attn_data_size = max_fingers + 1; 149 + f21->attn_data_button_offset = f21->attn_data_size - 1; 150 + /* 151 + * Each sensor uses two bytes, the button state uses one byte, 152 + * and each finger uses two bytes. 153 + */ 154 + f21->data_reg_size = sensor_count * 2 + 1 + max_fingers * 2; 155 + f21->data_reg_button_offset = sensor_count * 2; 156 + } else { 157 + /* 158 + * Regardless of the transport each finger uses two bytes, 159 + * and the button state uses one byte. 160 + */ 161 + f21->attn_data_size = sensor_count * 2 + 1; 162 + f21->attn_data_button_offset = sensor_count * 2; 163 + 164 + f21->data_reg_size = f21->attn_data_size; 165 + f21->data_reg_button_offset = f21->attn_data_button_offset; 166 + } 167 + 168 + return 0; 169 + } 170 + 171 + struct rmi_function_handler rmi_f21_handler = { 172 + .driver = { 173 + .name = "rmi4_f21", 174 + }, 175 + .func = 0x21, 176 + .probe = rmi_f21_probe, 177 + .config = rmi_f21_config, 178 + .attention = rmi_f21_attention, 179 + };
+277
drivers/input/touch-overlay.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Helper functions for overlay objects on touchscreens 4 + * 5 + * Copyright (c) 2023 Javier Carrasco <javier.carrasco@wolfvision.net> 6 + */ 7 + 8 + #include <linux/input.h> 9 + #include <linux/input/mt.h> 10 + #include <linux/input/touch-overlay.h> 11 + #include <linux/list.h> 12 + #include <linux/module.h> 13 + #include <linux/property.h> 14 + 15 + struct touch_overlay_segment { 16 + struct list_head list; 17 + u32 x_origin; 18 + u32 y_origin; 19 + u32 x_size; 20 + u32 y_size; 21 + u32 key; 22 + bool pressed; 23 + int slot; 24 + }; 25 + 26 + static int touch_overlay_get_segment(struct fwnode_handle *segment_node, 27 + struct touch_overlay_segment *segment, 28 + struct input_dev *input) 29 + { 30 + int error; 31 + 32 + error = fwnode_property_read_u32(segment_node, "x-origin", 33 + &segment->x_origin); 34 + if (error) 35 + return error; 36 + 37 + error = fwnode_property_read_u32(segment_node, "y-origin", 38 + &segment->y_origin); 39 + if (error) 40 + return error; 41 + 42 + error = fwnode_property_read_u32(segment_node, "x-size", 43 + &segment->x_size); 44 + if (error) 45 + return error; 46 + 47 + error = fwnode_property_read_u32(segment_node, "y-size", 48 + &segment->y_size); 49 + if (error) 50 + return error; 51 + 52 + error = fwnode_property_read_u32(segment_node, "linux,code", 53 + &segment->key); 54 + if (!error) 55 + input_set_capability(input, EV_KEY, segment->key); 56 + else if (error != -EINVAL) 57 + return error; 58 + 59 + return 0; 60 + } 61 + 62 + /** 63 + * touch_overlay_map - map overlay objects from the device tree and set 64 + * key capabilities if buttons are defined. 65 + * @list: pointer to the list that will hold the segments 66 + * @input: pointer to the already allocated input_dev 67 + * 68 + * Returns 0 on success and error number otherwise. 69 + * 70 + * If buttons are defined, key capabilities are set accordingly. 71 + */ 72 + int touch_overlay_map(struct list_head *list, struct input_dev *input) 73 + { 74 + struct fwnode_handle *fw_segment; 75 + struct device *dev = input->dev.parent; 76 + struct touch_overlay_segment *segment; 77 + int error; 78 + 79 + struct fwnode_handle *overlay __free(fwnode_handle) = 80 + device_get_named_child_node(dev, "touch-overlay"); 81 + if (!overlay) 82 + return 0; 83 + 84 + fwnode_for_each_available_child_node(overlay, fw_segment) { 85 + segment = devm_kzalloc(dev, sizeof(*segment), GFP_KERNEL); 86 + if (!segment) { 87 + fwnode_handle_put(fw_segment); 88 + return -ENOMEM; 89 + } 90 + error = touch_overlay_get_segment(fw_segment, segment, input); 91 + if (error) { 92 + fwnode_handle_put(fw_segment); 93 + return error; 94 + } 95 + list_add_tail(&segment->list, list); 96 + } 97 + 98 + return 0; 99 + } 100 + EXPORT_SYMBOL(touch_overlay_map); 101 + 102 + /** 103 + * touch_overlay_get_touchscreen_abs - get abs size from the touchscreen area. 104 + * @list: pointer to the list that holds the segments 105 + * @x: horizontal abs 106 + * @y: vertical abs 107 + */ 108 + void touch_overlay_get_touchscreen_abs(struct list_head *list, u16 *x, u16 *y) 109 + { 110 + struct touch_overlay_segment *segment; 111 + struct list_head *ptr; 112 + 113 + list_for_each(ptr, list) { 114 + segment = list_entry(ptr, struct touch_overlay_segment, list); 115 + if (!segment->key) { 116 + *x = segment->x_size - 1; 117 + *y = segment->y_size - 1; 118 + break; 119 + } 120 + } 121 + } 122 + EXPORT_SYMBOL(touch_overlay_get_touchscreen_abs); 123 + 124 + static bool touch_overlay_segment_event(struct touch_overlay_segment *seg, 125 + struct input_mt_pos *pos) 126 + { 127 + if (pos->x >= seg->x_origin && pos->x < (seg->x_origin + seg->x_size) && 128 + pos->y >= seg->y_origin && pos->y < (seg->y_origin + seg->y_size)) 129 + return true; 130 + 131 + return false; 132 + } 133 + 134 + /** 135 + * touch_overlay_mapped_touchscreen - check if a touchscreen area is mapped 136 + * @list: pointer to the list that holds the segments 137 + * 138 + * Returns true if a touchscreen area is mapped or false otherwise. 139 + */ 140 + bool touch_overlay_mapped_touchscreen(struct list_head *list) 141 + { 142 + struct touch_overlay_segment *segment; 143 + struct list_head *ptr; 144 + 145 + list_for_each(ptr, list) { 146 + segment = list_entry(ptr, struct touch_overlay_segment, list); 147 + if (!segment->key) 148 + return true; 149 + } 150 + 151 + return false; 152 + } 153 + EXPORT_SYMBOL(touch_overlay_mapped_touchscreen); 154 + 155 + static bool touch_overlay_event_on_ts(struct list_head *list, 156 + struct input_mt_pos *pos) 157 + { 158 + struct touch_overlay_segment *segment; 159 + struct list_head *ptr; 160 + 161 + list_for_each(ptr, list) { 162 + segment = list_entry(ptr, struct touch_overlay_segment, list); 163 + if (segment->key) 164 + continue; 165 + 166 + if (touch_overlay_segment_event(segment, pos)) { 167 + pos->x -= segment->x_origin; 168 + pos->y -= segment->y_origin; 169 + return true; 170 + } 171 + /* ignore touch events outside the defined area */ 172 + return false; 173 + } 174 + 175 + return true; 176 + } 177 + 178 + static bool touch_overlay_button_event(struct input_dev *input, 179 + struct touch_overlay_segment *segment, 180 + struct input_mt_pos *pos, int slot) 181 + { 182 + struct input_mt *mt = input->mt; 183 + struct input_mt_slot *s = &mt->slots[slot]; 184 + bool button_contact = touch_overlay_segment_event(segment, pos); 185 + 186 + if (segment->slot == slot && segment->pressed) { 187 + /* sliding out of the button releases it */ 188 + if (!button_contact) { 189 + input_report_key(input, segment->key, false); 190 + segment->pressed = false; 191 + /* keep available for a possible touch event */ 192 + return false; 193 + } 194 + /* ignore sliding on the button while pressed */ 195 + s->frame = mt->frame; 196 + return true; 197 + } else if (button_contact) { 198 + input_report_key(input, segment->key, true); 199 + s->frame = mt->frame; 200 + segment->slot = slot; 201 + segment->pressed = true; 202 + return true; 203 + } 204 + 205 + return false; 206 + } 207 + 208 + /** 209 + * touch_overlay_sync_frame - update the status of the segments and report 210 + * buttons whose tracked slot is unused. 211 + * @list: pointer to the list that holds the segments 212 + * @input: pointer to the input device associated to the contact 213 + */ 214 + void touch_overlay_sync_frame(struct list_head *list, struct input_dev *input) 215 + { 216 + struct touch_overlay_segment *segment; 217 + struct input_mt *mt = input->mt; 218 + struct input_mt_slot *s; 219 + struct list_head *ptr; 220 + 221 + list_for_each(ptr, list) { 222 + segment = list_entry(ptr, struct touch_overlay_segment, list); 223 + if (!segment->key) 224 + continue; 225 + 226 + s = &mt->slots[segment->slot]; 227 + if (!input_mt_is_used(mt, s) && segment->pressed) { 228 + input_report_key(input, segment->key, false); 229 + segment->pressed = false; 230 + } 231 + } 232 + } 233 + EXPORT_SYMBOL(touch_overlay_sync_frame); 234 + 235 + /** 236 + * touch_overlay_process_contact - process contacts according to the overlay 237 + * mapping. This function acts as a filter to release the calling driver 238 + * from the contacts that are either related to overlay buttons or out of the 239 + * overlay touchscreen area, if defined. 240 + * @list: pointer to the list that holds the segments 241 + * @input: pointer to the input device associated to the contact 242 + * @pos: pointer to the contact position 243 + * @slot: slot associated to the contact (0 if multitouch is not supported) 244 + * 245 + * Returns true if the contact was processed (reported for valid key events 246 + * and dropped for contacts outside the overlay touchscreen area) or false 247 + * if the contact must be processed by the caller. In that case this function 248 + * shifts the (x,y) coordinates to the overlay touchscreen axis if required. 249 + */ 250 + bool touch_overlay_process_contact(struct list_head *list, 251 + struct input_dev *input, 252 + struct input_mt_pos *pos, int slot) 253 + { 254 + struct touch_overlay_segment *segment; 255 + struct list_head *ptr; 256 + 257 + /* 258 + * buttons must be prioritized over overlay touchscreens to account for 259 + * overlappings e.g. a button inside the touchscreen area. 260 + */ 261 + list_for_each(ptr, list) { 262 + segment = list_entry(ptr, struct touch_overlay_segment, list); 263 + if (segment->key && 264 + touch_overlay_button_event(input, segment, pos, slot)) 265 + return true; 266 + } 267 + 268 + /* 269 + * valid contacts on the overlay touchscreen are left for the client 270 + * to be processed/reported according to its (possibly) unique features. 271 + */ 272 + return !touch_overlay_event_on_ts(list, pos); 273 + } 274 + EXPORT_SYMBOL(touch_overlay_process_contact); 275 + 276 + MODULE_LICENSE("GPL"); 277 + MODULE_DESCRIPTION("Helper functions for overlay objects on touch devices");
+7 -4
drivers/input/touchscreen/ad7879.c
··· 444 444 return !!(val & AD7879_GPIO_DATA); 445 445 } 446 446 447 - static void ad7879_gpio_set_value(struct gpio_chip *chip, 448 - unsigned gpio, int value) 447 + static int ad7879_gpio_set_value(struct gpio_chip *chip, unsigned int gpio, 448 + int value) 449 449 { 450 450 struct ad7879 *ts = gpiochip_get_data(chip); 451 + int ret; 451 452 452 453 mutex_lock(&ts->mutex); 453 454 if (value) ··· 456 455 else 457 456 ts->cmd_crtl2 &= ~AD7879_GPIO_DATA; 458 457 459 - ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); 458 + ret = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); 460 459 mutex_unlock(&ts->mutex); 460 + 461 + return ret; 461 462 } 462 463 463 464 static int ad7879_gpio_add(struct ad7879 *ts) ··· 475 472 ts->gc.direction_input = ad7879_gpio_direction_input; 476 473 ts->gc.direction_output = ad7879_gpio_direction_output; 477 474 ts->gc.get = ad7879_gpio_get_value; 478 - ts->gc.set = ad7879_gpio_set_value; 475 + ts->gc.set_rv = ad7879_gpio_set_value; 479 476 ts->gc.can_sleep = 1; 480 477 ts->gc.base = -1; 481 478 ts->gc.ngpio = 1;
+14 -12
drivers/input/touchscreen/edt-ft5x06.c
··· 120 120 struct regmap *regmap; 121 121 122 122 #if defined(CONFIG_DEBUG_FS) 123 - struct dentry *debug_dir; 124 123 u8 *raw_buffer; 125 124 size_t raw_bufsize; 126 125 #endif ··· 814 815 .read = edt_ft5x06_debugfs_raw_data_read, 815 816 }; 816 817 817 - static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, 818 - const char *debugfs_name) 818 + static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata) 819 819 { 820 - tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); 820 + struct dentry *debug_dir = tsdata->client->debugfs; 821 821 822 - debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); 823 - debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); 822 + debugfs_create_u16("num_x", S_IRUSR, debug_dir, &tsdata->num_x); 823 + debugfs_create_u16("num_y", S_IRUSR, debug_dir, &tsdata->num_y); 824 824 825 825 debugfs_create_file("mode", S_IRUSR | S_IWUSR, 826 - tsdata->debug_dir, tsdata, &debugfs_mode_fops); 826 + debug_dir, tsdata, &debugfs_mode_fops); 827 827 debugfs_create_file("raw_data", S_IRUSR, 828 - tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); 828 + debug_dir, tsdata, &debugfs_raw_data_fops); 829 829 } 830 830 831 831 static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) 832 832 { 833 - debugfs_remove_recursive(tsdata->debug_dir); 834 833 kfree(tsdata->raw_buffer); 835 834 } 836 835 ··· 839 842 return -ENOSYS; 840 843 } 841 844 842 - static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, 843 - const char *debugfs_name) 845 + static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata) 844 846 { 845 847 } 846 848 ··· 1345 1349 if (error) 1346 1350 return error; 1347 1351 1348 - edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); 1352 + edt_ft5x06_ts_prepare_debugfs(tsdata); 1349 1353 1350 1354 dev_dbg(&client->dev, 1351 1355 "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", ··· 1491 1495 .max_support_points = 10, 1492 1496 }; 1493 1497 1498 + static const struct edt_i2c_chip_data edt_ft8716_data = { 1499 + .max_support_points = 10, 1500 + }; 1501 + 1494 1502 static const struct edt_i2c_chip_data edt_ft8719_data = { 1495 1503 .max_support_points = 10, 1496 1504 }; ··· 1507 1507 /* Note no edt- prefix for compatibility with the ft6236.c driver */ 1508 1508 { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, 1509 1509 { .name = "ft8201", .driver_data = (long)&edt_ft8201_data }, 1510 + { .name = "ft8716", .driver_data = (long)&edt_ft8716_data }, 1510 1511 { .name = "ft8719", .driver_data = (long)&edt_ft8719_data }, 1511 1512 { /* sentinel */ } 1512 1513 }; ··· 1524 1523 /* Note focaltech vendor prefix for compatibility with ft6236.c */ 1525 1524 { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, 1526 1525 { .compatible = "focaltech,ft8201", .data = &edt_ft8201_data }, 1526 + { .compatible = "focaltech,ft8716", .data = &edt_ft8716_data }, 1527 1527 { .compatible = "focaltech,ft8719", .data = &edt_ft8719_data }, 1528 1528 { /* sentinel */ } 1529 1529 };
+44 -6
drivers/input/touchscreen/goodix.c
··· 44 44 #define GOODIX_HAVE_KEY BIT(4) 45 45 #define GOODIX_BUFFER_STATUS_TIMEOUT 20 46 46 47 - #define RESOLUTION_LOC 1 48 - #define MAX_CONTACTS_LOC 5 49 - #define TRIGGER_LOC 6 47 + #define RESOLUTION_LOC 1 48 + #define MAX_CONTACTS_LOC 5 49 + #define TRIGGER_LOC 6 50 + 51 + #define GOODIX_POLL_INTERVAL_MS 17 /* 17ms = 60fps */ 50 52 51 53 /* Our special handling for GPIO accesses through ACPI is x86 specific */ 52 54 #if defined CONFIG_X86 && defined CONFIG_ACPI ··· 499 497 input_sync(ts->input_dev); 500 498 } 501 499 500 + static void goodix_ts_work_i2c_poll(struct input_dev *input) 501 + { 502 + struct goodix_ts_data *ts = input_get_drvdata(input); 503 + 504 + goodix_process_events(ts); 505 + goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0); 506 + } 507 + 502 508 /** 503 509 * goodix_ts_irq_handler - The IRQ handler 504 510 * ··· 523 513 return IRQ_HANDLED; 524 514 } 525 515 516 + static void goodix_enable_irq(struct goodix_ts_data *ts) 517 + { 518 + if (ts->client->irq) 519 + enable_irq(ts->client->irq); 520 + } 521 + 522 + static void goodix_disable_irq(struct goodix_ts_data *ts) 523 + { 524 + if (ts->client->irq) 525 + disable_irq(ts->client->irq); 526 + } 527 + 526 528 static void goodix_free_irq(struct goodix_ts_data *ts) 527 529 { 528 - devm_free_irq(&ts->client->dev, ts->client->irq, ts); 530 + if (ts->client->irq) 531 + devm_free_irq(&ts->client->dev, ts->client->irq, ts); 529 532 } 530 533 531 534 static int goodix_request_irq(struct goodix_ts_data *ts) 532 535 { 536 + if (!ts->client->irq) 537 + return 0; 538 + 533 539 return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, 534 540 NULL, goodix_ts_irq_handler, 535 541 ts->irq_flags, ts->client->name, ts); ··· 1245 1219 return error; 1246 1220 } 1247 1221 1222 + input_set_drvdata(ts->input_dev, ts); 1223 + 1224 + if (!ts->client->irq) { 1225 + error = input_setup_polling(ts->input_dev, goodix_ts_work_i2c_poll); 1226 + if (error) { 1227 + dev_err(&ts->client->dev, 1228 + "could not set up polling mode, %d\n", error); 1229 + return error; 1230 + } 1231 + input_set_poll_interval(ts->input_dev, GOODIX_POLL_INTERVAL_MS); 1232 + } 1233 + 1248 1234 error = input_register_device(ts->input_dev); 1249 1235 if (error) { 1250 1236 dev_err(&ts->client->dev, ··· 1460 1422 1461 1423 /* We need gpio pins to suspend/resume */ 1462 1424 if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { 1463 - disable_irq(client->irq); 1425 + goodix_disable_irq(ts); 1464 1426 return 0; 1465 1427 } 1466 1428 ··· 1504 1466 int error; 1505 1467 1506 1468 if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { 1507 - enable_irq(client->irq); 1469 + goodix_enable_irq(ts); 1508 1470 return 0; 1509 1471 } 1510 1472
+27 -8
drivers/input/touchscreen/st1232.c
··· 22 22 #include <linux/pm_qos.h> 23 23 #include <linux/slab.h> 24 24 #include <linux/types.h> 25 + #include <linux/input/touch-overlay.h> 25 26 26 27 #define ST1232_TS_NAME "st1232-ts" 27 28 #define ST1633_TS_NAME "st1633-ts" ··· 58 57 struct dev_pm_qos_request low_latency_req; 59 58 struct gpio_desc *reset_gpio; 60 59 const struct st_chip_info *chip_info; 60 + struct list_head touch_overlay_list; 61 61 int read_buf_len; 62 62 u8 *read_buf; 63 63 }; ··· 158 156 159 157 input_mt_assign_slots(input, slots, pos, n_contacts, 0); 160 158 for (i = 0; i < n_contacts; i++) { 159 + if (touch_overlay_process_contact(&ts->touch_overlay_list, 160 + input, &pos[i], slots[i])) 161 + continue; 162 + 161 163 input_mt_slot(input, slots[i]); 162 164 input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 163 165 input_report_abs(input, ABS_MT_POSITION_X, pos[i].x); ··· 170 164 input_report_abs(input, ABS_MT_TOUCH_MAJOR, z[i]); 171 165 } 172 166 167 + touch_overlay_sync_frame(&ts->touch_overlay_list, input); 173 168 input_mt_sync_frame(input); 174 169 input_sync(input); 175 170 ··· 299 292 if (error) 300 293 return error; 301 294 302 - /* Read resolution from the chip */ 303 - error = st1232_ts_read_resolution(ts, &max_x, &max_y); 304 - if (error) { 305 - dev_err(&client->dev, 306 - "Failed to read resolution: %d\n", error); 307 - return error; 308 - } 309 - 310 295 if (ts->chip_info->have_z) 311 296 input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 312 297 ts->chip_info->max_area, 0, 0); 298 + 299 + /* map overlay objects if defined in the device tree */ 300 + INIT_LIST_HEAD(&ts->touch_overlay_list); 301 + error = touch_overlay_map(&ts->touch_overlay_list, input_dev); 302 + if (error) 303 + return error; 304 + 305 + if (touch_overlay_mapped_touchscreen(&ts->touch_overlay_list)) { 306 + /* Read resolution from the overlay touchscreen if defined */ 307 + touch_overlay_get_touchscreen_abs(&ts->touch_overlay_list, 308 + &max_x, &max_y); 309 + } else { 310 + /* Read resolution from the chip */ 311 + error = st1232_ts_read_resolution(ts, &max_x, &max_y); 312 + if (error) { 313 + dev_err(&client->dev, 314 + "Failed to read resolution: %d\n", error); 315 + return error; 316 + } 317 + } 313 318 314 319 input_set_abs_params(input_dev, ABS_MT_POSITION_X, 315 320 0, max_x, 0, 0);
+6 -3
drivers/md/dm-flakey.c
··· 215 215 } 216 216 217 217 if (test_bit(DROP_WRITES, &fc->flags) && 218 - (fc->corrupt_bio_rw == WRITE || fc->random_write_corrupt)) { 218 + ((fc->corrupt_bio_byte && fc->corrupt_bio_rw == WRITE) || 219 + fc->random_write_corrupt)) { 219 220 ti->error = "drop_writes is incompatible with random_write_corrupt or corrupt_bio_byte with the WRITE flag set"; 220 221 return -EINVAL; 221 222 222 223 } else if (test_bit(ERROR_WRITES, &fc->flags) && 223 - (fc->corrupt_bio_rw == WRITE || fc->random_write_corrupt)) { 224 + ((fc->corrupt_bio_byte && fc->corrupt_bio_rw == WRITE) || 225 + fc->random_write_corrupt)) { 224 226 ti->error = "error_writes is incompatible with random_write_corrupt or corrupt_bio_byte with the WRITE flag set"; 225 227 return -EINVAL; 226 228 } else if (test_bit(ERROR_READS, &fc->flags) && 227 - (fc->corrupt_bio_rw == READ || fc->random_read_corrupt)) { 229 + ((fc->corrupt_bio_byte && fc->corrupt_bio_rw == READ) || 230 + fc->random_read_corrupt)) { 228 231 ti->error = "error_reads is incompatible with random_read_corrupt or corrupt_bio_byte with the READ flag set"; 229 232 return -EINVAL; 230 233 }
+19 -23
drivers/md/dm-ima.c
··· 241 241 /* 242 242 * First retrieve the target metadata. 243 243 */ 244 - scnprintf(target_metadata_buf, DM_IMA_TARGET_METADATA_BUF_LEN, 245 - "target_index=%d,target_begin=%llu,target_len=%llu,", 246 - i, ti->begin, ti->len); 247 - target_metadata_buf_len = strlen(target_metadata_buf); 244 + target_metadata_buf_len = 245 + scnprintf(target_metadata_buf, 246 + DM_IMA_TARGET_METADATA_BUF_LEN, 247 + "target_index=%d,target_begin=%llu,target_len=%llu,", 248 + i, ti->begin, ti->len); 248 249 249 250 /* 250 251 * Then retrieve the actual target data. ··· 449 448 if (r) 450 449 goto error; 451 450 452 - scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, 453 - "%sname=%s,uuid=%s;device_resume=no_data;", 454 - DM_IMA_VERSION_STR, dev_name, dev_uuid); 455 - l = strlen(device_table_data); 456 - 451 + l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, 452 + "%sname=%s,uuid=%s;device_resume=no_data;", 453 + DM_IMA_VERSION_STR, dev_name, dev_uuid); 457 454 } 458 455 459 456 capacity_len = strlen(capacity_str); ··· 560 561 if (dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio)) 561 562 goto error; 562 563 563 - scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, 564 - "%sname=%s,uuid=%s;device_remove=no_data;", 565 - DM_IMA_VERSION_STR, dev_name, dev_uuid); 566 - l = strlen(device_table_data); 564 + l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, 565 + "%sname=%s,uuid=%s;device_remove=no_data;", 566 + DM_IMA_VERSION_STR, dev_name, dev_uuid); 567 567 } 568 568 569 569 memcpy(device_table_data + l, remove_all_str, remove_all_len); ··· 645 647 if (dm_ima_alloc_and_copy_name_uuid(md, &dev_name, &dev_uuid, noio)) 646 648 goto error2; 647 649 648 - scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, 649 - "%sname=%s,uuid=%s;table_clear=no_data;", 650 - DM_IMA_VERSION_STR, dev_name, dev_uuid); 651 - l = strlen(device_table_data); 650 + l = scnprintf(device_table_data, DM_IMA_DEVICE_BUF_LEN, 651 + "%sname=%s,uuid=%s;table_clear=no_data;", 652 + DM_IMA_VERSION_STR, dev_name, dev_uuid); 652 653 } 653 654 654 655 capacity_len = strlen(capacity_str); ··· 703 706 char *old_device_data = NULL, *new_device_data = NULL, *combined_device_data = NULL; 704 707 char *new_dev_name = NULL, *new_dev_uuid = NULL, *capacity_str = NULL; 705 708 bool noio = true; 706 - int r; 709 + int r, len; 707 710 708 711 if (dm_ima_alloc_and_copy_device_data(md, &new_device_data, 709 712 md->ima.active_table.num_targets, noio)) ··· 725 728 md->ima.active_table.device_metadata = new_device_data; 726 729 md->ima.active_table.device_metadata_len = strlen(new_device_data); 727 730 728 - scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2, 729 - "%s%snew_name=%s,new_uuid=%s;%s", DM_IMA_VERSION_STR, old_device_data, 730 - new_dev_name, new_dev_uuid, capacity_str); 731 + len = scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2, 732 + "%s%snew_name=%s,new_uuid=%s;%s", DM_IMA_VERSION_STR, old_device_data, 733 + new_dev_name, new_dev_uuid, capacity_str); 731 734 732 - dm_ima_measure_data("dm_device_rename", combined_device_data, strlen(combined_device_data), 733 - noio); 735 + dm_ima_measure_data("dm_device_rename", combined_device_data, len, noio); 734 736 735 737 goto exit; 736 738
+3 -5
drivers/md/dm-path-selector.c
··· 117 117 } 118 118 EXPORT_SYMBOL_GPL(dm_register_path_selector); 119 119 120 - int dm_unregister_path_selector(struct path_selector_type *pst) 120 + void dm_unregister_path_selector(struct path_selector_type *pst) 121 121 { 122 122 struct ps_internal *psi; 123 123 124 124 down_write(&_ps_lock); 125 125 126 126 psi = __find_path_selector_type(pst->name); 127 - if (!psi) { 127 + if (WARN_ON(!psi)) { 128 128 up_write(&_ps_lock); 129 - return -EINVAL; 129 + return; 130 130 } 131 131 132 132 list_del(&psi->list); ··· 134 134 up_write(&_ps_lock); 135 135 136 136 kfree(psi); 137 - 138 - return 0; 139 137 } 140 138 EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
+1 -1
drivers/md/dm-path-selector.h
··· 96 96 int dm_register_path_selector(struct path_selector_type *type); 97 97 98 98 /* Unregister a path selector */ 99 - int dm_unregister_path_selector(struct path_selector_type *type); 99 + void dm_unregister_path_selector(struct path_selector_type *type); 100 100 101 101 /* Returns a registered path selector type */ 102 102 struct path_selector_type *dm_get_path_selector(const char *name);
+4 -5
drivers/md/dm-ps-historical-service-time.c
··· 541 541 { 542 542 int r = dm_register_path_selector(&hst_ps); 543 543 544 - if (r < 0) 544 + if (r < 0) { 545 545 DMERR("register failed %d", r); 546 + return r; 547 + } 546 548 547 549 DMINFO("version " HST_VERSION " loaded"); 548 550 ··· 553 551 554 552 static void __exit dm_hst_exit(void) 555 553 { 556 - int r = dm_unregister_path_selector(&hst_ps); 557 - 558 - if (r < 0) 559 - DMERR("unregister failed %d", r); 554 + dm_unregister_path_selector(&hst_ps); 560 555 } 561 556 562 557 module_init(dm_hst_init);
+1 -4
drivers/md/dm-ps-io-affinity.c
··· 260 260 261 261 static void __exit dm_ioa_exit(void) 262 262 { 263 - int ret = dm_unregister_path_selector(&ioa_ps); 264 - 265 - if (ret < 0) 266 - DMERR("unregister failed %d", ret); 263 + dm_unregister_path_selector(&ioa_ps); 267 264 } 268 265 269 266 module_init(dm_ioa_init);
+4 -5
drivers/md/dm-ps-queue-length.c
··· 260 260 { 261 261 int r = dm_register_path_selector(&ql_ps); 262 262 263 - if (r < 0) 263 + if (r < 0) { 264 264 DMERR("register failed %d", r); 265 + return r; 266 + } 265 267 266 268 DMINFO("version " QL_VERSION " loaded"); 267 269 ··· 272 270 273 271 static void __exit dm_ql_exit(void) 274 272 { 275 - int r = dm_unregister_path_selector(&ql_ps); 276 - 277 - if (r < 0) 278 - DMERR("unregister failed %d", r); 273 + dm_unregister_path_selector(&ql_ps); 279 274 } 280 275 281 276 module_init(dm_ql_init);
+4 -5
drivers/md/dm-ps-round-robin.c
··· 220 220 { 221 221 int r = dm_register_path_selector(&rr_ps); 222 222 223 - if (r < 0) 223 + if (r < 0) { 224 224 DMERR("register failed %d", r); 225 + return r; 226 + } 225 227 226 228 DMINFO("version " RR_VERSION " loaded"); 227 229 ··· 232 230 233 231 static void __exit dm_rr_exit(void) 234 232 { 235 - int r = dm_unregister_path_selector(&rr_ps); 236 - 237 - if (r < 0) 238 - DMERR("unregister failed %d", r); 233 + dm_unregister_path_selector(&rr_ps); 239 234 } 240 235 241 236 module_init(dm_rr_init);
+4 -5
drivers/md/dm-ps-service-time.c
··· 341 341 { 342 342 int r = dm_register_path_selector(&st_ps); 343 343 344 - if (r < 0) 344 + if (r < 0) { 345 345 DMERR("register failed %d", r); 346 + return r; 347 + } 346 348 347 349 DMINFO("version " ST_VERSION " loaded"); 348 350 ··· 353 351 354 352 static void __exit dm_st_exit(void) 355 353 { 356 - int r = dm_unregister_path_selector(&st_ps); 357 - 358 - if (r < 0) 359 - DMERR("unregister failed %d", r); 354 + dm_unregister_path_selector(&st_ps); 360 355 } 361 356 362 357 module_init(dm_st_init);
+5 -2
drivers/md/dm-raid.c
··· 14 14 #include "raid5.h" 15 15 #include "raid10.h" 16 16 #include "md-bitmap.h" 17 - #include "dm-core.h" 18 17 19 18 #include <linux/device-mapper.h> 20 19 ··· 2531 2532 struct md_rdev *rdev, *freshest; 2532 2533 struct mddev *mddev = &rs->md; 2533 2534 2535 + /* Respect resynchronization requested with "sync" argument. */ 2536 + if (test_bit(__CTR_FLAG_SYNC, &rs->ctr_flags)) 2537 + set_bit(MD_ARRAY_FIRST_USE, &mddev->flags); 2538 + 2534 2539 freshest = NULL; 2535 2540 rdev_for_each(rdev, mddev) { 2536 2541 if (test_bit(Journal, &rdev->flags)) ··· 3308 3305 3309 3306 /* Disable/enable discard support on raid set. */ 3310 3307 configure_discard_support(rs); 3311 - rs->md.dm_gendisk = ti->table->md->disk; 3308 + rs->md.dm_gendisk = dm_disk(dm_table_get_md(ti->table)); 3312 3309 3313 3310 mddev_unlock(&rs->md); 3314 3311 return 0;
+5 -5
drivers/md/dm-table.c
··· 899 899 return true; 900 900 } 901 901 902 - static int device_is_rq_stackable(struct dm_target *ti, struct dm_dev *dev, 903 - sector_t start, sector_t len, void *data) 902 + static int device_is_not_rq_stackable(struct dm_target *ti, struct dm_dev *dev, 903 + sector_t start, sector_t len, void *data) 904 904 { 905 905 struct block_device *bdev = dev->bdev; 906 906 struct request_queue *q = bdev_get_queue(bdev); 907 907 908 908 /* request-based cannot stack on partitions! */ 909 909 if (bdev_is_partition(bdev)) 910 - return false; 910 + return true; 911 911 912 - return queue_is_mq(q); 912 + return !queue_is_mq(q); 913 913 } 914 914 915 915 static int dm_table_determine_type(struct dm_table *t) ··· 1005 1005 1006 1006 /* Non-request-stackable devices can't be used for request-based dm */ 1007 1007 if (!ti->type->iterate_devices || 1008 - !ti->type->iterate_devices(ti, device_is_rq_stackable, NULL)) { 1008 + ti->type->iterate_devices(ti, device_is_not_rq_stackable, NULL)) { 1009 1009 DMERR("table load rejected: including non-request-stackable devices"); 1010 1010 return -EINVAL; 1011 1011 }
+4 -3
drivers/md/dm-thin.c
··· 4111 4111 static struct target_type pool_target = { 4112 4112 .name = "thin-pool", 4113 4113 .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | 4114 - DM_TARGET_IMMUTABLE, 4115 - .version = {1, 23, 0}, 4114 + DM_TARGET_IMMUTABLE | DM_TARGET_PASSES_CRYPTO, 4115 + .version = {1, 24, 0}, 4116 4116 .module = THIS_MODULE, 4117 4117 .ctr = pool_ctr, 4118 4118 .dtr = pool_dtr, ··· 4497 4497 4498 4498 static struct target_type thin_target = { 4499 4499 .name = "thin", 4500 - .version = {1, 23, 0}, 4500 + .features = DM_TARGET_PASSES_CRYPTO, 4501 + .version = {1, 24, 0}, 4501 4502 .module = THIS_MODULE, 4502 4503 .ctr = thin_ctr, 4503 4504 .dtr = thin_dtr,
+1 -2
drivers/md/dm-vdo/funnel-workqueue.c
··· 252 252 * This speeds up some performance tests; that "other work" might include other VDO 253 253 * threads. 254 254 */ 255 - if (need_resched()) 256 - cond_resched(); 255 + cond_resched(); 257 256 } 258 257 259 258 run_finish_hook(queue);
+2 -2
drivers/md/dm-verity-fec.c
··· 191 191 u8 *want_digest, u8 *data) 192 192 { 193 193 if (unlikely(verity_hash(v, io, data, 1 << v->data_dev_block_bits, 194 - verity_io_real_digest(v, io), true))) 194 + verity_io_real_digest(v, io)))) 195 195 return 0; 196 196 197 197 return memcmp(verity_io_real_digest(v, io), want_digest, ··· 392 392 393 393 /* Always re-validate the corrected block against the expected hash */ 394 394 r = verity_hash(v, io, fio->output, 1 << v->data_dev_block_bits, 395 - verity_io_real_digest(v, io), true); 395 + verity_io_real_digest(v, io)); 396 396 if (unlikely(r < 0)) 397 397 return r; 398 398
+29 -156
drivers/md/dm-verity-target.c
··· 19 19 #include "dm-audit.h" 20 20 #include <linux/module.h> 21 21 #include <linux/reboot.h> 22 - #include <linux/scatterlist.h> 23 22 #include <linux/string.h> 24 23 #include <linux/jump_label.h> 25 24 #include <linux/security.h> ··· 59 60 module_param_array_named(use_bh_bytes, dm_verity_use_bh_bytes, uint, NULL, 0644); 60 61 61 62 static DEFINE_STATIC_KEY_FALSE(use_bh_wq_enabled); 62 - 63 - /* Is at least one dm-verity instance using ahash_tfm instead of shash_tfm? */ 64 - static DEFINE_STATIC_KEY_FALSE(ahash_enabled); 65 63 66 64 struct dm_verity_prefetch_work { 67 65 struct work_struct work; ··· 114 118 return block >> (level * v->hash_per_block_bits); 115 119 } 116 120 117 - static int verity_ahash_update(struct dm_verity *v, struct ahash_request *req, 118 - const u8 *data, size_t len, 119 - struct crypto_wait *wait) 120 - { 121 - struct scatterlist sg; 122 - 123 - if (likely(!is_vmalloc_addr(data))) { 124 - sg_init_one(&sg, data, len); 125 - ahash_request_set_crypt(req, &sg, NULL, len); 126 - return crypto_wait_req(crypto_ahash_update(req), wait); 127 - } 128 - 129 - do { 130 - int r; 131 - size_t this_step = min_t(size_t, len, PAGE_SIZE - offset_in_page(data)); 132 - 133 - flush_kernel_vmap_range((void *)data, this_step); 134 - sg_init_table(&sg, 1); 135 - sg_set_page(&sg, vmalloc_to_page(data), this_step, offset_in_page(data)); 136 - ahash_request_set_crypt(req, &sg, NULL, this_step); 137 - r = crypto_wait_req(crypto_ahash_update(req), wait); 138 - if (unlikely(r)) 139 - return r; 140 - data += this_step; 141 - len -= this_step; 142 - } while (len); 143 - 144 - return 0; 145 - } 146 - 147 - /* 148 - * Wrapper for crypto_ahash_init, which handles verity salting. 149 - */ 150 - static int verity_ahash_init(struct dm_verity *v, struct ahash_request *req, 151 - struct crypto_wait *wait, bool may_sleep) 152 - { 153 - int r; 154 - 155 - ahash_request_set_tfm(req, v->ahash_tfm); 156 - ahash_request_set_callback(req, 157 - may_sleep ? CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG : 0, 158 - crypto_req_done, (void *)wait); 159 - crypto_init_wait(wait); 160 - 161 - r = crypto_wait_req(crypto_ahash_init(req), wait); 162 - 163 - if (unlikely(r < 0)) { 164 - if (r != -ENOMEM) 165 - DMERR("crypto_ahash_init failed: %d", r); 166 - return r; 167 - } 168 - 169 - if (likely(v->salt_size && (v->version >= 1))) 170 - r = verity_ahash_update(v, req, v->salt, v->salt_size, wait); 171 - 172 - return r; 173 - } 174 - 175 - static int verity_ahash_final(struct dm_verity *v, struct ahash_request *req, 176 - u8 *digest, struct crypto_wait *wait) 177 - { 178 - int r; 179 - 180 - if (unlikely(v->salt_size && (!v->version))) { 181 - r = verity_ahash_update(v, req, v->salt, v->salt_size, wait); 182 - 183 - if (r < 0) { 184 - DMERR("%s failed updating salt: %d", __func__, r); 185 - goto out; 186 - } 187 - } 188 - 189 - ahash_request_set_crypt(req, NULL, digest, 0); 190 - r = crypto_wait_req(crypto_ahash_final(req), wait); 191 - out: 192 - return r; 193 - } 194 - 195 121 int verity_hash(struct dm_verity *v, struct dm_verity_io *io, 196 - const u8 *data, size_t len, u8 *digest, bool may_sleep) 122 + const u8 *data, size_t len, u8 *digest) 197 123 { 124 + struct shash_desc *desc = &io->hash_desc; 198 125 int r; 199 126 200 - if (static_branch_unlikely(&ahash_enabled) && !v->shash_tfm) { 201 - struct ahash_request *req = verity_io_hash_req(v, io); 202 - struct crypto_wait wait; 203 - 204 - r = verity_ahash_init(v, req, &wait, may_sleep) ?: 205 - verity_ahash_update(v, req, data, len, &wait) ?: 206 - verity_ahash_final(v, req, digest, &wait); 127 + desc->tfm = v->shash_tfm; 128 + if (unlikely(v->initial_hashstate == NULL)) { 129 + /* Version 0: salt at end */ 130 + r = crypto_shash_init(desc) ?: 131 + crypto_shash_update(desc, data, len) ?: 132 + crypto_shash_update(desc, v->salt, v->salt_size) ?: 133 + crypto_shash_final(desc, digest); 207 134 } else { 208 - struct shash_desc *desc = verity_io_hash_req(v, io); 209 - 210 - desc->tfm = v->shash_tfm; 135 + /* Version 1: salt at beginning */ 211 136 r = crypto_shash_import(desc, v->initial_hashstate) ?: 212 137 crypto_shash_finup(desc, data, len, digest); 213 138 } ··· 279 362 } 280 363 281 364 r = verity_hash(v, io, data, 1 << v->hash_dev_block_bits, 282 - verity_io_real_digest(v, io), !io->in_bh); 365 + verity_io_real_digest(v, io)); 283 366 if (unlikely(r < 0)) 284 367 goto release_ret_r; 285 368 ··· 382 465 goto free_ret; 383 466 384 467 r = verity_hash(v, io, buffer, 1 << v->data_dev_block_bits, 385 - verity_io_real_digest(v, io), true); 468 + verity_io_real_digest(v, io)); 386 469 if (unlikely(r)) 387 470 goto free_ret; 388 471 ··· 498 581 } 499 582 500 583 r = verity_hash(v, io, data, block_size, 501 - verity_io_real_digest(v, io), !io->in_bh); 584 + verity_io_real_digest(v, io)); 502 585 if (unlikely(r < 0)) { 503 586 kunmap_local(data); 504 587 return r; ··· 1009 1092 kfree(v->zero_digest); 1010 1093 verity_free_sig(v); 1011 1094 1012 - if (v->ahash_tfm) { 1013 - static_branch_dec(&ahash_enabled); 1014 - crypto_free_ahash(v->ahash_tfm); 1015 - } else { 1016 - crypto_free_shash(v->shash_tfm); 1017 - } 1095 + crypto_free_shash(v->shash_tfm); 1018 1096 1019 1097 kfree(v->alg_name); 1020 1098 ··· 1069 1157 if (!v->zero_digest) 1070 1158 return r; 1071 1159 1072 - io = kmalloc(sizeof(*io) + v->hash_reqsize, GFP_KERNEL); 1160 + io = kmalloc(sizeof(*io) + crypto_shash_descsize(v->shash_tfm), 1161 + GFP_KERNEL); 1073 1162 1074 1163 if (!io) 1075 1164 return r; /* verity_dtr will free zero_digest */ ··· 1081 1168 goto out; 1082 1169 1083 1170 r = verity_hash(v, io, zero_data, 1 << v->data_dev_block_bits, 1084 - v->zero_digest, true); 1171 + v->zero_digest); 1085 1172 1086 1173 out: 1087 1174 kfree(io); ··· 1237 1324 static int verity_setup_hash_alg(struct dm_verity *v, const char *alg_name) 1238 1325 { 1239 1326 struct dm_target *ti = v->ti; 1240 - struct crypto_ahash *ahash; 1241 - struct crypto_shash *shash = NULL; 1242 - const char *driver_name; 1327 + struct crypto_shash *shash; 1243 1328 1244 1329 v->alg_name = kstrdup(alg_name, GFP_KERNEL); 1245 1330 if (!v->alg_name) { ··· 1245 1334 return -ENOMEM; 1246 1335 } 1247 1336 1248 - /* 1249 - * Allocate the hash transformation object that this dm-verity instance 1250 - * will use. The vast majority of dm-verity users use CPU-based 1251 - * hashing, so when possible use the shash API to minimize the crypto 1252 - * API overhead. If the ahash API resolves to a different driver 1253 - * (likely an off-CPU hardware offload), use ahash instead. Also use 1254 - * ahash if the obsolete dm-verity format with the appended salt is 1255 - * being used, so that quirk only needs to be handled in one place. 1256 - */ 1257 - ahash = crypto_alloc_ahash(alg_name, 0, 1258 - v->use_bh_wq ? CRYPTO_ALG_ASYNC : 0); 1259 - if (IS_ERR(ahash)) { 1337 + shash = crypto_alloc_shash(alg_name, 0, 0); 1338 + if (IS_ERR(shash)) { 1260 1339 ti->error = "Cannot initialize hash function"; 1261 - return PTR_ERR(ahash); 1340 + return PTR_ERR(shash); 1262 1341 } 1263 - driver_name = crypto_ahash_driver_name(ahash); 1264 - if (v->version >= 1 /* salt prepended, not appended? */) { 1265 - shash = crypto_alloc_shash(alg_name, 0, 0); 1266 - if (!IS_ERR(shash) && 1267 - strcmp(crypto_shash_driver_name(shash), driver_name) != 0) { 1268 - /* 1269 - * ahash gave a different driver than shash, so probably 1270 - * this is a case of real hardware offload. Use ahash. 1271 - */ 1272 - crypto_free_shash(shash); 1273 - shash = NULL; 1274 - } 1275 - } 1276 - if (!IS_ERR_OR_NULL(shash)) { 1277 - crypto_free_ahash(ahash); 1278 - ahash = NULL; 1279 - v->shash_tfm = shash; 1280 - v->digest_size = crypto_shash_digestsize(shash); 1281 - v->hash_reqsize = sizeof(struct shash_desc) + 1282 - crypto_shash_descsize(shash); 1283 - DMINFO("%s using shash \"%s\"", alg_name, driver_name); 1284 - } else { 1285 - v->ahash_tfm = ahash; 1286 - static_branch_inc(&ahash_enabled); 1287 - v->digest_size = crypto_ahash_digestsize(ahash); 1288 - v->hash_reqsize = sizeof(struct ahash_request) + 1289 - crypto_ahash_reqsize(ahash); 1290 - DMINFO("%s using ahash \"%s\"", alg_name, driver_name); 1291 - } 1342 + v->shash_tfm = shash; 1343 + v->digest_size = crypto_shash_digestsize(shash); 1344 + DMINFO("%s using \"%s\"", alg_name, crypto_shash_driver_name(shash)); 1292 1345 if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) { 1293 1346 ti->error = "Digest size too big"; 1294 1347 return -EINVAL; ··· 1277 1402 return -EINVAL; 1278 1403 } 1279 1404 } 1280 - if (v->shash_tfm) { 1405 + if (v->version) { /* Version 1: salt at beginning */ 1281 1406 SHASH_DESC_ON_STACK(desc, v->shash_tfm); 1282 1407 int r; 1283 1408 ··· 1556 1681 goto bad; 1557 1682 } 1558 1683 1559 - ti->per_io_data_size = sizeof(struct dm_verity_io) + v->hash_reqsize; 1684 + ti->per_io_data_size = sizeof(struct dm_verity_io) + 1685 + crypto_shash_descsize(v->shash_tfm); 1560 1686 1561 1687 r = verity_fec_ctr(v); 1562 1688 if (r) ··· 1664 1788 bdev = dm_disk(dm_table_get_md(ti->table))->part0; 1665 1789 root_digest.digest = v->root_digest; 1666 1790 root_digest.digest_len = v->digest_size; 1667 - if (static_branch_unlikely(&ahash_enabled) && !v->shash_tfm) 1668 - root_digest.alg = crypto_ahash_alg_name(v->ahash_tfm); 1669 - else 1670 - root_digest.alg = crypto_shash_alg_name(v->shash_tfm); 1791 + root_digest.alg = crypto_shash_alg_name(v->shash_tfm); 1671 1792 1672 1793 r = security_bdev_setintegrity(bdev, LSM_INT_DMVERITY_ROOTHASH, &root_digest, 1673 1794 sizeof(root_digest)); ··· 1690 1817 .name = "verity", 1691 1818 /* Note: the LSMs depend on the singleton and immutable features */ 1692 1819 .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE, 1693 - .version = {1, 11, 0}, 1820 + .version = {1, 12, 0}, 1694 1821 .module = THIS_MODULE, 1695 1822 .ctr = verity_ctr, 1696 1823 .dtr = verity_dtr,
+7 -15
drivers/md/dm-verity.h
··· 39 39 struct dm_target *ti; 40 40 struct dm_bufio_client *bufio; 41 41 char *alg_name; 42 - struct crypto_ahash *ahash_tfm; /* either this or shash_tfm is set */ 43 - struct crypto_shash *shash_tfm; /* either this or ahash_tfm is set */ 42 + struct crypto_shash *shash_tfm; 44 43 u8 *root_digest; /* digest of the root block */ 45 44 u8 *salt; /* salt: its size is salt_size */ 46 - u8 *initial_hashstate; /* salted initial state, if shash_tfm is set */ 45 + u8 *initial_hashstate; /* salted initial state, if version >= 1 */ 47 46 u8 *zero_digest; /* digest for a zero block */ 48 47 #ifdef CONFIG_SECURITY 49 48 u8 *root_digest_sig; /* signature of the root digest */ ··· 60 61 bool hash_failed:1; /* set if hash of any block failed */ 61 62 bool use_bh_wq:1; /* try to verify in BH wq before normal work-queue */ 62 63 unsigned int digest_size; /* digest size for the current hash algorithm */ 63 - unsigned int hash_reqsize; /* the size of temporary space for crypto */ 64 64 enum verity_mode mode; /* mode for handling verification errors */ 65 65 enum verity_mode error_mode;/* mode for handling I/O errors */ 66 66 unsigned int corrupted_errs;/* Number of errors for corrupted blocks */ ··· 98 100 u8 want_digest[HASH_MAX_DIGESTSIZE]; 99 101 100 102 /* 101 - * This struct is followed by a variable-sized hash request of size 102 - * v->hash_reqsize, either a struct ahash_request or a struct shash_desc 103 - * (depending on whether ahash_tfm or shash_tfm is being used). To 104 - * access it, use verity_io_hash_req(). 103 + * Temporary space for hashing. This is variable-length and must be at 104 + * the end of the struct. struct shash_desc is just the fixed part; 105 + * it's followed by a context of size crypto_shash_descsize(shash_tfm). 105 106 */ 107 + struct shash_desc hash_desc; 106 108 }; 107 - 108 - static inline void *verity_io_hash_req(struct dm_verity *v, 109 - struct dm_verity_io *io) 110 - { 111 - return io + 1; 112 - } 113 109 114 110 static inline u8 *verity_io_real_digest(struct dm_verity *v, 115 111 struct dm_verity_io *io) ··· 118 126 } 119 127 120 128 extern int verity_hash(struct dm_verity *v, struct dm_verity_io *io, 121 - const u8 *data, size_t len, u8 *digest, bool may_sleep); 129 + const u8 *data, size_t len, u8 *digest); 122 130 123 131 extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, 124 132 sector_t block, u8 *digest, bool *is_zero);
-2
drivers/md/dm-zone.c
··· 467 467 bdev_offset_from_zone_start(disk->part0, 468 468 clone->bi_iter.bi_sector); 469 469 } 470 - 471 - return; 472 470 } 473 471 474 472 static int dm_zone_need_reset_cb(struct blk_zone *zone, unsigned int idx,
+1 -1
drivers/md/dm-zoned-target.c
··· 1062 1062 struct dmz_target *dmz = ti->private; 1063 1063 unsigned int zone_nr_sectors = dmz_zone_nr_sectors(dmz->metadata); 1064 1064 sector_t capacity; 1065 - int i, r; 1065 + int i, r = 0; 1066 1066 1067 1067 for (i = 0; i < dmz->nr_ddevs; i++) { 1068 1068 capacity = dmz->dev[i].capacity & ~(zone_nr_sectors - 1);
+2 -9
drivers/md/dm.c
··· 1024 1024 * 1025 1025 * 2) io->orig_bio points to new cloned bio which matches the requeued dm_io. 1026 1026 */ 1027 - static void dm_io_complete(struct dm_io *io) 1027 + static inline void dm_io_complete(struct dm_io *io) 1028 1028 { 1029 - bool first_requeue; 1030 - 1031 1029 /* 1032 1030 * Only dm_io that has been split needs two stage requeue, otherwise 1033 1031 * we may run into long bio clone chain during suspend and OOM could ··· 1034 1036 * Also flush data dm_io won't be marked as DM_IO_WAS_SPLIT, so they 1035 1037 * also aren't handled via the first stage requeue. 1036 1038 */ 1037 - if (dm_io_flagged(io, DM_IO_WAS_SPLIT)) 1038 - first_requeue = true; 1039 - else 1040 - first_requeue = false; 1041 - 1042 - __dm_io_complete(io, first_requeue); 1039 + __dm_io_complete(io, dm_io_flagged(io, DM_IO_WAS_SPLIT)); 1043 1040 } 1044 1041 1045 1042 /*
+8 -4
drivers/media/platform/qcom/venus/pm_helpers.c
··· 48 48 int ret; 49 49 50 50 opp = dev_pm_opp_find_freq_ceil(dev, &freq); 51 - dev_pm_opp_put(opp); 51 + if (!IS_ERR(opp)) 52 + dev_pm_opp_put(opp); 52 53 53 54 for (i = 0; i < res->clks_num; i++) { 54 55 if (IS_V6(core)) { ··· 661 660 /*TODO : divide this inst->load by work_route */ 662 661 663 662 opp = dev_pm_opp_find_freq_floor(dev, &max_freq); 664 - dev_pm_opp_put(opp); 663 + if (!IS_ERR(opp)) 664 + dev_pm_opp_put(opp); 665 665 666 666 min_loaded_core(inst, &min_coreid, &min_load, false); 667 667 min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true); ··· 1123 1121 freq = max(freq_core1, freq_core2); 1124 1122 1125 1123 opp = dev_pm_opp_find_freq_floor(dev, &max_freq); 1126 - dev_pm_opp_put(opp); 1124 + if (!IS_ERR(opp)) 1125 + dev_pm_opp_put(opp); 1127 1126 1128 1127 if (freq > max_freq) { 1129 1128 dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n", ··· 1134 1131 } 1135 1132 1136 1133 opp = dev_pm_opp_find_freq_ceil(dev, &freq); 1137 - dev_pm_opp_put(opp); 1134 + if (!IS_ERR(opp)) 1135 + dev_pm_opp_put(opp); 1138 1136 1139 1137 set_freq: 1140 1138
+1 -1
drivers/net/ethernet/marvell/mvneta.c
··· 4610 4610 /* Inform that we are stopping so we don't want to setup the 4611 4611 * driver for new CPUs in the notifiers. The code of the 4612 4612 * notifier for CPU online is protected by the same spinlock, 4613 - * so when we get the lock, the notifer work is done. 4613 + * so when we get the lock, the notifier work is done. 4614 4614 */ 4615 4615 spin_lock(&pp->lock); 4616 4616 pp->is_stopped = true;
+3 -3
drivers/net/usb/usbnet.c
··· 1120 1120 if (!test_bit(EVENT_DEV_OPEN, &dev->flags)) 1121 1121 return; 1122 1122 1123 + if (test_and_clear_bit(EVENT_LINK_CARRIER_ON, &dev->flags)) 1124 + netif_carrier_on(dev->net); 1125 + 1123 1126 if (!netif_carrier_ok(dev->net)) { 1124 1127 /* kill URBs for reading packets to save bus bandwidth */ 1125 1128 unlink_urbs(dev, &dev->rxq); ··· 1132 1129 * tx queue is stopped by netcore after link becomes off 1133 1130 */ 1134 1131 } else { 1135 - if (test_and_clear_bit(EVENT_LINK_CARRIER_ON, &dev->flags)) 1136 - netif_carrier_on(dev->net); 1137 - 1138 1132 /* submitting URBs for reading packets */ 1139 1133 queue_work(system_bh_wq, &dev->bh_work); 1140 1134 }
+1 -2
drivers/net/wwan/iosm/iosm_ipc_trace.c
··· 51 51 } 52 52 53 53 static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf, 54 - void *prev_subbuf, 55 - size_t prev_padding) 54 + void *prev_subbuf) 56 55 { 57 56 if (relay_buf_full(buf)) { 58 57 pr_err_ratelimited("Relay_buf full dropping traces");
+1 -1
drivers/net/wwan/t7xx/t7xx_port_trace.c
··· 33 33 } 34 34 35 35 static int t7xx_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf, 36 - void *prev_subbuf, size_t prev_padding) 36 + void *prev_subbuf) 37 37 { 38 38 if (relay_buf_full(buf)) { 39 39 pr_err_ratelimited("Relay_buf full dropping traces");
+226 -24
drivers/pci/hotplug/pnv_php.c
··· 3 3 * PCI Hotplug Driver for PowerPC PowerNV platform. 4 4 * 5 5 * Copyright Gavin Shan, IBM Corporation 2016. 6 + * Copyright (C) 2025 Raptor Engineering, LLC 7 + * Copyright (C) 2025 Raptor Computing Systems, LLC 6 8 */ 7 9 8 10 #include <linux/bitfield.h> 9 11 #include <linux/libfdt.h> 10 12 #include <linux/module.h> 11 13 #include <linux/pci.h> 14 + #include <linux/delay.h> 12 15 #include <linux/pci_hotplug.h> 13 16 #include <linux/of_fdt.h> 14 17 ··· 39 36 static void pnv_php_unregister_one(struct device_node *dn); 40 37 static void pnv_php_unregister(struct device_node *dn); 41 38 39 + static void pnv_php_enable_irq(struct pnv_php_slot *php_slot); 40 + 42 41 static void pnv_php_disable_irq(struct pnv_php_slot *php_slot, 43 - bool disable_device) 42 + bool disable_device, bool disable_msi) 44 43 { 45 44 struct pci_dev *pdev = php_slot->pdev; 46 45 u16 ctrl; ··· 58 53 php_slot->irq = 0; 59 54 } 60 55 61 - if (php_slot->wq) { 62 - destroy_workqueue(php_slot->wq); 63 - php_slot->wq = NULL; 64 - } 65 - 66 - if (disable_device) { 56 + if (disable_device || disable_msi) { 67 57 if (pdev->msix_enabled) 68 58 pci_disable_msix(pdev); 69 59 else if (pdev->msi_enabled) 70 60 pci_disable_msi(pdev); 71 - 72 - pci_disable_device(pdev); 73 61 } 62 + 63 + if (disable_device) 64 + pci_disable_device(pdev); 74 65 } 75 66 76 67 static void pnv_php_free_slot(struct kref *kref) ··· 75 74 struct pnv_php_slot, kref); 76 75 77 76 WARN_ON(!list_empty(&php_slot->children)); 78 - pnv_php_disable_irq(php_slot, false); 77 + pnv_php_disable_irq(php_slot, false, false); 78 + destroy_workqueue(php_slot->wq); 79 79 kfree(php_slot->name); 80 80 kfree(php_slot); 81 81 } ··· 393 391 return 0; 394 392 } 395 393 394 + static int pcie_check_link_active(struct pci_dev *pdev) 395 + { 396 + u16 lnk_status; 397 + int ret; 398 + 399 + ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status); 400 + if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status)) 401 + return -ENODEV; 402 + 403 + ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); 404 + 405 + return ret; 406 + } 407 + 396 408 static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state) 397 409 { 398 410 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); ··· 419 403 */ 420 404 ret = pnv_pci_get_presence_state(php_slot->id, &presence); 421 405 if (ret >= 0) { 406 + if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM && 407 + presence == OPAL_PCI_SLOT_EMPTY) { 408 + /* 409 + * Similar to pciehp_hpc, check whether the Link Active 410 + * bit is set to account for broken downstream bridges 411 + * that don't properly assert Presence Detect State, as 412 + * was observed on the Microsemi Switchtec PM8533 PFX 413 + * [11f8:8533]. 414 + */ 415 + if (pcie_check_link_active(php_slot->pdev) > 0) 416 + presence = OPAL_PCI_SLOT_PRESENT; 417 + } 418 + 422 419 *state = presence; 423 420 ret = 0; 424 421 } else { ··· 441 412 return ret; 442 413 } 443 414 415 + static int pnv_php_get_raw_indicator_status(struct hotplug_slot *slot, u8 *state) 416 + { 417 + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); 418 + struct pci_dev *bridge = php_slot->pdev; 419 + u16 status; 420 + 421 + pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status); 422 + *state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6; 423 + return 0; 424 + } 425 + 426 + 444 427 static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state) 445 428 { 446 429 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); 447 430 431 + pnv_php_get_raw_indicator_status(slot, &php_slot->attention_state); 448 432 *state = php_slot->attention_state; 449 433 return 0; 450 434 } ··· 475 433 mask = PCI_EXP_SLTCTL_AIC; 476 434 477 435 if (state) 478 - new = PCI_EXP_SLTCTL_ATTN_IND_ON; 436 + new = FIELD_PREP(PCI_EXP_SLTCTL_AIC, state); 479 437 else 480 438 new = PCI_EXP_SLTCTL_ATTN_IND_OFF; 481 439 482 440 pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new); 483 441 484 442 return 0; 443 + } 444 + 445 + static int pnv_php_activate_slot(struct pnv_php_slot *php_slot, 446 + struct hotplug_slot *slot) 447 + { 448 + int ret, i; 449 + 450 + /* 451 + * Issue initial slot activation command to firmware 452 + * 453 + * Firmware will power slot on, attempt to train the link, and 454 + * discover any downstream devices. If this process fails, firmware 455 + * will return an error code and an invalid device tree. Failure 456 + * can be caused for multiple reasons, including a faulty 457 + * downstream device, poor connection to the downstream device, or 458 + * a previously latched PHB fence. On failure, issue fundamental 459 + * reset up to three times before aborting. 460 + */ 461 + ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON); 462 + if (ret) { 463 + SLOT_WARN( 464 + php_slot, 465 + "PCI slot activation failed with error code %d, possible frozen PHB", 466 + ret); 467 + SLOT_WARN( 468 + php_slot, 469 + "Attempting complete PHB reset before retrying slot activation\n"); 470 + for (i = 0; i < 3; i++) { 471 + /* 472 + * Slot activation failed, PHB may be fenced from a 473 + * prior device failure. 474 + * 475 + * Use the OPAL fundamental reset call to both try a 476 + * device reset and clear any potentially active PHB 477 + * fence / freeze. 478 + */ 479 + SLOT_WARN(php_slot, "Try %d...\n", i + 1); 480 + pci_set_pcie_reset_state(php_slot->pdev, 481 + pcie_warm_reset); 482 + msleep(250); 483 + pci_set_pcie_reset_state(php_slot->pdev, 484 + pcie_deassert_reset); 485 + 486 + ret = pnv_php_set_slot_power_state( 487 + slot, OPAL_PCI_SLOT_POWER_ON); 488 + if (!ret) 489 + break; 490 + } 491 + 492 + if (i >= 3) 493 + SLOT_WARN(php_slot, 494 + "Failed to bring slot online, aborting!\n"); 495 + } 496 + 497 + return ret; 485 498 } 486 499 487 500 static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan) ··· 601 504 goto scan; 602 505 603 506 /* Power is off, turn it on and then scan the slot */ 604 - ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON); 507 + ret = pnv_php_activate_slot(php_slot, slot); 605 508 if (ret) 606 509 return ret; 607 510 ··· 658 561 static int pnv_php_enable_slot(struct hotplug_slot *slot) 659 562 { 660 563 struct pnv_php_slot *php_slot = to_pnv_php_slot(slot); 564 + u32 prop32; 565 + int ret; 661 566 662 - return pnv_php_enable(php_slot, true); 567 + ret = pnv_php_enable(php_slot, true); 568 + if (ret) 569 + return ret; 570 + 571 + /* (Re-)enable interrupt if the slot supports surprise hotplug */ 572 + ret = of_property_read_u32(php_slot->dn, "ibm,slot-surprise-pluggable", 573 + &prop32); 574 + if (!ret && prop32) 575 + pnv_php_enable_irq(php_slot); 576 + 577 + return 0; 578 + } 579 + 580 + /* 581 + * Disable any hotplug interrupts for all slots on the provided bus, as well as 582 + * all downstream slots in preparation for a hot unplug. 583 + */ 584 + static int pnv_php_disable_all_irqs(struct pci_bus *bus) 585 + { 586 + struct pci_bus *child_bus; 587 + struct pci_slot *slot; 588 + 589 + /* First go down child buses */ 590 + list_for_each_entry(child_bus, &bus->children, node) 591 + pnv_php_disable_all_irqs(child_bus); 592 + 593 + /* Disable IRQs for all pnv_php slots on this bus */ 594 + list_for_each_entry(slot, &bus->slots, list) { 595 + struct pnv_php_slot *php_slot = to_pnv_php_slot(slot->hotplug); 596 + 597 + pnv_php_disable_irq(php_slot, false, true); 598 + } 599 + 600 + return 0; 601 + } 602 + 603 + /* 604 + * Disable any hotplug interrupts for all downstream slots on the provided 605 + * bus in preparation for a hot unplug. 606 + */ 607 + static int pnv_php_disable_all_downstream_irqs(struct pci_bus *bus) 608 + { 609 + struct pci_bus *child_bus; 610 + 611 + /* Go down child buses, recursively deactivating their IRQs */ 612 + list_for_each_entry(child_bus, &bus->children, node) 613 + pnv_php_disable_all_irqs(child_bus); 614 + 615 + return 0; 663 616 } 664 617 665 618 static int pnv_php_disable_slot(struct hotplug_slot *slot) ··· 725 578 if (php_slot->state != PNV_PHP_STATE_POPULATED && 726 579 php_slot->state != PNV_PHP_STATE_REGISTERED) 727 580 return 0; 581 + 582 + /* 583 + * Free all IRQ resources from all child slots before remove. 584 + * Note that we do not disable the root slot IRQ here as that 585 + * would also deactivate the slot hot (re)plug interrupt! 586 + */ 587 + pnv_php_disable_all_downstream_irqs(php_slot->bus); 728 588 729 589 /* Remove all devices behind the slot */ 730 590 pci_lock_rescan_remove(); ··· 797 643 798 644 php_slot->name = kstrdup(label, GFP_KERNEL); 799 645 if (!php_slot->name) { 646 + kfree(php_slot); 647 + return NULL; 648 + } 649 + 650 + /* Allocate workqueue for this slot's interrupt handling */ 651 + php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name); 652 + if (!php_slot->wq) { 653 + SLOT_WARN(php_slot, "Cannot alloc workqueue\n"); 654 + kfree(php_slot->name); 800 655 kfree(php_slot); 801 656 return NULL; 802 657 } ··· 908 745 return entry.vector; 909 746 } 910 747 748 + static void 749 + pnv_php_detect_clear_suprise_removal_freeze(struct pnv_php_slot *php_slot) 750 + { 751 + struct pci_dev *pdev = php_slot->pdev; 752 + struct eeh_dev *edev; 753 + struct eeh_pe *pe; 754 + int i, rc; 755 + 756 + /* 757 + * When a device is surprise removed from a downstream bridge slot, 758 + * the upstream bridge port can still end up frozen due to related EEH 759 + * events, which will in turn block the MSI interrupts for slot hotplug 760 + * detection. 761 + * 762 + * Detect and thaw any frozen upstream PE after slot deactivation. 763 + */ 764 + edev = pci_dev_to_eeh_dev(pdev); 765 + pe = edev ? edev->pe : NULL; 766 + rc = eeh_pe_get_state(pe); 767 + if ((rc == -ENODEV) || (rc == -ENOENT)) { 768 + SLOT_WARN( 769 + php_slot, 770 + "Upstream bridge PE state unknown, hotplug detect may fail\n"); 771 + } else { 772 + if (pe->state & EEH_PE_ISOLATED) { 773 + SLOT_WARN( 774 + php_slot, 775 + "Upstream bridge PE %02x frozen, thawing...\n", 776 + pe->addr); 777 + for (i = 0; i < 3; i++) 778 + if (!eeh_unfreeze_pe(pe)) 779 + break; 780 + if (i >= 3) 781 + SLOT_WARN( 782 + php_slot, 783 + "Unable to thaw PE %02x, hotplug detect will fail!\n", 784 + pe->addr); 785 + else 786 + SLOT_WARN(php_slot, 787 + "PE %02x thawed successfully\n", 788 + pe->addr); 789 + } 790 + } 791 + } 792 + 911 793 static void pnv_php_event_handler(struct work_struct *work) 912 794 { 913 795 struct pnv_php_event *event = 914 796 container_of(work, struct pnv_php_event, work); 915 797 struct pnv_php_slot *php_slot = event->php_slot; 916 798 917 - if (event->added) 799 + if (event->added) { 918 800 pnv_php_enable_slot(&php_slot->slot); 919 - else 801 + } else { 920 802 pnv_php_disable_slot(&php_slot->slot); 803 + pnv_php_detect_clear_suprise_removal_freeze(php_slot); 804 + } 921 805 922 806 kfree(event); 923 807 } ··· 1053 843 u16 sts, ctrl; 1054 844 int ret; 1055 845 1056 - /* Allocate workqueue */ 1057 - php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name); 1058 - if (!php_slot->wq) { 1059 - SLOT_WARN(php_slot, "Cannot alloc workqueue\n"); 1060 - pnv_php_disable_irq(php_slot, true); 1061 - return; 1062 - } 1063 - 1064 846 /* Check PDC (Presence Detection Change) is broken or not */ 1065 847 ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc", 1066 848 &broken_pdc); ··· 1071 869 ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED, 1072 870 php_slot->name, php_slot); 1073 871 if (ret) { 1074 - pnv_php_disable_irq(php_slot, true); 872 + pnv_php_disable_irq(php_slot, true, true); 1075 873 SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq); 1076 874 return; 1077 875 }
+12 -9
drivers/rtc/Kconfig
··· 483 483 This driver can also be built as a module. If so, the module 484 484 will be called rtc-pcf8523. 485 485 486 - config RTC_DRV_PCF85063 487 - tristate "NXP PCF85063" 488 - select REGMAP_I2C 489 - help 490 - If you say yes here you get support for the PCF85063 RTC chip 491 - 492 - This driver can also be built as a module. If so, the module 493 - will be called rtc-pcf85063. 494 - 495 486 config RTC_DRV_PCF85363 496 487 tristate "NXP PCF85363" 497 488 select REGMAP_I2C ··· 961 970 962 971 This driver can also be built as a module. If so, the module 963 972 will be called rtc-pcf2127. 973 + 974 + config RTC_DRV_PCF85063 975 + tristate "NXP PCF85063" 976 + depends on RTC_I2C_AND_SPI 977 + select REGMAP_I2C if I2C 978 + select REGMAP_SPI if SPI_MASTER 979 + help 980 + If you say yes here you get support for the PCF85063 and RV8063 981 + RTC chips. 982 + 983 + This driver can also be built as a module. If so, the module 984 + will be called rtc-pcf85063. 964 985 965 986 config RTC_DRV_RV3029C2 966 987 tristate "Micro Crystal RV3029/3049"
+1 -1
drivers/rtc/Makefile
··· 15 15 rtc-core-$(CONFIG_RTC_INTF_PROC) += proc.o 16 16 rtc-core-$(CONFIG_RTC_INTF_SYSFS) += sysfs.o 17 17 18 - obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o 18 + obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += test_rtc_lib.o 19 19 20 20 # Keep the list ordered. 21 21
+19 -21
drivers/rtc/lib.c
··· 51 51 */ 52 52 void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) 53 53 { 54 - int days, secs; 54 + int secs; 55 55 56 56 u64 u64tmp; 57 57 u32 u32tmp, udays, century, day_of_century, year_of_century, year, ··· 59 59 bool is_Jan_or_Feb, is_leap_year; 60 60 61 61 /* 62 - * Get days and seconds while preserving the sign to 63 - * handle negative time values (dates before 1970-01-01) 62 + * The time represented by `time` is given in seconds since 1970-01-01 63 + * (UTC). As the division done below might misbehave for negative 64 + * values, we convert it to seconds since 0000-03-01 and then assume it 65 + * will be non-negative. 66 + * Below we do 4 * udays + 3 which should fit into a 32 bit unsigned 67 + * variable. So the latest date this algorithm works for is 1073741823 68 + * days after 0000-03-01 which is in the year 2939805. 64 69 */ 65 - days = div_s64_rem(time, 86400, &secs); 70 + time += (u64)719468 * 86400; 71 + 72 + udays = div_s64_rem(time, 86400, &secs); 66 73 67 74 /* 68 - * We need 0 <= secs < 86400 which isn't given for negative 69 - * values of time. Fixup accordingly. 75 + * day of the week, 0000-03-01 was a Wednesday (in the proleptic 76 + * Gregorian calendar) 70 77 */ 71 - if (secs < 0) { 72 - days -= 1; 73 - secs += 86400; 74 - } 75 - 76 - /* day of the week, 1970-01-01 was a Thursday */ 77 - tm->tm_wday = (days + 4) % 7; 78 - /* Ensure tm_wday is always positive */ 79 - if (tm->tm_wday < 0) 80 - tm->tm_wday += 7; 78 + tm->tm_wday = (udays + 3) % 7; 81 79 82 80 /* 83 - * The following algorithm is, basically, Proposition 6.3 of Neri 81 + * The following algorithm is, basically, Figure 12 of Neri 84 82 * and Schneider [1]. In a few words: it works on the computational 85 83 * (fictitious) calendar where the year starts in March, month = 2 86 84 * (*), and finishes in February, month = 13. This calendar is ··· 98 100 * (using just arithmetics) it's easy to convert it to the 99 101 * corresponding date in the Gregorian calendar. 100 102 * 101 - * [1] "Euclidean Affine Functions and Applications to Calendar 102 - * Algorithms". https://arxiv.org/abs/2102.06959 103 + * [1] Neri C, Schneider L. Euclidean affine functions and their 104 + * application to calendar algorithms. Softw Pract Exper. 105 + * 2023;53(4):937-970. doi: 10.1002/spe.3172 106 + * https://doi.org/10.1002/spe.3172 103 107 * 104 108 * (*) The numbering of months follows rtc_time more closely and 105 109 * thus, is slightly different from [1]. 106 110 */ 107 - 108 - udays = days + 719468; 109 111 110 112 u32tmp = 4 * udays + 3; 111 113 century = u32tmp / 146097;
drivers/rtc/lib_test.c drivers/rtc/test_rtc_lib.c
+22 -8
drivers/rtc/rtc-ds1307.c
··· 279 279 if (tmp & DS1340_BIT_OSF) 280 280 return -EINVAL; 281 281 break; 282 + case ds_1341: 283 + ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &tmp); 284 + if (ret) 285 + return ret; 286 + if (tmp & DS1337_BIT_OSF) 287 + return -EINVAL; 288 + break; 282 289 case ds_1388: 283 290 ret = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &tmp); 284 291 if (ret) ··· 383 376 case ds_1340: 384 377 regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG, 385 378 DS1340_BIT_OSF, 0); 379 + break; 380 + case ds_1341: 381 + regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS, 382 + DS1337_BIT_OSF, 0); 386 383 break; 387 384 case ds_1388: 388 385 regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG, ··· 1467 1456 return ds3231_clk_sqw_rates[rate_sel]; 1468 1457 } 1469 1458 1470 - static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate, 1471 - unsigned long *prate) 1459 + static int ds3231_clk_sqw_determine_rate(struct clk_hw *hw, 1460 + struct clk_rate_request *req) 1472 1461 { 1473 1462 int i; 1474 1463 1475 1464 for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) { 1476 - if (ds3231_clk_sqw_rates[i] <= rate) 1477 - return ds3231_clk_sqw_rates[i]; 1465 + if (ds3231_clk_sqw_rates[i] <= req->rate) { 1466 + req->rate = ds3231_clk_sqw_rates[i]; 1467 + 1468 + return 0; 1469 + } 1478 1470 } 1471 + 1472 + req->rate = ds3231_clk_sqw_rates[ARRAY_SIZE(ds3231_clk_sqw_rates) - 1]; 1479 1473 1480 1474 return 0; 1481 1475 } ··· 1541 1525 .unprepare = ds3231_clk_sqw_unprepare, 1542 1526 .is_prepared = ds3231_clk_sqw_is_prepared, 1543 1527 .recalc_rate = ds3231_clk_sqw_recalc_rate, 1544 - .round_rate = ds3231_clk_sqw_round_rate, 1528 + .determine_rate = ds3231_clk_sqw_determine_rate, 1545 1529 .set_rate = ds3231_clk_sqw_set_rate, 1546 1530 }; 1547 1531 ··· 1829 1813 regmap_write(ds1307->regmap, DS1337_REG_CONTROL, 1830 1814 regs[0]); 1831 1815 1832 - /* oscillator fault? clear flag, and warn */ 1816 + /* oscillator fault? warn */ 1833 1817 if (regs[1] & DS1337_BIT_OSF) { 1834 - regmap_write(ds1307->regmap, DS1337_REG_STATUS, 1835 - regs[1] & ~DS1337_BIT_OSF); 1836 1818 dev_warn(ds1307->dev, "SET TIME!\n"); 1837 1819 } 1838 1820 break;
+2 -2
drivers/rtc/rtc-ds1685.c
··· 3 3 * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time 4 4 * chips. 5 5 * 6 - * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>. 6 + * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>. 7 7 * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>. 8 8 * 9 9 * References: ··· 1436 1436 /* ----------------------------------------------------------------------- */ 1437 1437 1438 1438 1439 - MODULE_AUTHOR("Joshua Kinard <kumba@gentoo.org>"); 1439 + MODULE_AUTHOR("Joshua Kinard <linux@kumba.dev>"); 1440 1440 MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd-electronics.com>"); 1441 1441 MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687-series RTC driver"); 1442 1442 MODULE_LICENSE("GPL");
+10 -5
drivers/rtc/rtc-hym8563.c
··· 285 285 return clkout_rates[ret]; 286 286 } 287 287 288 - static long hym8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 289 - unsigned long *prate) 288 + static int hym8563_clkout_determine_rate(struct clk_hw *hw, 289 + struct clk_rate_request *req) 290 290 { 291 291 int i; 292 292 293 293 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 294 - if (clkout_rates[i] <= rate) 295 - return clkout_rates[i]; 294 + if (clkout_rates[i] <= req->rate) { 295 + req->rate = clkout_rates[i]; 296 + 297 + return 0; 298 + } 299 + 300 + req->rate = clkout_rates[0]; 296 301 297 302 return 0; 298 303 } ··· 368 363 .unprepare = hym8563_clkout_unprepare, 369 364 .is_prepared = hym8563_clkout_is_prepared, 370 365 .recalc_rate = hym8563_clkout_recalc_rate, 371 - .round_rate = hym8563_clkout_round_rate, 366 + .determine_rate = hym8563_clkout_determine_rate, 372 367 .set_rate = hym8563_clkout_set_rate, 373 368 }; 374 369
+13 -12
drivers/rtc/rtc-m41t80.c
··· 72 72 73 73 static const struct i2c_device_id m41t80_id[] = { 74 74 { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, 75 - { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD }, 75 + { "m41t65", M41T80_FEATURE_WD }, 76 76 { "m41t80", M41T80_FEATURE_SQ }, 77 77 { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ}, 78 78 { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ }, ··· 93 93 }, 94 94 { 95 95 .compatible = "st,m41t65", 96 - .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_WD) 96 + .data = (void *)(M41T80_FEATURE_WD) 97 97 }, 98 98 { 99 99 .compatible = "st,m41t80", ··· 484 484 return sqw_to_m41t80_data(hw)->freq; 485 485 } 486 486 487 - static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate, 488 - unsigned long *prate) 487 + static int m41t80_sqw_determine_rate(struct clk_hw *hw, 488 + struct clk_rate_request *req) 489 489 { 490 - if (rate >= M41T80_SQW_MAX_FREQ) 491 - return M41T80_SQW_MAX_FREQ; 492 - if (rate >= M41T80_SQW_MAX_FREQ / 4) 493 - return M41T80_SQW_MAX_FREQ / 4; 494 - if (!rate) 495 - return 0; 496 - return 1 << ilog2(rate); 490 + if (req->rate >= M41T80_SQW_MAX_FREQ) 491 + req->rate = M41T80_SQW_MAX_FREQ; 492 + else if (req->rate >= M41T80_SQW_MAX_FREQ / 4) 493 + req->rate = M41T80_SQW_MAX_FREQ / 4; 494 + else if (req->rate) 495 + req->rate = 1 << ilog2(req->rate); 496 + 497 + return 0; 497 498 } 498 499 499 500 static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate, ··· 565 564 .unprepare = m41t80_sqw_unprepare, 566 565 .is_prepared = m41t80_sqw_is_prepared, 567 566 .recalc_rate = m41t80_sqw_recalc_rate, 568 - .round_rate = m41t80_sqw_round_rate, 567 + .determine_rate = m41t80_sqw_determine_rate, 569 568 .set_rate = m41t80_sqw_set_rate, 570 569 }; 571 570
+7 -5
drivers/rtc/rtc-max31335.c
··· 497 497 return max31335_clkout_freq[reg & freq_mask]; 498 498 } 499 499 500 - static long max31335_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 501 - unsigned long *prate) 500 + static int max31335_clkout_determine_rate(struct clk_hw *hw, 501 + struct clk_rate_request *req) 502 502 { 503 503 int index; 504 504 505 - index = find_closest(rate, max31335_clkout_freq, 505 + index = find_closest(req->rate, max31335_clkout_freq, 506 506 ARRAY_SIZE(max31335_clkout_freq)); 507 507 508 - return max31335_clkout_freq[index]; 508 + req->rate = max31335_clkout_freq[index]; 509 + 510 + return 0; 509 511 } 510 512 511 513 static int max31335_clkout_set_rate(struct clk_hw *hw, unsigned long rate, ··· 556 554 557 555 static const struct clk_ops max31335_clkout_ops = { 558 556 .recalc_rate = max31335_clkout_recalc_rate, 559 - .round_rate = max31335_clkout_round_rate, 557 + .determine_rate = max31335_clkout_determine_rate, 560 558 .set_rate = max31335_clkout_set_rate, 561 559 .enable = max31335_clkout_enable, 562 560 .disable = max31335_clkout_disable,
+10 -5
drivers/rtc/rtc-nct3018y.c
··· 367 367 return clkout_rates[flags]; 368 368 } 369 369 370 - static long nct3018y_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 371 - unsigned long *prate) 370 + static int nct3018y_clkout_determine_rate(struct clk_hw *hw, 371 + struct clk_rate_request *req) 372 372 { 373 373 int i; 374 374 375 375 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 376 - if (clkout_rates[i] <= rate) 377 - return clkout_rates[i]; 376 + if (clkout_rates[i] <= req->rate) { 377 + req->rate = clkout_rates[i]; 378 + 379 + return 0; 380 + } 381 + 382 + req->rate = clkout_rates[0]; 378 383 379 384 return 0; 380 385 } ··· 451 446 .unprepare = nct3018y_clkout_unprepare, 452 447 .is_prepared = nct3018y_clkout_is_prepared, 453 448 .recalc_rate = nct3018y_clkout_recalc_rate, 454 - .round_rate = nct3018y_clkout_round_rate, 449 + .determine_rate = nct3018y_clkout_determine_rate, 455 450 .set_rate = nct3018y_clkout_set_rate, 456 451 }; 457 452
+242 -109
drivers/rtc/rtc-pcf85063.c
··· 17 17 #include <linux/of.h> 18 18 #include <linux/pm_wakeirq.h> 19 19 #include <linux/regmap.h> 20 + #include <linux/spi/spi.h> 20 21 21 22 /* 22 23 * Information for this driver was pulled from the following datasheets. ··· 30 29 * 31 30 * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf 32 31 * RV8263 -- Rev. 1.0 — January 2019 32 + * 33 + * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8063-C7_App-Manual.pdf 34 + * RV8063 -- Rev. 1.1 - October 2018 33 35 */ 34 36 35 37 #define PCF85063_REG_CTRL1 0x00 /* status */ ··· 405 401 return clkout_rates[buf]; 406 402 } 407 403 408 - static long pcf85063_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 409 - unsigned long *prate) 404 + static int pcf85063_clkout_determine_rate(struct clk_hw *hw, 405 + struct clk_rate_request *req) 410 406 { 411 407 int i; 412 408 413 409 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 414 - if (clkout_rates[i] <= rate) 415 - return clkout_rates[i]; 410 + if (clkout_rates[i] <= req->rate) { 411 + req->rate = clkout_rates[i]; 412 + 413 + return 0; 414 + } 415 + 416 + req->rate = clkout_rates[0]; 416 417 417 418 return 0; 418 419 } ··· 491 482 .unprepare = pcf85063_clkout_unprepare, 492 483 .is_prepared = pcf85063_clkout_is_prepared, 493 484 .recalc_rate = pcf85063_clkout_recalc_rate, 494 - .round_rate = pcf85063_clkout_round_rate, 485 + .determine_rate = pcf85063_clkout_determine_rate, 495 486 .set_rate = pcf85063_clkout_set_rate, 496 487 }; 497 488 ··· 533 524 } 534 525 #endif 535 526 527 + static int pcf85063_probe(struct device *dev, struct regmap *regmap, int irq, 528 + const struct pcf85063_config *config) 529 + { 530 + struct pcf85063 *pcf85063; 531 + unsigned int tmp; 532 + int err; 533 + struct nvmem_config nvmem_cfg = { 534 + .name = "pcf85063_nvram", 535 + .reg_read = pcf85063_nvmem_read, 536 + .reg_write = pcf85063_nvmem_write, 537 + .type = NVMEM_TYPE_BATTERY_BACKED, 538 + .size = 1, 539 + }; 540 + 541 + dev_dbg(dev, "%s\n", __func__); 542 + 543 + pcf85063 = devm_kzalloc(dev, sizeof(struct pcf85063), 544 + GFP_KERNEL); 545 + if (!pcf85063) 546 + return -ENOMEM; 547 + 548 + pcf85063->regmap = regmap; 549 + 550 + dev_set_drvdata(dev, pcf85063); 551 + 552 + err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp); 553 + if (err) 554 + return dev_err_probe(dev, err, "RTC chip is not present\n"); 555 + 556 + pcf85063->rtc = devm_rtc_allocate_device(dev); 557 + if (IS_ERR(pcf85063->rtc)) 558 + return PTR_ERR(pcf85063->rtc); 559 + 560 + /* 561 + * If a Power loss is detected, SW reset the device. 562 + * From PCF85063A datasheet: 563 + * There is a low probability that some devices will have corruption 564 + * of the registers after the automatic power-on reset... 565 + */ 566 + if (tmp & PCF85063_REG_SC_OS) { 567 + dev_warn(dev, "POR issue detected, sending a SW reset\n"); 568 + err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1, 569 + PCF85063_REG_CTRL1_SWR); 570 + if (err < 0) 571 + dev_warn(dev, "SW reset failed, trying to continue\n"); 572 + } 573 + 574 + err = pcf85063_load_capacitance(pcf85063, dev->of_node, 575 + config->force_cap_7000 ? 7000 : 0); 576 + if (err < 0) 577 + dev_warn(dev, "failed to set xtal load capacitance: %d", 578 + err); 579 + 580 + pcf85063->rtc->ops = &pcf85063_rtc_ops; 581 + pcf85063->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 582 + pcf85063->rtc->range_max = RTC_TIMESTAMP_END_2099; 583 + set_bit(RTC_FEATURE_ALARM_RES_2S, pcf85063->rtc->features); 584 + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features); 585 + clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); 586 + 587 + if (config->has_alarms && irq > 0) { 588 + unsigned long irqflags = IRQF_TRIGGER_LOW; 589 + 590 + if (dev_fwnode(dev)) 591 + irqflags = 0; 592 + 593 + err = devm_request_threaded_irq(dev, irq, 594 + NULL, pcf85063_rtc_handle_irq, 595 + irqflags | IRQF_ONESHOT, 596 + "pcf85063", pcf85063); 597 + if (err) { 598 + dev_warn(&pcf85063->rtc->dev, 599 + "unable to request IRQ, alarms disabled\n"); 600 + } else { 601 + set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); 602 + device_init_wakeup(dev, true); 603 + err = dev_pm_set_wake_irq(dev, irq); 604 + if (err) 605 + dev_err(&pcf85063->rtc->dev, 606 + "failed to enable irq wake\n"); 607 + } 608 + } 609 + 610 + nvmem_cfg.priv = pcf85063->regmap; 611 + devm_rtc_nvmem_register(pcf85063->rtc, &nvmem_cfg); 612 + 613 + #ifdef CONFIG_COMMON_CLK 614 + /* register clk in common clk framework */ 615 + pcf85063_clkout_register_clk(pcf85063); 616 + #endif 617 + 618 + return devm_rtc_register_device(pcf85063->rtc); 619 + } 620 + 621 + #if IS_ENABLED(CONFIG_I2C) 622 + 536 623 static const struct pcf85063_config config_pcf85063 = { 537 624 .regmap = { 538 625 .reg_bits = 8, ··· 664 559 .force_cap_7000 = 1, 665 560 }; 666 561 667 - static int pcf85063_probe(struct i2c_client *client) 668 - { 669 - struct pcf85063 *pcf85063; 670 - unsigned int tmp; 671 - int err; 672 - const struct pcf85063_config *config; 673 - struct nvmem_config nvmem_cfg = { 674 - .name = "pcf85063_nvram", 675 - .reg_read = pcf85063_nvmem_read, 676 - .reg_write = pcf85063_nvmem_write, 677 - .type = NVMEM_TYPE_BATTERY_BACKED, 678 - .size = 1, 679 - }; 680 - 681 - dev_dbg(&client->dev, "%s\n", __func__); 682 - 683 - pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063), 684 - GFP_KERNEL); 685 - if (!pcf85063) 686 - return -ENOMEM; 687 - 688 - config = i2c_get_match_data(client); 689 - if (!config) 690 - return -ENODEV; 691 - 692 - pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); 693 - if (IS_ERR(pcf85063->regmap)) 694 - return PTR_ERR(pcf85063->regmap); 695 - 696 - i2c_set_clientdata(client, pcf85063); 697 - 698 - err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp); 699 - if (err) 700 - return dev_err_probe(&client->dev, err, "RTC chip is not present\n"); 701 - 702 - pcf85063->rtc = devm_rtc_allocate_device(&client->dev); 703 - if (IS_ERR(pcf85063->rtc)) 704 - return PTR_ERR(pcf85063->rtc); 705 - 706 - /* 707 - * If a Power loss is detected, SW reset the device. 708 - * From PCF85063A datasheet: 709 - * There is a low probability that some devices will have corruption 710 - * of the registers after the automatic power-on reset... 711 - */ 712 - if (tmp & PCF85063_REG_SC_OS) { 713 - dev_warn(&client->dev, 714 - "POR issue detected, sending a SW reset\n"); 715 - err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1, 716 - PCF85063_REG_CTRL1_SWR); 717 - if (err < 0) 718 - dev_warn(&client->dev, 719 - "SW reset failed, trying to continue\n"); 720 - } 721 - 722 - err = pcf85063_load_capacitance(pcf85063, client->dev.of_node, 723 - config->force_cap_7000 ? 7000 : 0); 724 - if (err < 0) 725 - dev_warn(&client->dev, "failed to set xtal load capacitance: %d", 726 - err); 727 - 728 - pcf85063->rtc->ops = &pcf85063_rtc_ops; 729 - pcf85063->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 730 - pcf85063->rtc->range_max = RTC_TIMESTAMP_END_2099; 731 - set_bit(RTC_FEATURE_ALARM_RES_2S, pcf85063->rtc->features); 732 - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features); 733 - clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); 734 - 735 - if (config->has_alarms && client->irq > 0) { 736 - unsigned long irqflags = IRQF_TRIGGER_LOW; 737 - 738 - if (dev_fwnode(&client->dev)) 739 - irqflags = 0; 740 - 741 - err = devm_request_threaded_irq(&client->dev, client->irq, 742 - NULL, pcf85063_rtc_handle_irq, 743 - irqflags | IRQF_ONESHOT, 744 - "pcf85063", pcf85063); 745 - if (err) { 746 - dev_warn(&pcf85063->rtc->dev, 747 - "unable to request IRQ, alarms disabled\n"); 748 - } else { 749 - set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); 750 - device_init_wakeup(&client->dev, true); 751 - err = dev_pm_set_wake_irq(&client->dev, client->irq); 752 - if (err) 753 - dev_err(&pcf85063->rtc->dev, 754 - "failed to enable irq wake\n"); 755 - } 756 - } 757 - 758 - nvmem_cfg.priv = pcf85063->regmap; 759 - devm_rtc_nvmem_register(pcf85063->rtc, &nvmem_cfg); 760 - 761 - #ifdef CONFIG_COMMON_CLK 762 - /* register clk in common clk framework */ 763 - pcf85063_clkout_register_clk(pcf85063); 764 - #endif 765 - 766 - return devm_rtc_register_device(pcf85063->rtc); 767 - } 768 - 769 562 static const struct i2c_device_id pcf85063_ids[] = { 770 563 { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, 771 564 { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 }, ··· 686 683 MODULE_DEVICE_TABLE(of, pcf85063_of_match); 687 684 #endif 688 685 686 + static int pcf85063_i2c_probe(struct i2c_client *client) 687 + { 688 + const struct pcf85063_config *config; 689 + struct regmap *regmap; 690 + 691 + config = i2c_get_match_data(client); 692 + if (!config) 693 + return -ENODEV; 694 + 695 + regmap = devm_regmap_init_i2c(client, &config->regmap); 696 + if (IS_ERR(regmap)) 697 + return PTR_ERR(regmap); 698 + 699 + return pcf85063_probe(&client->dev, regmap, client->irq, config); 700 + } 701 + 689 702 static struct i2c_driver pcf85063_driver = { 690 703 .driver = { 691 704 .name = "rtc-pcf85063", 692 705 .of_match_table = of_match_ptr(pcf85063_of_match), 693 706 }, 694 - .probe = pcf85063_probe, 707 + .probe = pcf85063_i2c_probe, 695 708 .id_table = pcf85063_ids, 696 709 }; 697 710 698 - module_i2c_driver(pcf85063_driver); 711 + static int pcf85063_register_driver(void) 712 + { 713 + return i2c_add_driver(&pcf85063_driver); 714 + } 715 + 716 + static void pcf85063_unregister_driver(void) 717 + { 718 + i2c_del_driver(&pcf85063_driver); 719 + } 720 + 721 + #else 722 + 723 + static int pcf85063_register_driver(void) 724 + { 725 + return 0; 726 + } 727 + 728 + static void pcf85063_unregister_driver(void) 729 + { 730 + } 731 + 732 + #endif /* IS_ENABLED(CONFIG_I2C) */ 733 + 734 + #if IS_ENABLED(CONFIG_SPI_MASTER) 735 + 736 + static const struct pcf85063_config config_rv8063 = { 737 + .regmap = { 738 + .reg_bits = 8, 739 + .val_bits = 8, 740 + .max_register = 0x11, 741 + .read_flag_mask = BIT(7) | BIT(5), 742 + .write_flag_mask = BIT(5), 743 + }, 744 + .has_alarms = 1, 745 + .force_cap_7000 = 1, 746 + }; 747 + 748 + static const struct spi_device_id rv8063_id[] = { 749 + { "rv8063" }, 750 + {} 751 + }; 752 + MODULE_DEVICE_TABLE(spi, rv8063_id); 753 + 754 + static const struct of_device_id rv8063_of_match[] = { 755 + { .compatible = "microcrystal,rv8063" }, 756 + {} 757 + }; 758 + MODULE_DEVICE_TABLE(of, rv8063_of_match); 759 + 760 + static int rv8063_probe(struct spi_device *spi) 761 + { 762 + const struct pcf85063_config *config = &config_rv8063; 763 + struct regmap *regmap; 764 + 765 + regmap = devm_regmap_init_spi(spi, &config->regmap); 766 + if (IS_ERR(regmap)) 767 + return PTR_ERR(regmap); 768 + 769 + return pcf85063_probe(&spi->dev, regmap, spi->irq, config); 770 + } 771 + 772 + static struct spi_driver rv8063_driver = { 773 + .driver = { 774 + .name = "rv8063", 775 + .of_match_table = rv8063_of_match, 776 + }, 777 + .probe = rv8063_probe, 778 + .id_table = rv8063_id, 779 + }; 780 + 781 + static int __init rv8063_register_driver(void) 782 + { 783 + return spi_register_driver(&rv8063_driver); 784 + } 785 + 786 + static void __exit rv8063_unregister_driver(void) 787 + { 788 + spi_unregister_driver(&rv8063_driver); 789 + } 790 + 791 + #else 792 + 793 + static int __init rv8063_register_driver(void) 794 + { 795 + return 0; 796 + } 797 + 798 + static void __exit rv8063_unregister_driver(void) 799 + { 800 + } 801 + 802 + #endif /* IS_ENABLED(CONFIG_SPI_MASTER) */ 803 + 804 + static int __init pcf85063_init(void) 805 + { 806 + int ret; 807 + 808 + ret = pcf85063_register_driver(); 809 + if (ret) 810 + return ret; 811 + 812 + ret = rv8063_register_driver(); 813 + if (ret) 814 + pcf85063_unregister_driver(); 815 + 816 + return ret; 817 + } 818 + module_init(pcf85063_init); 819 + 820 + static void __exit pcf85063_exit(void) 821 + { 822 + rv8063_unregister_driver(); 823 + pcf85063_unregister_driver(); 824 + } 825 + module_exit(pcf85063_exit); 699 826 700 827 MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>"); 701 828 MODULE_DESCRIPTION("PCF85063 RTC driver");
+10 -5
drivers/rtc/rtc-pcf8563.c
··· 330 330 return clkout_rates[buf]; 331 331 } 332 332 333 - static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 334 - unsigned long *prate) 333 + static int pcf8563_clkout_determine_rate(struct clk_hw *hw, 334 + struct clk_rate_request *req) 335 335 { 336 336 int i; 337 337 338 338 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 339 - if (clkout_rates[i] <= rate) 340 - return clkout_rates[i]; 339 + if (clkout_rates[i] <= req->rate) { 340 + req->rate = clkout_rates[i]; 341 + 342 + return 0; 343 + } 344 + 345 + req->rate = clkout_rates[0]; 341 346 342 347 return 0; 343 348 } ··· 418 413 .unprepare = pcf8563_clkout_unprepare, 419 414 .is_prepared = pcf8563_clkout_is_prepared, 420 415 .recalc_rate = pcf8563_clkout_recalc_rate, 421 - .round_rate = pcf8563_clkout_round_rate, 416 + .determine_rate = pcf8563_clkout_determine_rate, 422 417 .set_rate = pcf8563_clkout_set_rate, 423 418 }; 424 419
+10 -5
drivers/rtc/rtc-rv3028.c
··· 731 731 return clkout_rates[clkout]; 732 732 } 733 733 734 - static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 735 - unsigned long *prate) 734 + static int rv3028_clkout_determine_rate(struct clk_hw *hw, 735 + struct clk_rate_request *req) 736 736 { 737 737 int i; 738 738 739 739 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 740 - if (clkout_rates[i] <= rate) 741 - return clkout_rates[i]; 740 + if (clkout_rates[i] <= req->rate) { 741 + req->rate = clkout_rates[i]; 742 + 743 + return 0; 744 + } 745 + 746 + req->rate = clkout_rates[0]; 742 747 743 748 return 0; 744 749 } ··· 807 802 .unprepare = rv3028_clkout_unprepare, 808 803 .is_prepared = rv3028_clkout_is_prepared, 809 804 .recalc_rate = rv3028_clkout_recalc_rate, 810 - .round_rate = rv3028_clkout_round_rate, 805 + .determine_rate = rv3028_clkout_determine_rate, 811 806 .set_rate = rv3028_clkout_set_rate, 812 807 }; 813 808
+13 -8
drivers/rtc/rtc-rv3032.c
··· 646 646 return clkout_xtal_rates[FIELD_GET(RV3032_CLKOUT2_FD_MSK, clkout)]; 647 647 } 648 648 649 - static long rv3032_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 650 - unsigned long *prate) 649 + static int rv3032_clkout_determine_rate(struct clk_hw *hw, 650 + struct clk_rate_request *req) 651 651 { 652 652 int i, hfd; 653 653 654 - if (rate < RV3032_HFD_STEP) 654 + if (req->rate < RV3032_HFD_STEP) 655 655 for (i = 0; i < ARRAY_SIZE(clkout_xtal_rates); i++) 656 - if (clkout_xtal_rates[i] <= rate) 657 - return clkout_xtal_rates[i]; 656 + if (clkout_xtal_rates[i] <= req->rate) { 657 + req->rate = clkout_xtal_rates[i]; 658 658 659 - hfd = DIV_ROUND_CLOSEST(rate, RV3032_HFD_STEP); 659 + return 0; 660 + } 660 661 661 - return RV3032_HFD_STEP * clamp(hfd, 0, 8192); 662 + hfd = DIV_ROUND_CLOSEST(req->rate, RV3032_HFD_STEP); 663 + 664 + req->rate = RV3032_HFD_STEP * clamp(hfd, 0, 8192); 665 + 666 + return 0; 662 667 } 663 668 664 669 static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate, ··· 743 738 .unprepare = rv3032_clkout_unprepare, 744 739 .is_prepared = rv3032_clkout_is_prepared, 745 740 .recalc_rate = rv3032_clkout_recalc_rate, 746 - .round_rate = rv3032_clkout_round_rate, 741 + .determine_rate = rv3032_clkout_determine_rate, 747 742 .set_rate = rv3032_clkout_set_rate, 748 743 }; 749 744
+4 -4
drivers/rtc/rtc-s3c.c
··· 549 549 writeb(mask, info->base + S3C2410_INTP); 550 550 } 551 551 552 - static struct s3c_rtc_data const s3c2410_rtc_data = { 552 + static const struct s3c_rtc_data s3c2410_rtc_data = { 553 553 .irq_handler = s3c24xx_rtc_irq, 554 554 .enable = s3c24xx_rtc_enable, 555 555 .disable = s3c24xx_rtc_disable, 556 556 }; 557 557 558 - static struct s3c_rtc_data const s3c2416_rtc_data = { 558 + static const struct s3c_rtc_data s3c2416_rtc_data = { 559 559 .irq_handler = s3c24xx_rtc_irq, 560 560 .enable = s3c24xx_rtc_enable, 561 561 .disable = s3c24xx_rtc_disable, 562 562 }; 563 563 564 - static struct s3c_rtc_data const s3c2443_rtc_data = { 564 + static const struct s3c_rtc_data s3c2443_rtc_data = { 565 565 .irq_handler = s3c24xx_rtc_irq, 566 566 .enable = s3c24xx_rtc_enable, 567 567 .disable = s3c24xx_rtc_disable, 568 568 }; 569 569 570 - static struct s3c_rtc_data const s3c6410_rtc_data = { 570 + static const struct s3c_rtc_data s3c6410_rtc_data = { 571 571 .needs_src_clk = true, 572 572 .irq_handler = s3c6410_rtc_irq, 573 573 .enable = s3c24xx_rtc_enable,
+4 -4
drivers/rtc/rtc-sh.c
··· 455 455 clk_disable(rtc->clk); 456 456 } 457 457 458 - static int __maybe_unused sh_rtc_suspend(struct device *dev) 458 + static int sh_rtc_suspend(struct device *dev) 459 459 { 460 460 struct sh_rtc *rtc = dev_get_drvdata(dev); 461 461 ··· 465 465 return 0; 466 466 } 467 467 468 - static int __maybe_unused sh_rtc_resume(struct device *dev) 468 + static int sh_rtc_resume(struct device *dev) 469 469 { 470 470 struct sh_rtc *rtc = dev_get_drvdata(dev); 471 471 ··· 475 475 return 0; 476 476 } 477 477 478 - static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume); 478 + static DEFINE_SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume); 479 479 480 480 static const struct of_device_id sh_rtc_of_match[] = { 481 481 { .compatible = "renesas,sh-rtc", }, ··· 492 492 static struct platform_driver sh_rtc_platform_driver __refdata = { 493 493 .driver = { 494 494 .name = DRV_NAME, 495 - .pm = &sh_rtc_pm_ops, 495 + .pm = pm_sleep_ptr(&sh_rtc_pm_ops), 496 496 .of_match_table = sh_rtc_of_match, 497 497 }, 498 498 .remove = __exit_p(sh_rtc_remove),
+30 -34
drivers/rtc/sysfs.c
··· 24 24 static ssize_t 25 25 name_show(struct device *dev, struct device_attribute *attr, char *buf) 26 26 { 27 - return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent), 28 - dev_name(dev->parent)); 27 + return sysfs_emit(buf, "%s %s\n", dev_driver_string(dev->parent), 28 + dev_name(dev->parent)); 29 29 } 30 30 static DEVICE_ATTR_RO(name); 31 31 ··· 39 39 if (retval) 40 40 return retval; 41 41 42 - return sprintf(buf, "%ptRd\n", &tm); 42 + return sysfs_emit(buf, "%ptRd\n", &tm); 43 43 } 44 44 static DEVICE_ATTR_RO(date); 45 45 ··· 53 53 if (retval) 54 54 return retval; 55 55 56 - return sprintf(buf, "%ptRt\n", &tm); 56 + return sysfs_emit(buf, "%ptRt\n", &tm); 57 57 } 58 58 static DEVICE_ATTR_RO(time); 59 59 ··· 64 64 struct rtc_time tm; 65 65 66 66 retval = rtc_read_time(to_rtc_device(dev), &tm); 67 - if (retval == 0) { 68 - time64_t time; 67 + if (retval) 68 + return retval; 69 69 70 - time = rtc_tm_to_time64(&tm); 71 - retval = sprintf(buf, "%lld\n", time); 72 - } 73 - 74 - return retval; 70 + return sysfs_emit(buf, "%lld\n", rtc_tm_to_time64(&tm)); 75 71 } 76 72 static DEVICE_ATTR_RO(since_epoch); 77 73 78 74 static ssize_t 79 75 max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) 80 76 { 81 - return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); 77 + return sysfs_emit(buf, "%d\n", to_rtc_device(dev)->max_user_freq); 82 78 } 83 79 84 80 static ssize_t ··· 114 118 if (rtc_hctosys_ret == 0 && 115 119 strcmp(dev_name(&to_rtc_device(dev)->dev), 116 120 CONFIG_RTC_HCTOSYS_DEVICE) == 0) 117 - return sprintf(buf, "1\n"); 121 + return sysfs_emit(buf, "1\n"); 118 122 #endif 119 - return sprintf(buf, "0\n"); 123 + return sysfs_emit(buf, "0\n"); 120 124 } 121 125 static DEVICE_ATTR_RO(hctosys); 122 126 ··· 124 128 wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) 125 129 { 126 130 ssize_t retval; 127 - time64_t alarm; 128 131 struct rtc_wkalrm alm; 129 132 130 133 /* Don't show disabled alarms. For uniformity, RTC alarms are ··· 135 140 * alarms after they trigger, to ensure one-shot semantics. 136 141 */ 137 142 retval = rtc_read_alarm(to_rtc_device(dev), &alm); 138 - if (retval == 0 && alm.enabled) { 139 - alarm = rtc_tm_to_time64(&alm.time); 140 - retval = sprintf(buf, "%lld\n", alarm); 141 - } 143 + if (retval) 144 + return retval; 142 145 143 - return retval; 146 + if (alm.enabled) 147 + return sysfs_emit(buf, "%lld\n", rtc_tm_to_time64(&alm.time)); 148 + 149 + return 0; 144 150 } 145 151 146 152 static ssize_t ··· 218 222 long offset; 219 223 220 224 retval = rtc_read_offset(to_rtc_device(dev), &offset); 221 - if (retval == 0) 222 - retval = sprintf(buf, "%ld\n", offset); 225 + if (retval) 226 + return retval; 223 227 224 - return retval; 228 + return sysfs_emit(buf, "%ld\n", offset); 225 229 } 226 230 227 231 static ssize_t ··· 242 246 static ssize_t 243 247 range_show(struct device *dev, struct device_attribute *attr, char *buf) 244 248 { 245 - return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min, 246 - to_rtc_device(dev)->range_max); 249 + return sysfs_emit(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min, 250 + to_rtc_device(dev)->range_max); 247 251 } 248 252 static DEVICE_ATTR_RO(range); 249 253 ··· 298 302 .is_visible = rtc_attr_is_visible, 299 303 .attrs = rtc_attrs, 300 304 }; 301 - 302 - static const struct attribute_group *rtc_attr_groups[] = { 303 - &rtc_attr_group, 304 - NULL 305 - }; 305 + __ATTRIBUTE_GROUPS(rtc_attr); 306 306 307 307 const struct attribute_group **rtc_get_dev_attribute_groups(void) 308 308 { ··· 310 318 size_t old_cnt = 0, add_cnt = 0, new_cnt; 311 319 const struct attribute_group **groups, **old; 312 320 313 - if (!grps) 321 + if (grps) { 322 + for (groups = grps; *groups; groups++) 323 + add_cnt++; 324 + /* No need to modify current groups if nothing new is provided */ 325 + if (add_cnt == 0) 326 + return 0; 327 + } else { 314 328 return -EINVAL; 329 + } 315 330 316 331 groups = rtc->dev.groups; 317 332 if (groups) 318 333 for (; *groups; groups++) 319 334 old_cnt++; 320 - 321 - for (groups = grps; *groups; groups++) 322 - add_cnt++; 323 335 324 336 new_cnt = old_cnt + add_cnt + 1; 325 337 groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL);
+1 -2
drivers/scsi/aacraid/comminit.c
··· 481 481 pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { 482 482 min_msix = 2; 483 483 i = pci_alloc_irq_vectors(dev->pdev, 484 - min_msix, msi_count, 485 - PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); 484 + min_msix, msi_count, PCI_IRQ_MSIX); 486 485 if (i > 0) { 487 486 dev->msi_enabled = 1; 488 487 msi_count = i;
+2 -8
drivers/scsi/libsas/sas_ata.c
··· 252 252 return ata_dev_classify(&tf); 253 253 } 254 254 255 - int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) 255 + static int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) 256 256 { 257 257 if (phy->attached_tproto & SAS_PROTOCOL_STP) 258 258 dev->tproto = phy->attached_tproto; ··· 927 927 928 928 void sas_ata_wait_eh(struct domain_device *dev) 929 929 { 930 - struct ata_port *ap; 931 - 932 - if (!dev_is_sata(dev)) 933 - return; 934 - 935 - ap = dev->sata_dev.ap; 936 - ata_port_wait_eh(ap); 930 + ata_port_wait_eh(dev->sata_dev.ap); 937 931 } 938 932 939 933 void sas_ata_device_link_abort(struct domain_device *device, bool force_reset)
+1 -1
drivers/scsi/libsas/sas_discover.c
··· 406 406 } 407 407 } 408 408 409 - void sas_unregister_domain_devices(struct asd_sas_port *port, int gone) 409 + void sas_unregister_domain_devices(struct asd_sas_port *port, bool gone) 410 410 { 411 411 struct domain_device *dev, *n; 412 412
+76 -2
drivers/scsi/libsas/sas_internal.h
··· 44 44 int sas_discover_root_expander(struct domain_device *dev); 45 45 46 46 int sas_ex_revalidate_domain(struct domain_device *dev); 47 - void sas_unregister_domain_devices(struct asd_sas_port *port, int gone); 47 + void sas_unregister_domain_devices(struct asd_sas_port *port, bool gone); 48 48 void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port); 49 49 void sas_discover_event(struct asd_sas_port *port, enum discover_event ev); 50 50 ··· 70 70 void sas_queue_deferred_work(struct sas_ha_struct *ha); 71 71 void __sas_drain_work(struct sas_ha_struct *ha); 72 72 73 - void sas_deform_port(struct asd_sas_phy *phy, int gone); 73 + void sas_deform_port(struct asd_sas_phy *phy, bool gone); 74 74 75 75 void sas_porte_bytes_dmaed(struct work_struct *work); 76 76 void sas_porte_broadcast_rcvd(struct work_struct *work); ··· 221 221 { 222 222 kref_put(&dev->kref, sas_free_device); 223 223 } 224 + 225 + #ifdef CONFIG_SCSI_SAS_ATA 226 + 227 + int sas_ata_init(struct domain_device *dev); 228 + void sas_ata_task_abort(struct sas_task *task); 229 + int sas_discover_sata(struct domain_device *dev); 230 + int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, 231 + struct domain_device *child, int phy_id); 232 + void sas_ata_strategy_handler(struct Scsi_Host *shost); 233 + void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q); 234 + void sas_ata_end_eh(struct ata_port *ap); 235 + void sas_ata_wait_eh(struct domain_device *dev); 236 + void sas_probe_sata(struct asd_sas_port *port); 237 + void sas_suspend_sata(struct asd_sas_port *port); 238 + void sas_resume_sata(struct asd_sas_port *port); 239 + 240 + #else 241 + 242 + static inline int sas_ata_init(struct domain_device *dev) 243 + { 244 + return 0; 245 + } 246 + 247 + static inline void sas_ata_task_abort(struct sas_task *task) 248 + { 249 + } 250 + 251 + static inline void sas_ata_strategy_handler(struct Scsi_Host *shost) 252 + { 253 + } 254 + 255 + static inline void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q) 256 + { 257 + } 258 + 259 + static inline void sas_ata_end_eh(struct ata_port *ap) 260 + { 261 + } 262 + 263 + static inline void sas_ata_wait_eh(struct domain_device *dev) 264 + { 265 + } 266 + 267 + static inline void sas_probe_sata(struct asd_sas_port *port) 268 + { 269 + } 270 + 271 + static inline void sas_suspend_sata(struct asd_sas_port *port) 272 + { 273 + } 274 + 275 + static inline void sas_resume_sata(struct asd_sas_port *port) 276 + { 277 + } 278 + 279 + static inline void sas_ata_disabled_notice(void) 280 + { 281 + pr_notice_once("ATA device seen but CONFIG_SCSI_SAS_ATA=N\n"); 282 + } 283 + 284 + static inline int sas_discover_sata(struct domain_device *dev) 285 + { 286 + sas_ata_disabled_notice(); 287 + return -ENXIO; 288 + } 289 + 290 + static inline int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, 291 + struct domain_device *child, int phy_id) 292 + { 293 + sas_ata_disabled_notice(); 294 + return -ENODEV; 295 + } 296 + 297 + #endif 224 298 225 299 #endif /* _SAS_INTERNAL_H_ */
+3 -3
drivers/scsi/libsas/sas_phy.c
··· 20 20 struct asd_sas_phy *phy = ev->phy; 21 21 22 22 phy->error = 0; 23 - sas_deform_port(phy, 1); 23 + sas_deform_port(phy, true); 24 24 } 25 25 26 26 static void sas_phye_oob_done(struct work_struct *work) ··· 40 40 struct sas_internal *i = 41 41 to_sas_internal(sas_ha->shost->transportt); 42 42 43 - sas_deform_port(phy, 1); 43 + sas_deform_port(phy, true); 44 44 45 45 if (!port && phy->enabled && i->dft->lldd_control_phy) { 46 46 phy->error++; ··· 85 85 86 86 phy->error = 0; 87 87 phy->suspended = 0; 88 - sas_deform_port(phy, 1); 88 + sas_deform_port(phy, true); 89 89 } 90 90 91 91
+6 -7
drivers/scsi/libsas/sas_port.c
··· 113 113 114 114 if (port) { 115 115 if (!phy_is_wideport_member(port, phy)) 116 - sas_deform_port(phy, 0); 116 + sas_deform_port(phy, false); 117 117 else if (phy->suspended) { 118 118 phy->suspended = 0; 119 119 sas_resume_port(phy); ··· 206 206 * This is called when the physical link to the other phy has been 207 207 * lost (on this phy), in Event thread context. We cannot delay here. 208 208 */ 209 - void sas_deform_port(struct asd_sas_phy *phy, int gone) 209 + void sas_deform_port(struct asd_sas_phy *phy, bool gone) 210 210 { 211 211 struct sas_ha_struct *sas_ha = phy->ha; 212 212 struct asd_sas_port *port = phy->port; ··· 301 301 struct asd_sas_event *ev = to_asd_sas_event(work); 302 302 struct asd_sas_phy *phy = ev->phy; 303 303 304 - sas_deform_port(phy, 1); 304 + sas_deform_port(phy, true); 305 305 } 306 306 307 307 void sas_porte_timer_event(struct work_struct *work) ··· 309 309 struct asd_sas_event *ev = to_asd_sas_event(work); 310 310 struct asd_sas_phy *phy = ev->phy; 311 311 312 - sas_deform_port(phy, 1); 312 + sas_deform_port(phy, true); 313 313 } 314 314 315 315 void sas_porte_hard_reset(struct work_struct *work) ··· 317 317 struct asd_sas_event *ev = to_asd_sas_event(work); 318 318 struct asd_sas_phy *phy = ev->phy; 319 319 320 - sas_deform_port(phy, 1); 320 + sas_deform_port(phy, true); 321 321 } 322 322 323 323 /* ---------- SAS port registration ---------- */ ··· 358 358 359 359 for (i = 0; i < sas_ha->num_phys; i++) 360 360 if (sas_ha->sas_phy[i]->port) 361 - sas_deform_port(sas_ha->sas_phy[i], 0); 362 - 361 + sas_deform_port(sas_ha->sas_phy[i], false); 363 362 } 364 363 365 364 const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
+1 -2
drivers/scsi/mpt3sas/mpt3sas_scsih.c
··· 10809 10809 break; 10810 10810 case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 10811 10811 _scsih_pcie_topology_change_event(ioc, fw_event); 10812 - ioc->current_event = NULL; 10813 - return; 10812 + break; 10814 10813 } 10815 10814 out: 10816 10815 fw_event_work_put(fw_event);
+1 -1
drivers/scsi/scsi_scan.c
··· 1900 1900 1901 1901 return 0; 1902 1902 } 1903 - 1903 + EXPORT_SYMBOL(scsi_scan_host_selected); 1904 1904 static void scsi_sysfs_add_devices(struct Scsi_Host *shost) 1905 1905 { 1906 1906 struct scsi_device *sdev;
+2
drivers/scsi/scsi_transport_iscsi.c
··· 2143 2143 return 0; 2144 2144 2145 2145 iscsi_remove_conn(iscsi_dev_to_conn(dev)); 2146 + iscsi_put_conn(iscsi_dev_to_conn(dev)); 2147 + 2146 2148 return 0; 2147 2149 } 2148 2150
+49 -13
drivers/scsi/scsi_transport_sas.c
··· 40 40 #include <scsi/scsi_transport_sas.h> 41 41 42 42 #include "scsi_sas_internal.h" 43 + #include "scsi_priv.h" 44 + 43 45 struct sas_host_attrs { 44 46 struct list_head rphy_list; 45 47 struct mutex lock; ··· 1685 1683 } 1686 1684 EXPORT_SYMBOL(scsi_is_sas_rphy); 1687 1685 1686 + static void scan_channel_zero(struct Scsi_Host *shost, uint id, u64 lun) 1687 + { 1688 + struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1689 + struct sas_rphy *rphy; 1690 + 1691 + list_for_each_entry(rphy, &sas_host->rphy_list, list) { 1692 + if (rphy->identify.device_type != SAS_END_DEVICE || 1693 + rphy->scsi_target_id == -1) 1694 + continue; 1695 + 1696 + if (id == SCAN_WILD_CARD || id == rphy->scsi_target_id) { 1697 + scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, 1698 + lun, SCSI_SCAN_MANUAL); 1699 + } 1700 + } 1701 + } 1688 1702 1689 1703 /* 1690 1704 * SCSI scan helper ··· 1710 1692 uint id, u64 lun) 1711 1693 { 1712 1694 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1713 - struct sas_rphy *rphy; 1695 + int res = 0; 1696 + int i; 1714 1697 1715 - mutex_lock(&sas_host->lock); 1716 - list_for_each_entry(rphy, &sas_host->rphy_list, list) { 1717 - if (rphy->identify.device_type != SAS_END_DEVICE || 1718 - rphy->scsi_target_id == -1) 1719 - continue; 1698 + switch (channel) { 1699 + case 0: 1700 + mutex_lock(&sas_host->lock); 1701 + scan_channel_zero(shost, id, lun); 1702 + mutex_unlock(&sas_host->lock); 1703 + break; 1720 1704 1721 - if ((channel == SCAN_WILD_CARD || channel == 0) && 1722 - (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { 1723 - scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, 1724 - lun, SCSI_SCAN_MANUAL); 1705 + case SCAN_WILD_CARD: 1706 + mutex_lock(&sas_host->lock); 1707 + scan_channel_zero(shost, id, lun); 1708 + mutex_unlock(&sas_host->lock); 1709 + 1710 + for (i = 1; i <= shost->max_channel; i++) { 1711 + res = scsi_scan_host_selected(shost, i, id, lun, 1712 + SCSI_SCAN_MANUAL); 1713 + if (res) 1714 + goto exit_scan; 1725 1715 } 1726 - } 1727 - mutex_unlock(&sas_host->lock); 1716 + break; 1728 1717 1729 - return 0; 1718 + default: 1719 + if (channel < shost->max_channel) { 1720 + res = scsi_scan_host_selected(shost, channel, id, lun, 1721 + SCSI_SCAN_MANUAL); 1722 + } else { 1723 + res = -EINVAL; 1724 + } 1725 + break; 1726 + } 1727 + 1728 + exit_scan: 1729 + return res; 1730 1730 } 1731 1731 1732 1732
+3 -1
drivers/scsi/sd.c
··· 4173 4173 if ((system_state != SYSTEM_RESTART && 4174 4174 sdkp->device->manage_system_start_stop) || 4175 4175 (system_state == SYSTEM_POWER_OFF && 4176 - sdkp->device->manage_shutdown)) { 4176 + sdkp->device->manage_shutdown) || 4177 + (system_state == SYSTEM_RUNNING && 4178 + sdkp->device->manage_runtime_start_stop)) { 4177 4179 sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); 4178 4180 sd_start_stop_device(sdkp, 0); 4179 4181 }
+49 -16
drivers/target/target_core_fabric_lib.c
··· 257 257 return len; 258 258 } 259 259 260 - static char *iscsi_parse_pr_out_transport_id( 260 + static void sas_parse_pr_out_transport_id(char *buf, char *i_str) 261 + { 262 + char hex[17] = {}; 263 + 264 + bin2hex(hex, buf + 4, 8); 265 + snprintf(i_str, TRANSPORT_IQN_LEN, "naa.%s", hex); 266 + } 267 + 268 + static void srp_parse_pr_out_transport_id(char *buf, char *i_str) 269 + { 270 + char hex[33] = {}; 271 + 272 + bin2hex(hex, buf + 8, 16); 273 + snprintf(i_str, TRANSPORT_IQN_LEN, "0x%s", hex); 274 + } 275 + 276 + static void fcp_parse_pr_out_transport_id(char *buf, char *i_str) 277 + { 278 + snprintf(i_str, TRANSPORT_IQN_LEN, "%8phC", buf + 8); 279 + } 280 + 281 + static void sbp_parse_pr_out_transport_id(char *buf, char *i_str) 282 + { 283 + char hex[17] = {}; 284 + 285 + bin2hex(hex, buf + 8, 8); 286 + snprintf(i_str, TRANSPORT_IQN_LEN, "%s", hex); 287 + } 288 + 289 + static bool iscsi_parse_pr_out_transport_id( 261 290 struct se_portal_group *se_tpg, 262 291 char *buf, 263 292 u32 *out_tid_len, 264 - char **port_nexus_ptr) 293 + char **port_nexus_ptr, 294 + char *i_str) 265 295 { 266 296 char *p; 267 297 int i; ··· 312 282 if ((format_code != 0x00) && (format_code != 0x40)) { 313 283 pr_err("Illegal format code: 0x%02x for iSCSI" 314 284 " Initiator Transport ID\n", format_code); 315 - return NULL; 285 + return false; 316 286 } 317 287 /* 318 288 * If the caller wants the TransportID Length, we set that value for the ··· 336 306 pr_err("Unable to locate \",i,0x\" separator" 337 307 " for Initiator port identifier: %s\n", 338 308 &buf[4]); 339 - return NULL; 309 + return false; 340 310 } 341 311 *p = '\0'; /* Terminate iSCSI Name */ 342 312 p += 5; /* Skip over ",i,0x" separator */ ··· 369 339 } else 370 340 *port_nexus_ptr = NULL; 371 341 372 - return &buf[4]; 342 + strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN); 343 + return true; 373 344 } 374 345 375 346 int target_get_pr_transport_id_len(struct se_node_acl *nacl, ··· 418 387 } 419 388 } 420 389 421 - const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, 422 - char *buf, u32 *out_tid_len, char **port_nexus_ptr) 390 + bool target_parse_pr_out_transport_id(struct se_portal_group *tpg, 391 + char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str) 423 392 { 424 - u32 offset; 425 - 426 393 switch (tpg->proto_id) { 427 394 case SCSI_PROTOCOL_SAS: 428 395 /* 429 396 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID 430 397 * for initiator ports using SCSI over SAS Serial SCSI Protocol. 431 398 */ 432 - offset = 4; 399 + sas_parse_pr_out_transport_id(buf, i_str); 400 + break; 401 + case SCSI_PROTOCOL_SRP: 402 + srp_parse_pr_out_transport_id(buf, i_str); 403 + break; 404 + case SCSI_PROTOCOL_FCP: 405 + fcp_parse_pr_out_transport_id(buf, i_str); 433 406 break; 434 407 case SCSI_PROTOCOL_SBP: 435 - case SCSI_PROTOCOL_SRP: 436 - case SCSI_PROTOCOL_FCP: 437 - offset = 8; 408 + sbp_parse_pr_out_transport_id(buf, i_str); 438 409 break; 439 410 case SCSI_PROTOCOL_ISCSI: 440 411 return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len, 441 - port_nexus_ptr); 412 + port_nexus_ptr, i_str); 442 413 default: 443 414 pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id); 444 - return NULL; 415 + return false; 445 416 } 446 417 447 418 *port_nexus_ptr = NULL; 448 419 *out_tid_len = 24; 449 - return buf + offset; 420 + return true; 450 421 }
+28 -5
drivers/target/target_core_iblock.c
··· 64 64 pr_err("Unable to allocate struct iblock_dev\n"); 65 65 return NULL; 66 66 } 67 + ib_dev->ibd_exclusive = true; 67 68 68 69 ib_dev->ibd_plug = kcalloc(nr_cpu_ids, sizeof(*ib_dev->ibd_plug), 69 70 GFP_KERNEL); ··· 96 95 struct block_device *bd; 97 96 struct blk_integrity *bi; 98 97 blk_mode_t mode = BLK_OPEN_READ; 98 + void *holder = ib_dev; 99 99 unsigned int max_write_zeroes_sectors; 100 100 int ret; 101 101 ··· 111 109 goto out; 112 110 } 113 111 114 - pr_debug( "IBLOCK: Claiming struct block_device: %s\n", 115 - ib_dev->ibd_udev_path); 112 + pr_debug("IBLOCK: Claiming struct block_device: %s: %d\n", 113 + ib_dev->ibd_udev_path, ib_dev->ibd_exclusive); 116 114 117 115 if (!ib_dev->ibd_readonly) 118 116 mode |= BLK_OPEN_WRITE; 119 117 else 120 118 dev->dev_flags |= DF_READ_ONLY; 121 119 122 - bdev_file = bdev_file_open_by_path(ib_dev->ibd_udev_path, mode, ib_dev, 120 + if (!ib_dev->ibd_exclusive) 121 + holder = NULL; 122 + 123 + bdev_file = bdev_file_open_by_path(ib_dev->ibd_udev_path, mode, holder, 123 124 NULL); 124 125 if (IS_ERR(bdev_file)) { 125 126 ret = PTR_ERR(bdev_file); ··· 565 560 } 566 561 567 562 enum { 568 - Opt_udev_path, Opt_readonly, Opt_force, Opt_err 563 + Opt_udev_path, Opt_readonly, Opt_force, Opt_exclusive, Opt_err, 569 564 }; 570 565 571 566 static match_table_t tokens = { 572 567 {Opt_udev_path, "udev_path=%s"}, 573 568 {Opt_readonly, "readonly=%d"}, 574 569 {Opt_force, "force=%d"}, 570 + {Opt_exclusive, "exclusive=%d"}, 575 571 {Opt_err, NULL} 576 572 }; 577 573 ··· 582 576 struct iblock_dev *ib_dev = IBLOCK_DEV(dev); 583 577 char *orig, *ptr, *arg_p, *opts; 584 578 substring_t args[MAX_OPT_ARGS]; 585 - int ret = 0, token; 579 + int ret = 0, token, tmp_exclusive; 586 580 unsigned long tmp_readonly; 587 581 588 582 opts = kstrdup(page, GFP_KERNEL); ··· 629 623 ib_dev->ibd_readonly = tmp_readonly; 630 624 pr_debug("IBLOCK: readonly: %d\n", ib_dev->ibd_readonly); 631 625 break; 626 + case Opt_exclusive: 627 + arg_p = match_strdup(&args[0]); 628 + if (!arg_p) { 629 + ret = -ENOMEM; 630 + break; 631 + } 632 + ret = kstrtoint(arg_p, 0, &tmp_exclusive); 633 + kfree(arg_p); 634 + if (ret < 0) { 635 + pr_err("kstrtoul() failed for exclusive=\n"); 636 + goto out; 637 + } 638 + ib_dev->ibd_exclusive = tmp_exclusive; 639 + pr_debug("IBLOCK: exclusive: %d\n", 640 + ib_dev->ibd_exclusive); 641 + break; 632 642 case Opt_force: 633 643 break; 634 644 default: ··· 669 647 bl += sprintf(b + bl, " UDEV PATH: %s", 670 648 ib_dev->ibd_udev_path); 671 649 bl += sprintf(b + bl, " readonly: %d\n", ib_dev->ibd_readonly); 650 + bl += sprintf(b + bl, " exclusive: %d\n", ib_dev->ibd_exclusive); 672 651 673 652 bl += sprintf(b + bl, " "); 674 653 if (bd) {
+1
drivers/target/target_core_iblock.h
··· 34 34 struct block_device *ibd_bd; 35 35 struct file *ibd_bdev_file; 36 36 bool ibd_readonly; 37 + bool ibd_exclusive; 37 38 struct iblock_dev_plug *ibd_plug; 38 39 } ____cacheline_aligned; 39 40
+2 -2
drivers/target/target_core_internal.h
··· 103 103 int target_get_pr_transport_id(struct se_node_acl *nacl, 104 104 struct t10_pr_registration *pr_reg, int *format_code, 105 105 unsigned char *buf); 106 - const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, 107 - char *buf, u32 *out_tid_len, char **port_nexus_ptr); 106 + bool target_parse_pr_out_transport_id(struct se_portal_group *tpg, 107 + char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str); 108 108 109 109 /* target_core_hba.c */ 110 110 struct se_hba *core_alloc_hba(const char *, u32, u32);
+10 -8
drivers/target/target_core_pr.c
··· 1478 1478 LIST_HEAD(tid_dest_list); 1479 1479 struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; 1480 1480 unsigned char *buf, *ptr, proto_ident; 1481 - const unsigned char *i_str = NULL; 1481 + unsigned char i_str[TRANSPORT_IQN_LEN]; 1482 1482 char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; 1483 1483 sense_reason_t ret; 1484 1484 u32 tpdl, tid_len = 0; 1485 1485 u32 dest_rtpi = 0; 1486 + bool tid_found; 1486 1487 1487 1488 /* 1488 1489 * Allocate a struct pr_transport_id_holder and setup the ··· 1572 1571 dest_rtpi = tmp_lun->lun_tpg->tpg_rtpi; 1573 1572 1574 1573 iport_ptr = NULL; 1575 - i_str = target_parse_pr_out_transport_id(tmp_tpg, 1576 - ptr, &tid_len, &iport_ptr); 1577 - if (!i_str) 1574 + tid_found = target_parse_pr_out_transport_id(tmp_tpg, 1575 + ptr, &tid_len, &iport_ptr, i_str); 1576 + if (!tid_found) 1578 1577 continue; 1579 1578 /* 1580 1579 * Determine if this SCSI device server requires that ··· 3154 3153 struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; 3155 3154 struct t10_reservation *pr_tmpl = &dev->t10_pr; 3156 3155 unsigned char *buf; 3157 - const unsigned char *initiator_str; 3156 + unsigned char initiator_str[TRANSPORT_IQN_LEN]; 3158 3157 char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN] = { }; 3159 3158 u32 tid_len, tmp_tid_len; 3160 3159 int new_reg = 0, type, scope, matching_iname; 3161 3160 sense_reason_t ret; 3162 3161 unsigned short rtpi; 3163 3162 unsigned char proto_ident; 3163 + bool tid_found; 3164 3164 3165 3165 if (!se_sess || !se_lun) { 3166 3166 pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); ··· 3280 3278 ret = TCM_INVALID_PARAMETER_LIST; 3281 3279 goto out; 3282 3280 } 3283 - initiator_str = target_parse_pr_out_transport_id(dest_se_tpg, 3284 - &buf[24], &tmp_tid_len, &iport_ptr); 3285 - if (!initiator_str) { 3281 + tid_found = target_parse_pr_out_transport_id(dest_se_tpg, 3282 + &buf[24], &tmp_tid_len, &iport_ptr, initiator_str); 3283 + if (!tid_found) { 3286 3284 pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" 3287 3285 " initiator_str from Transport ID\n"); 3288 3286 ret = TCM_INVALID_PARAMETER_LIST;
+2 -1
drivers/ufs/core/ufs-sysfs.c
··· 5 5 #include <linux/string.h> 6 6 #include <linux/bitfield.h> 7 7 #include <linux/unaligned.h> 8 + #include <linux/string_choices.h> 8 9 9 10 #include <ufs/ufs.h> 10 11 #include <ufs/unipro.h> ··· 1517 1516 ret = -EINVAL; \ 1518 1517 goto out; \ 1519 1518 } \ 1520 - ret = sysfs_emit(buf, "%s\n", flag ? "true" : "false"); \ 1519 + ret = sysfs_emit(buf, "%s\n", str_true_false(flag)); \ 1521 1520 out: \ 1522 1521 up(&hba->host_sem); \ 1523 1522 return ret; \
+49 -56
drivers/ufs/core/ufshcd.c
··· 364 364 } 365 365 EXPORT_SYMBOL_GPL(ufshcd_disable_irq); 366 366 367 + /** 368 + * ufshcd_enable_intr - enable interrupts 369 + * @hba: per adapter instance 370 + * @intrs: interrupt bits 371 + */ 372 + static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) 373 + { 374 + u32 old_val = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 375 + u32 new_val = old_val | intrs; 376 + 377 + if (new_val != old_val) 378 + ufshcd_writel(hba, new_val, REG_INTERRUPT_ENABLE); 379 + } 380 + 381 + /** 382 + * ufshcd_disable_intr - disable interrupts 383 + * @hba: per adapter instance 384 + * @intrs: interrupt bits 385 + */ 386 + static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs) 387 + { 388 + u32 old_val = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 389 + u32 new_val = old_val & ~intrs; 390 + 391 + if (new_val != old_val) 392 + ufshcd_writel(hba, new_val, REG_INTERRUPT_ENABLE); 393 + } 394 + 367 395 static void ufshcd_configure_wb(struct ufs_hba *hba) 368 396 { 369 397 if (!ufshcd_is_wb_allowed(hba)) ··· 2624 2596 */ 2625 2597 int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) 2626 2598 { 2599 + unsigned long flags; 2627 2600 int ret; 2628 2601 2629 2602 if (hba->quirks & UFSHCD_QUIRK_BROKEN_UIC_CMD) ··· 2633 2604 ufshcd_hold(hba); 2634 2605 mutex_lock(&hba->uic_cmd_mutex); 2635 2606 ufshcd_add_delay_before_dme_cmd(hba); 2607 + 2608 + spin_lock_irqsave(hba->host->host_lock, flags); 2609 + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); 2610 + spin_unlock_irqrestore(hba->host->host_lock, flags); 2636 2611 2637 2612 ret = __ufshcd_send_uic_cmd(hba, uic_cmd); 2638 2613 if (!ret) ··· 2712 2679 ufshcd_sgl_to_prdt(hba, lrbp, sg_segments, scsi_sglist(cmd)); 2713 2680 2714 2681 return ufshcd_crypto_fill_prdt(hba, lrbp); 2715 - } 2716 - 2717 - /** 2718 - * ufshcd_enable_intr - enable interrupts 2719 - * @hba: per adapter instance 2720 - * @intrs: interrupt bits 2721 - */ 2722 - static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) 2723 - { 2724 - u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 2725 - 2726 - set |= intrs; 2727 - ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); 2728 - } 2729 - 2730 - /** 2731 - * ufshcd_disable_intr - disable interrupts 2732 - * @hba: per adapter instance 2733 - * @intrs: interrupt bits 2734 - */ 2735 - static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs) 2736 - { 2737 - u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 2738 - 2739 - set &= ~intrs; 2740 - ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); 2741 2682 } 2742 2683 2743 2684 /** ··· 4325 4318 unsigned long flags; 4326 4319 u8 status; 4327 4320 int ret; 4328 - bool reenable_intr = false; 4329 4321 4330 4322 mutex_lock(&hba->uic_cmd_mutex); 4331 4323 ufshcd_add_delay_before_dme_cmd(hba); ··· 4335 4329 goto out_unlock; 4336 4330 } 4337 4331 hba->uic_async_done = &uic_async_done; 4338 - if (ufshcd_readl(hba, REG_INTERRUPT_ENABLE) & UIC_COMMAND_COMPL) { 4339 - ufshcd_disable_intr(hba, UIC_COMMAND_COMPL); 4340 - /* 4341 - * Make sure UIC command completion interrupt is disabled before 4342 - * issuing UIC command. 4343 - */ 4344 - ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 4345 - reenable_intr = true; 4346 - } 4332 + ufshcd_disable_intr(hba, UIC_COMMAND_COMPL); 4347 4333 spin_unlock_irqrestore(hba->host->host_lock, flags); 4348 4334 ret = __ufshcd_send_uic_cmd(hba, cmd); 4349 4335 if (ret) { ··· 4379 4381 spin_lock_irqsave(hba->host->host_lock, flags); 4380 4382 hba->active_uic_cmd = NULL; 4381 4383 hba->uic_async_done = NULL; 4382 - if (reenable_intr) 4383 - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL); 4384 - if (ret) { 4384 + if (ret && !hba->pm_op_in_progress) { 4385 4385 ufshcd_set_link_broken(hba); 4386 4386 ufshcd_schedule_eh_work(hba); 4387 4387 } 4388 4388 out_unlock: 4389 4389 spin_unlock_irqrestore(hba->host->host_lock, flags); 4390 4390 mutex_unlock(&hba->uic_cmd_mutex); 4391 + 4392 + /* 4393 + * If the h8 exit fails during the runtime resume process, it becomes 4394 + * stuck and cannot be recovered through the error handler. To fix 4395 + * this, use link recovery instead of the error handler. 4396 + */ 4397 + if (ret && hba->pm_op_in_progress) 4398 + ret = ufshcd_link_recovery(hba); 4391 4399 4392 4400 return ret; 4393 4401 } ··· 4409 4405 { 4410 4406 int ret; 4411 4407 4408 + if (uic_cmd->argument1 != UIC_ARG_MIB(PA_PWRMODE) || 4409 + uic_cmd->command != UIC_CMD_DME_SET) 4410 + return ufshcd_send_uic_cmd(hba, uic_cmd); 4411 + 4412 4412 if (hba->quirks & UFSHCD_QUIRK_BROKEN_UIC_CMD) 4413 4413 return 0; 4414 4414 4415 4415 ufshcd_hold(hba); 4416 - 4417 - if (uic_cmd->argument1 == UIC_ARG_MIB(PA_PWRMODE) && 4418 - uic_cmd->command == UIC_CMD_DME_SET) { 4419 - ret = ufshcd_uic_pwr_ctrl(hba, uic_cmd); 4420 - goto out; 4421 - } 4422 - 4423 - mutex_lock(&hba->uic_cmd_mutex); 4424 - ufshcd_add_delay_before_dme_cmd(hba); 4425 - 4426 - ret = __ufshcd_send_uic_cmd(hba, uic_cmd); 4427 - if (!ret) 4428 - ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); 4429 - 4430 - mutex_unlock(&hba->uic_cmd_mutex); 4431 - 4432 - out: 4416 + ret = ufshcd_uic_pwr_ctrl(hba, uic_cmd); 4433 4417 ufshcd_release(hba); 4418 + 4434 4419 return ret; 4435 4420 } 4436 4421
+297 -33
drivers/ufs/host/ufs-mediatek.c
··· 50 50 51 51 static const struct of_device_id ufs_mtk_of_match[] = { 52 52 { .compatible = "mediatek,mt8183-ufshci" }, 53 + { .compatible = "mediatek,mt8195-ufshci" }, 53 54 {}, 54 55 }; 55 56 MODULE_DEVICE_TABLE(of, ufs_mtk_of_match); ··· 97 96 { 98 97 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 99 98 100 - return !!(host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE); 99 + return host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE; 101 100 } 102 101 103 102 static bool ufs_mtk_is_va09_supported(struct ufs_hba *hba) 104 103 { 105 104 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 106 105 107 - return !!(host->caps & UFS_MTK_CAP_VA09_PWR_CTRL); 106 + return host->caps & UFS_MTK_CAP_VA09_PWR_CTRL; 108 107 } 109 108 110 109 static bool ufs_mtk_is_broken_vcc(struct ufs_hba *hba) 111 110 { 112 111 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 113 112 114 - return !!(host->caps & UFS_MTK_CAP_BROKEN_VCC); 113 + return host->caps & UFS_MTK_CAP_BROKEN_VCC; 115 114 } 116 115 117 116 static bool ufs_mtk_is_pmc_via_fastauto(struct ufs_hba *hba) 118 117 { 119 118 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 120 119 121 - return !!(host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO); 120 + return host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO; 122 121 } 123 122 124 123 static bool ufs_mtk_is_tx_skew_fix(struct ufs_hba *hba) 125 124 { 126 125 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 127 126 128 - return (host->caps & UFS_MTK_CAP_TX_SKEW_FIX); 127 + return host->caps & UFS_MTK_CAP_TX_SKEW_FIX; 129 128 } 130 129 131 130 static bool ufs_mtk_is_rtff_mtcmos(struct ufs_hba *hba) 132 131 { 133 132 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 134 133 135 - return (host->caps & UFS_MTK_CAP_RTFF_MTCMOS); 134 + return host->caps & UFS_MTK_CAP_RTFF_MTCMOS; 136 135 } 137 136 138 137 static bool ufs_mtk_is_allow_vccqx_lpm(struct ufs_hba *hba) 139 138 { 140 139 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 141 140 142 - return (host->caps & UFS_MTK_CAP_ALLOW_VCCQX_LPM); 141 + return host->caps & UFS_MTK_CAP_ALLOW_VCCQX_LPM; 142 + } 143 + 144 + static bool ufs_mtk_is_clk_scale_ready(struct ufs_hba *hba) 145 + { 146 + struct ufs_mtk_host *host = ufshcd_get_variant(hba); 147 + struct ufs_mtk_clk *mclk = &host->mclk; 148 + 149 + return mclk->ufs_sel_clki && 150 + mclk->ufs_sel_max_clki && 151 + mclk->ufs_sel_min_clki; 143 152 } 144 153 145 154 static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) ··· 278 267 ufshcd_writel(hba, 279 268 ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) | 0x80, 280 269 REG_UFS_XOUFS_CTRL); 270 + 271 + /* DDR_EN setting */ 272 + if (host->ip_ver >= IP_VER_MT6989) { 273 + ufshcd_rmwl(hba, UFS_MASK(0x7FFF, 8), 274 + 0x453000, REG_UFS_MMIO_OPT_CTRL_0); 275 + } 276 + 281 277 } 282 278 283 279 return 0; ··· 362 344 363 345 dev_err(hba->dev, "missing ack of refclk req, reg: 0x%x\n", value); 364 346 365 - ufs_mtk_ref_clk_notify(host->ref_clk_enabled, POST_CHANGE, res); 347 + /* 348 + * If clock on timeout, assume clock is off, notify tfa do clock 349 + * off setting.(keep DIFN disable, release resource) 350 + * If clock off timeout, assume clock will off finally, 351 + * set ref_clk_enabled directly.(keep DIFN disable, keep resource) 352 + */ 353 + if (on) 354 + ufs_mtk_ref_clk_notify(false, POST_CHANGE, res); 355 + else 356 + host->ref_clk_enabled = false; 366 357 367 358 return -ETIMEDOUT; 368 359 ··· 690 663 if (of_property_read_bool(np, "mediatek,ufs-rtff-mtcmos")) 691 664 host->caps |= UFS_MTK_CAP_RTFF_MTCMOS; 692 665 666 + if (of_property_read_bool(np, "mediatek,ufs-broken-rtc")) 667 + host->caps |= UFS_MTK_CAP_MCQ_BROKEN_RTC; 668 + 693 669 dev_info(hba->dev, "caps: 0x%x", host->caps); 694 670 } 695 671 ··· 809 779 return ret; 810 780 } 811 781 782 + static u32 ufs_mtk_mcq_get_irq(struct ufs_hba *hba, unsigned int cpu) 783 + { 784 + struct ufs_mtk_host *host = ufshcd_get_variant(hba); 785 + struct blk_mq_tag_set *tag_set = &hba->host->tag_set; 786 + struct blk_mq_queue_map *map = &tag_set->map[HCTX_TYPE_DEFAULT]; 787 + unsigned int nr = map->nr_queues; 788 + unsigned int q_index; 789 + 790 + q_index = map->mq_map[cpu]; 791 + if (q_index > nr) { 792 + dev_err(hba->dev, "hwq index %d exceed %d\n", 793 + q_index, nr); 794 + return MTK_MCQ_INVALID_IRQ; 795 + } 796 + 797 + return host->mcq_intr_info[q_index].irq; 798 + } 799 + 800 + static void ufs_mtk_mcq_set_irq_affinity(struct ufs_hba *hba, unsigned int cpu) 801 + { 802 + unsigned int irq, _cpu; 803 + int ret; 804 + 805 + irq = ufs_mtk_mcq_get_irq(hba, cpu); 806 + if (irq == MTK_MCQ_INVALID_IRQ) { 807 + dev_err(hba->dev, "invalid irq. unable to bind irq to cpu%d", cpu); 808 + return; 809 + } 810 + 811 + /* force migrate irq of cpu0 to cpu3 */ 812 + _cpu = (cpu == 0) ? 3 : cpu; 813 + ret = irq_set_affinity(irq, cpumask_of(_cpu)); 814 + if (ret) { 815 + dev_err(hba->dev, "set irq %d affinity to CPU %d failed\n", 816 + irq, _cpu); 817 + return; 818 + } 819 + dev_info(hba->dev, "set irq %d affinity to CPU: %d\n", irq, _cpu); 820 + } 821 + 822 + static bool ufs_mtk_is_legacy_chipset(struct ufs_hba *hba, u32 hw_ip_ver) 823 + { 824 + bool is_legacy = false; 825 + 826 + switch (hw_ip_ver) { 827 + case IP_LEGACY_VER_MT6893: 828 + case IP_LEGACY_VER_MT6781: 829 + /* can add other legacy chipset ID here accordingly */ 830 + is_legacy = true; 831 + break; 832 + default: 833 + break; 834 + } 835 + dev_info(hba->dev, "legacy IP version - 0x%x, is legacy : %d", hw_ip_ver, is_legacy); 836 + 837 + return is_legacy; 838 + } 839 + 840 + /* 841 + * HW version format has been changed from 01MMmmmm to 1MMMmmmm, since 842 + * project MT6878. In order to perform correct version comparison, 843 + * version number is changed by SW for the following projects. 844 + * IP_VER_MT6983 0x00360000 to 0x10360000 845 + * IP_VER_MT6897 0x01440000 to 0x10440000 846 + * IP_VER_MT6989 0x01450000 to 0x10450000 847 + * IP_VER_MT6991 0x01460000 to 0x10460000 848 + */ 849 + static void ufs_mtk_get_hw_ip_version(struct ufs_hba *hba) 850 + { 851 + struct ufs_mtk_host *host = ufshcd_get_variant(hba); 852 + u32 hw_ip_ver; 853 + 854 + hw_ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER); 855 + 856 + if (((hw_ip_ver & (0xFF << 24)) == (0x1 << 24)) || 857 + ((hw_ip_ver & (0xFF << 24)) == 0)) { 858 + hw_ip_ver &= ~(0xFF << 24); 859 + hw_ip_ver |= (0x1 << 28); 860 + } 861 + 862 + host->ip_ver = hw_ip_ver; 863 + 864 + host->legacy_ip_ver = ufs_mtk_is_legacy_chipset(hba, hw_ip_ver); 865 + } 866 + 812 867 static void ufs_mtk_get_controller_version(struct ufs_hba *hba) 813 868 { 814 869 struct ufs_mtk_host *host = ufshcd_get_variant(hba); ··· 933 818 { 934 819 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 935 820 struct list_head *head = &hba->clk_list_head; 936 - struct ufs_mtk_clk *mclk = &host->mclk; 937 821 struct ufs_clk_info *clki, *clki_tmp; 822 + struct device *dev = hba->dev; 823 + struct regulator *reg; 824 + u32 volt; 938 825 939 826 /* 940 827 * Find private clocks and store them in struct ufs_mtk_clk. ··· 954 837 host->mclk.ufs_sel_min_clki = clki; 955 838 clk_disable_unprepare(clki->clk); 956 839 list_del(&clki->list); 840 + } else if (!strcmp(clki->name, "ufs_fde")) { 841 + host->mclk.ufs_fde_clki = clki; 842 + } else if (!strcmp(clki->name, "ufs_fde_max_src")) { 843 + host->mclk.ufs_fde_max_clki = clki; 844 + clk_disable_unprepare(clki->clk); 845 + list_del(&clki->list); 846 + } else if (!strcmp(clki->name, "ufs_fde_min_src")) { 847 + host->mclk.ufs_fde_min_clki = clki; 848 + clk_disable_unprepare(clki->clk); 849 + list_del(&clki->list); 957 850 } 958 851 } 959 852 960 - if (!mclk->ufs_sel_clki || !mclk->ufs_sel_max_clki || 961 - !mclk->ufs_sel_min_clki) { 853 + list_for_each_entry(clki, head, list) { 854 + dev_info(hba->dev, "clk \"%s\" present", clki->name); 855 + } 856 + 857 + if (!ufs_mtk_is_clk_scale_ready(hba)) { 962 858 hba->caps &= ~UFSHCD_CAP_CLK_SCALING; 963 859 dev_info(hba->dev, 964 860 "%s: Clk-scaling not ready. Feature disabled.", 965 861 __func__); 862 + return; 863 + } 864 + 865 + /* 866 + * Default get vcore if dts have these settings. 867 + * No matter clock scaling support or not. (may disable by customer) 868 + */ 869 + reg = devm_regulator_get_optional(dev, "dvfsrc-vcore"); 870 + if (IS_ERR(reg)) { 871 + dev_info(dev, "failed to get dvfsrc-vcore: %ld", 872 + PTR_ERR(reg)); 873 + return; 874 + } 875 + 876 + if (of_property_read_u32(dev->of_node, "clk-scale-up-vcore-min", 877 + &volt)) { 878 + dev_info(dev, "failed to get clk-scale-up-vcore-min"); 879 + return; 880 + } 881 + 882 + host->mclk.reg_vcore = reg; 883 + host->mclk.vcore_volt = volt; 884 + 885 + /* If default boot is max gear, request vcore */ 886 + if (reg && volt && host->clk_scale_up) { 887 + if (regulator_set_voltage(reg, volt, INT_MAX)) { 888 + dev_info(hba->dev, 889 + "Failed to set vcore to %d\n", volt); 890 + } 966 891 } 967 892 } 968 893 ··· 1173 1014 1174 1015 /* Enable clk scaling*/ 1175 1016 hba->caps |= UFSHCD_CAP_CLK_SCALING; 1017 + host->clk_scale_up = true; /* default is max freq */ 1176 1018 1177 1019 /* Set runtime pm delay to replace default */ 1178 1020 shost->rpm_autosuspend_delay = MTK_RPM_AUTOSUSPEND_DELAY_MS; 1179 1021 1180 1022 hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL; 1023 + 1181 1024 hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_INTR; 1182 - hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_RTC; 1025 + if (host->caps & UFS_MTK_CAP_MCQ_BROKEN_RTC) 1026 + hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_RTC; 1027 + 1183 1028 hba->vps->wb_flush_threshold = UFS_WB_BUF_REMAIN_PERCENT(80); 1184 1029 1185 1030 if (host->caps & UFS_MTK_CAP_DISABLE_AH8) ··· 1213 1050 1214 1051 ufs_mtk_setup_clocks(hba, true, POST_CHANGE); 1215 1052 1216 - host->ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER); 1053 + ufs_mtk_get_hw_ip_version(hba); 1217 1054 1218 1055 goto out; 1219 1056 ··· 1668 1505 { 1669 1506 struct ufs_dev_info *dev_info = &hba->dev_info; 1670 1507 u16 mid = dev_info->wmanufacturerid; 1508 + unsigned int cpu; 1509 + 1510 + if (hba->mcq_enabled) { 1511 + /* Iterate all cpus to set affinity for mcq irqs */ 1512 + for (cpu = 0; cpu < nr_cpu_ids; cpu++) 1513 + ufs_mtk_mcq_set_irq_affinity(hba, cpu); 1514 + } 1671 1515 1672 1516 if (mid == UFS_VENDOR_SAMSUNG) { 1673 1517 ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 6); ··· 1768 1598 hba->vps->ondemand_data.downdifferential = 20; 1769 1599 } 1770 1600 1601 + static void _ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up) 1602 + { 1603 + struct ufs_mtk_host *host = ufshcd_get_variant(hba); 1604 + struct ufs_mtk_clk *mclk = &host->mclk; 1605 + struct ufs_clk_info *clki = mclk->ufs_sel_clki; 1606 + struct ufs_clk_info *fde_clki = mclk->ufs_fde_clki; 1607 + struct regulator *reg; 1608 + int volt, ret = 0; 1609 + bool clk_bind_vcore = false; 1610 + bool clk_fde_scale = false; 1611 + 1612 + if (!hba->clk_scaling.is_initialized) 1613 + return; 1614 + 1615 + if (!clki || !fde_clki) 1616 + return; 1617 + 1618 + reg = host->mclk.reg_vcore; 1619 + volt = host->mclk.vcore_volt; 1620 + if (reg && volt != 0) 1621 + clk_bind_vcore = true; 1622 + 1623 + if (mclk->ufs_fde_max_clki && mclk->ufs_fde_min_clki) 1624 + clk_fde_scale = true; 1625 + 1626 + ret = clk_prepare_enable(clki->clk); 1627 + if (ret) { 1628 + dev_info(hba->dev, 1629 + "clk_prepare_enable() fail, ret: %d\n", ret); 1630 + return; 1631 + } 1632 + 1633 + if (clk_fde_scale) { 1634 + ret = clk_prepare_enable(fde_clki->clk); 1635 + if (ret) { 1636 + dev_info(hba->dev, 1637 + "fde clk_prepare_enable() fail, ret: %d\n", ret); 1638 + return; 1639 + } 1640 + } 1641 + 1642 + if (scale_up) { 1643 + if (clk_bind_vcore) { 1644 + ret = regulator_set_voltage(reg, volt, INT_MAX); 1645 + if (ret) { 1646 + dev_info(hba->dev, 1647 + "Failed to set vcore to %d\n", volt); 1648 + goto out; 1649 + } 1650 + } 1651 + 1652 + ret = clk_set_parent(clki->clk, mclk->ufs_sel_max_clki->clk); 1653 + if (ret) { 1654 + dev_info(hba->dev, "Failed to set clk mux, ret = %d\n", 1655 + ret); 1656 + } 1657 + 1658 + if (clk_fde_scale) { 1659 + ret = clk_set_parent(fde_clki->clk, 1660 + mclk->ufs_fde_max_clki->clk); 1661 + if (ret) { 1662 + dev_info(hba->dev, 1663 + "Failed to set fde clk mux, ret = %d\n", 1664 + ret); 1665 + } 1666 + } 1667 + } else { 1668 + if (clk_fde_scale) { 1669 + ret = clk_set_parent(fde_clki->clk, 1670 + mclk->ufs_fde_min_clki->clk); 1671 + if (ret) { 1672 + dev_info(hba->dev, 1673 + "Failed to set fde clk mux, ret = %d\n", 1674 + ret); 1675 + goto out; 1676 + } 1677 + } 1678 + 1679 + ret = clk_set_parent(clki->clk, mclk->ufs_sel_min_clki->clk); 1680 + if (ret) { 1681 + dev_info(hba->dev, "Failed to set clk mux, ret = %d\n", 1682 + ret); 1683 + goto out; 1684 + } 1685 + 1686 + if (clk_bind_vcore) { 1687 + ret = regulator_set_voltage(reg, 0, INT_MAX); 1688 + if (ret) { 1689 + dev_info(hba->dev, 1690 + "failed to set vcore to MIN\n"); 1691 + } 1692 + } 1693 + } 1694 + 1695 + out: 1696 + clk_disable_unprepare(clki->clk); 1697 + 1698 + if (clk_fde_scale) 1699 + clk_disable_unprepare(fde_clki->clk); 1700 + } 1701 + 1771 1702 /** 1772 1703 * ufs_mtk_clk_scale - Internal clk scaling operation 1773 1704 * ··· 1886 1615 struct ufs_mtk_host *host = ufshcd_get_variant(hba); 1887 1616 struct ufs_mtk_clk *mclk = &host->mclk; 1888 1617 struct ufs_clk_info *clki = mclk->ufs_sel_clki; 1889 - int ret = 0; 1890 1618 1891 - ret = clk_prepare_enable(clki->clk); 1892 - if (ret) { 1893 - dev_info(hba->dev, 1894 - "clk_prepare_enable() fail, ret: %d\n", ret); 1895 - return; 1896 - } 1619 + if (host->clk_scale_up == scale_up) 1620 + goto out; 1897 1621 1898 - if (scale_up) { 1899 - ret = clk_set_parent(clki->clk, mclk->ufs_sel_max_clki->clk); 1622 + if (scale_up) 1623 + _ufs_mtk_clk_scale(hba, true); 1624 + else 1625 + _ufs_mtk_clk_scale(hba, false); 1626 + 1627 + host->clk_scale_up = scale_up; 1628 + 1629 + /* Must always set before clk_set_rate() */ 1630 + if (scale_up) 1900 1631 clki->curr_freq = clki->max_freq; 1901 - } else { 1902 - ret = clk_set_parent(clki->clk, mclk->ufs_sel_min_clki->clk); 1632 + else 1903 1633 clki->curr_freq = clki->min_freq; 1904 - } 1905 - 1906 - if (ret) { 1907 - dev_info(hba->dev, 1908 - "Failed to set ufs_sel_clki, ret: %d\n", ret); 1909 - } 1910 - 1911 - clk_disable_unprepare(clki->clk); 1912 - 1634 + out: 1913 1635 trace_ufs_mtk_clk_scale(clki->name, scale_up, clk_get_rate(clki->clk)); 1914 1636 } 1915 1637
+32
drivers/ufs/host/ufs-mediatek.h
··· 133 133 UFS_MTK_CAP_DISABLE_MCQ = 1 << 8, 134 134 /* Control MTCMOS with RTFF */ 135 135 UFS_MTK_CAP_RTFF_MTCMOS = 1 << 9, 136 + 137 + UFS_MTK_CAP_MCQ_BROKEN_RTC = 1 << 10, 136 138 }; 137 139 138 140 struct ufs_mtk_crypt_cfg { ··· 149 147 struct ufs_clk_info *ufs_sel_clki; /* Mux */ 150 148 struct ufs_clk_info *ufs_sel_max_clki; /* Max src */ 151 149 struct ufs_clk_info *ufs_sel_min_clki; /* Min src */ 150 + struct ufs_clk_info *ufs_fde_clki; /* Mux */ 151 + struct ufs_clk_info *ufs_fde_max_clki; /* Max src */ 152 + struct ufs_clk_info *ufs_fde_min_clki; /* Min src */ 153 + struct regulator *reg_vcore; 154 + int vcore_volt; 152 155 }; 153 156 154 157 struct ufs_mtk_hw_ver { ··· 183 176 bool mphy_powered_on; 184 177 bool unipro_lpm; 185 178 bool ref_clk_enabled; 179 + bool clk_scale_up; 186 180 u16 ref_clk_ungating_wait_us; 187 181 u16 ref_clk_gating_wait_us; 188 182 u32 ip_ver; 183 + bool legacy_ip_ver; 189 184 190 185 bool mcq_set_intr; 191 186 bool is_mcq_intr_enabled; ··· 200 191 201 192 /* MTK RTT support number */ 202 193 #define MTK_MAX_NUM_RTT 2 194 + 195 + /* UFSHCI MTK ip version value */ 196 + enum { 197 + /* UFSHCI 3.1 */ 198 + IP_VER_MT6983 = 0x10360000, 199 + IP_VER_MT6878 = 0x10420200, 200 + 201 + /* UFSHCI 4.0 */ 202 + IP_VER_MT6897 = 0x10440000, 203 + IP_VER_MT6989 = 0x10450000, 204 + IP_VER_MT6899 = 0x10450100, 205 + IP_VER_MT6991_A0 = 0x10460000, 206 + IP_VER_MT6991_B0 = 0x10470000, 207 + IP_VER_MT6993 = 0x10480000, 208 + 209 + IP_VER_NONE = 0xFFFFFFFF 210 + }; 211 + 212 + enum ip_ver_legacy { 213 + IP_LEGACY_VER_MT6781 = 0x10380000, 214 + IP_LEGACY_VER_MT6879 = 0x10360000, 215 + IP_LEGACY_VER_MT6893 = 0x20160706 216 + }; 203 217 204 218 #endif /* !_UFS_MEDIATEK_H */
-8
drivers/ufs/host/ufs-qcom.c
··· 1898 1898 return 0; 1899 1899 } 1900 1900 1901 - #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) 1902 1901 static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, 1903 1902 struct devfreq_dev_profile *p, 1904 1903 struct devfreq_simple_ondemand_data *d) ··· 1909 1910 1910 1911 hba->clk_scaling.suspend_on_no_request = true; 1911 1912 } 1912 - #else 1913 - static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, 1914 - struct devfreq_dev_profile *p, 1915 - struct devfreq_simple_ondemand_data *data) 1916 - { 1917 - } 1918 - #endif 1919 1913 1920 1914 /* Resources */ 1921 1915 static const struct ufshcd_res_info ufs_res_info[RES_MAX] = {
+9 -24
drivers/ufs/host/ufshcd-pci.c
··· 22 22 23 23 #define MAX_SUPP_MAC 64 24 24 25 - struct ufs_host { 26 - void (*late_init)(struct ufs_hba *hba); 27 - }; 28 - 29 25 enum intel_ufs_dsm_func_id { 30 26 INTEL_DSM_FNS = 0, 31 27 INTEL_DSM_RESET = 1, 32 28 }; 33 29 34 30 struct intel_host { 35 - struct ufs_host ufs_host; 36 31 u32 dsm_fns; 37 32 u32 active_ltr; 38 33 u32 idle_ltr; ··· 403 408 return ufs_intel_common_init(hba); 404 409 } 405 410 406 - static void ufs_intel_lkf_late_init(struct ufs_hba *hba) 411 + static int ufs_intel_lkf_init(struct ufs_hba *hba) 407 412 { 413 + int err; 414 + 415 + hba->nop_out_timeout = 200; 416 + hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; 417 + hba->caps |= UFSHCD_CAP_CRYPTO; 418 + err = ufs_intel_common_init(hba); 408 419 /* LKF always needs a full reset, so set PM accordingly */ 409 420 if (hba->caps & UFSHCD_CAP_DEEPSLEEP) { 410 421 hba->spm_lvl = UFS_PM_LVL_6; ··· 419 418 hba->spm_lvl = UFS_PM_LVL_5; 420 419 hba->rpm_lvl = UFS_PM_LVL_5; 421 420 } 422 - } 423 - 424 - static int ufs_intel_lkf_init(struct ufs_hba *hba) 425 - { 426 - struct ufs_host *ufs_host; 427 - int err; 428 - 429 - hba->nop_out_timeout = 200; 430 - hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; 431 - hba->caps |= UFSHCD_CAP_CRYPTO; 432 - err = ufs_intel_common_init(hba); 433 - ufs_host = ufshcd_get_variant(hba); 434 - ufs_host->late_init = ufs_intel_lkf_late_init; 435 421 return err; 436 422 } 437 423 ··· 432 444 433 445 static int ufs_intel_mtl_init(struct ufs_hba *hba) 434 446 { 447 + hba->rpm_lvl = UFS_PM_LVL_2; 448 + hba->spm_lvl = UFS_PM_LVL_2; 435 449 hba->caps |= UFSHCD_CAP_CRYPTO | UFSHCD_CAP_WB_EN; 436 450 return ufs_intel_common_init(hba); 437 451 } ··· 564 574 static int 565 575 ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 566 576 { 567 - struct ufs_host *ufs_host; 568 577 struct ufs_hba *hba; 569 578 void __iomem *mmio_base; 570 579 int err; ··· 595 606 dev_err(&pdev->dev, "Initialization failed\n"); 596 607 return err; 597 608 } 598 - 599 - ufs_host = ufshcd_get_variant(hba); 600 - if (ufs_host && ufs_host->late_init) 601 - ufs_host->late_init(hba); 602 609 603 610 pm_runtime_put_noidle(&pdev->dev); 604 611 pm_runtime_allow(&pdev->dev);
+35 -3
drivers/vfio/device_cdev.c
··· 60 60 spin_unlock(&df->kvm_ref_lock); 61 61 } 62 62 63 + static int vfio_df_check_token(struct vfio_device *device, 64 + const struct vfio_device_bind_iommufd *bind) 65 + { 66 + uuid_t uuid; 67 + 68 + if (!device->ops->match_token_uuid) { 69 + if (bind->flags & VFIO_DEVICE_BIND_FLAG_TOKEN) 70 + return -EINVAL; 71 + return 0; 72 + } 73 + 74 + if (!(bind->flags & VFIO_DEVICE_BIND_FLAG_TOKEN)) 75 + return device->ops->match_token_uuid(device, NULL); 76 + 77 + if (copy_from_user(&uuid, u64_to_user_ptr(bind->token_uuid_ptr), 78 + sizeof(uuid))) 79 + return -EFAULT; 80 + return device->ops->match_token_uuid(device, &uuid); 81 + } 82 + 63 83 long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df, 64 84 struct vfio_device_bind_iommufd __user *arg) 65 85 { 86 + const u32 VALID_FLAGS = VFIO_DEVICE_BIND_FLAG_TOKEN; 66 87 struct vfio_device *device = df->device; 67 88 struct vfio_device_bind_iommufd bind; 68 89 unsigned long minsz; 90 + u32 user_size; 69 91 int ret; 70 92 71 93 static_assert(__same_type(arg->out_devid, df->devid)); 72 94 73 95 minsz = offsetofend(struct vfio_device_bind_iommufd, out_devid); 74 96 75 - if (copy_from_user(&bind, arg, minsz)) 76 - return -EFAULT; 97 + ret = get_user(user_size, &arg->argsz); 98 + if (ret) 99 + return ret; 100 + if (user_size < minsz) 101 + return -EINVAL; 102 + ret = copy_struct_from_user(&bind, minsz, arg, user_size); 103 + if (ret) 104 + return ret; 77 105 78 - if (bind.argsz < minsz || bind.flags || bind.iommufd < 0) 106 + if (bind.iommufd < 0 || bind.flags & ~VALID_FLAGS) 79 107 return -EINVAL; 80 108 81 109 /* BIND_IOMMUFD only allowed for cdev fds */ ··· 120 92 ret = -EINVAL; 121 93 goto out_unlock; 122 94 } 95 + 96 + ret = vfio_df_check_token(device, &bind); 97 + if (ret) 98 + goto out_unlock; 123 99 124 100 df->iommufd = iommufd_ctx_from_fd(bind.iommufd); 125 101 if (IS_ERR(df->iommufd)) {
+3 -4
drivers/vfio/group.c
··· 192 192 * implies they expected translation to exist 193 193 */ 194 194 if (!capable(CAP_SYS_RAWIO) || 195 - vfio_iommufd_device_has_compat_ioas(device, df->iommufd)) 195 + vfio_iommufd_device_has_compat_ioas(device, df->iommufd)) { 196 196 ret = -EPERM; 197 - else 198 - ret = 0; 199 - goto out_put_kvm; 197 + goto out_put_kvm; 198 + } 200 199 } 201 200 202 201 ret = vfio_df_open(df);
+4
drivers/vfio/iommufd.c
··· 25 25 26 26 lockdep_assert_held(&vdev->dev_set->lock); 27 27 28 + /* Returns 0 to permit device opening under noiommu mode */ 29 + if (vfio_device_is_noiommu(vdev)) 30 + return 0; 31 + 28 32 return vdev->ops->bind_iommufd(vdev, ictx, &df->devid); 29 33 } 30 34
+1
drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
··· 1583 1583 .mmap = vfio_pci_core_mmap, 1584 1584 .request = vfio_pci_core_request, 1585 1585 .match = vfio_pci_core_match, 1586 + .match_token_uuid = vfio_pci_core_match_token_uuid, 1586 1587 .bind_iommufd = vfio_iommufd_physical_bind, 1587 1588 .unbind_iommufd = vfio_iommufd_physical_unbind, 1588 1589 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+2 -2
drivers/vfio/pci/mlx5/cmd.c
··· 1523 1523 log_max_msg_size = MLX5_CAP_ADV_VIRTUALIZATION(mdev, pg_track_log_max_msg_size); 1524 1524 max_msg_size = (1ULL << log_max_msg_size); 1525 1525 /* The RQ must hold at least 4 WQEs/messages for successful QP creation */ 1526 - if (rq_size < 4 * max_msg_size) 1527 - rq_size = 4 * max_msg_size; 1526 + if (rq_size < 4ULL * max_msg_size) 1527 + rq_size = 4ULL * max_msg_size; 1528 1528 1529 1529 memset(tracker, 0, sizeof(*tracker)); 1530 1530 tracker->uar = mlx5_get_uars_page(mdev);
+1
drivers/vfio/pci/mlx5/main.c
··· 1372 1372 .mmap = vfio_pci_core_mmap, 1373 1373 .request = vfio_pci_core_request, 1374 1374 .match = vfio_pci_core_match, 1375 + .match_token_uuid = vfio_pci_core_match_token_uuid, 1375 1376 .bind_iommufd = vfio_iommufd_physical_bind, 1376 1377 .unbind_iommufd = vfio_iommufd_physical_unbind, 1377 1378 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+2
drivers/vfio/pci/nvgrace-gpu/main.c
··· 696 696 .mmap = nvgrace_gpu_mmap, 697 697 .request = vfio_pci_core_request, 698 698 .match = vfio_pci_core_match, 699 + .match_token_uuid = vfio_pci_core_match_token_uuid, 699 700 .bind_iommufd = vfio_iommufd_physical_bind, 700 701 .unbind_iommufd = vfio_iommufd_physical_unbind, 701 702 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 716 715 .mmap = vfio_pci_core_mmap, 717 716 .request = vfio_pci_core_request, 718 717 .match = vfio_pci_core_match, 718 + .match_token_uuid = vfio_pci_core_match_token_uuid, 719 719 .bind_iommufd = vfio_iommufd_physical_bind, 720 720 .unbind_iommufd = vfio_iommufd_physical_unbind, 721 721 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+2
drivers/vfio/pci/pds/vfio_dev.c
··· 201 201 .mmap = vfio_pci_core_mmap, 202 202 .request = vfio_pci_core_request, 203 203 .match = vfio_pci_core_match, 204 + .match_token_uuid = vfio_pci_core_match_token_uuid, 204 205 .bind_iommufd = vfio_iommufd_physical_bind, 205 206 .unbind_iommufd = vfio_iommufd_physical_unbind, 206 207 .attach_ioas = vfio_iommufd_physical_attach_ioas, 208 + .detach_ioas = vfio_iommufd_physical_detach_ioas, 207 209 }; 208 210 209 211 const struct vfio_device_ops *pds_vfio_ops_info(void)
+4 -1
drivers/vfio/pci/qat/main.c
··· 614 614 .mmap = vfio_pci_core_mmap, 615 615 .request = vfio_pci_core_request, 616 616 .match = vfio_pci_core_match, 617 + .match_token_uuid = vfio_pci_core_match_token_uuid, 617 618 .bind_iommufd = vfio_iommufd_physical_bind, 618 619 .unbind_iommufd = vfio_iommufd_physical_unbind, 619 620 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 676 675 { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4941) }, 677 676 { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4943) }, 678 677 { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4945) }, 678 + /* Intel QAT GEN6 6xxx VF device */ 679 + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_INTEL, 0x4949) }, 679 680 {} 680 681 }; 681 682 MODULE_DEVICE_TABLE(pci, qat_vf_vfio_pci_table); ··· 699 696 700 697 MODULE_LICENSE("GPL"); 701 698 MODULE_AUTHOR("Xin Zeng <xin.zeng@intel.com>"); 702 - MODULE_DESCRIPTION("QAT VFIO PCI - VFIO PCI driver with live migration support for Intel(R) QAT GEN4 device family"); 699 + MODULE_DESCRIPTION("QAT VFIO PCI - VFIO PCI driver with live migration support for Intel(R) QAT device family"); 703 700 MODULE_IMPORT_NS("CRYPTO_QAT");
+1
drivers/vfio/pci/vfio_pci.c
··· 138 138 .mmap = vfio_pci_core_mmap, 139 139 .request = vfio_pci_core_request, 140 140 .match = vfio_pci_core_match, 141 + .match_token_uuid = vfio_pci_core_match_token_uuid, 141 142 .bind_iommufd = vfio_iommufd_physical_bind, 142 143 .unbind_iommufd = vfio_iommufd_physical_unbind, 143 144 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+15 -9
drivers/vfio/pci/vfio_pci_core.c
··· 1818 1818 } 1819 1819 EXPORT_SYMBOL_GPL(vfio_pci_core_request); 1820 1820 1821 - static int vfio_pci_validate_vf_token(struct vfio_pci_core_device *vdev, 1822 - bool vf_token, uuid_t *uuid) 1821 + int vfio_pci_core_match_token_uuid(struct vfio_device *core_vdev, 1822 + const uuid_t *uuid) 1823 + 1823 1824 { 1825 + struct vfio_pci_core_device *vdev = 1826 + container_of(core_vdev, struct vfio_pci_core_device, vdev); 1827 + 1824 1828 /* 1825 1829 * There's always some degree of trust or collaboration between SR-IOV 1826 1830 * PF and VFs, even if just that the PF hosts the SR-IOV capability and ··· 1855 1851 bool match; 1856 1852 1857 1853 if (!pf_vdev) { 1858 - if (!vf_token) 1854 + if (!uuid) 1859 1855 return 0; /* PF is not vfio-pci, no VF token */ 1860 1856 1861 1857 pci_info_ratelimited(vdev->pdev, ··· 1863 1859 return -EINVAL; 1864 1860 } 1865 1861 1866 - if (!vf_token) { 1862 + if (!uuid) { 1867 1863 pci_info_ratelimited(vdev->pdev, 1868 1864 "VF token required to access device\n"); 1869 1865 return -EACCES; ··· 1881 1877 } else if (vdev->vf_token) { 1882 1878 mutex_lock(&vdev->vf_token->lock); 1883 1879 if (vdev->vf_token->users) { 1884 - if (!vf_token) { 1880 + if (!uuid) { 1885 1881 mutex_unlock(&vdev->vf_token->lock); 1886 1882 pci_info_ratelimited(vdev->pdev, 1887 1883 "VF token required to access device\n"); ··· 1894 1890 "Incorrect VF token provided for device\n"); 1895 1891 return -EACCES; 1896 1892 } 1897 - } else if (vf_token) { 1893 + } else if (uuid) { 1898 1894 uuid_copy(&vdev->vf_token->uuid, uuid); 1899 1895 } 1900 1896 1901 1897 mutex_unlock(&vdev->vf_token->lock); 1902 - } else if (vf_token) { 1898 + } else if (uuid) { 1903 1899 pci_info_ratelimited(vdev->pdev, 1904 1900 "VF token incorrectly provided, not a PF or VF\n"); 1905 1901 return -EINVAL; ··· 1907 1903 1908 1904 return 0; 1909 1905 } 1906 + EXPORT_SYMBOL_GPL(vfio_pci_core_match_token_uuid); 1910 1907 1911 1908 #define VF_TOKEN_ARG "vf_token=" 1912 1909 ··· 1954 1949 } 1955 1950 } 1956 1951 1957 - ret = vfio_pci_validate_vf_token(vdev, vf_token, &uuid); 1952 + ret = core_vdev->ops->match_token_uuid(core_vdev, 1953 + vf_token ? &uuid : NULL); 1958 1954 if (ret) 1959 1955 return ret; 1960 1956 ··· 2152 2146 return -EBUSY; 2153 2147 } 2154 2148 2155 - if (pci_is_root_bus(pdev->bus)) { 2149 + if (pci_is_root_bus(pdev->bus) || pdev->is_virtfn) { 2156 2150 ret = vfio_assign_device_set(&vdev->vdev, vdev); 2157 2151 } else if (!pci_probe_reset_slot(pdev->slot)) { 2158 2152 ret = vfio_assign_device_set(&vdev->vdev, pdev->slot);
+3
drivers/vfio/pci/virtio/main.c
··· 94 94 .mmap = vfio_pci_core_mmap, 95 95 .request = vfio_pci_core_request, 96 96 .match = vfio_pci_core_match, 97 + .match_token_uuid = vfio_pci_core_match_token_uuid, 97 98 .bind_iommufd = vfio_iommufd_physical_bind, 98 99 .unbind_iommufd = vfio_iommufd_physical_unbind, 99 100 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 115 114 .mmap = vfio_pci_core_mmap, 116 115 .request = vfio_pci_core_request, 117 116 .match = vfio_pci_core_match, 117 + .match_token_uuid = vfio_pci_core_match_token_uuid, 118 118 .bind_iommufd = vfio_iommufd_physical_bind, 119 119 .unbind_iommufd = vfio_iommufd_physical_unbind, 120 120 .attach_ioas = vfio_iommufd_physical_attach_ioas, ··· 136 134 .mmap = vfio_pci_core_mmap, 137 135 .request = vfio_pci_core_request, 138 136 .match = vfio_pci_core_match, 137 + .match_token_uuid = vfio_pci_core_match_token_uuid, 139 138 .bind_iommufd = vfio_iommufd_physical_bind, 140 139 .unbind_iommufd = vfio_iommufd_physical_unbind, 141 140 .attach_ioas = vfio_iommufd_physical_attach_ioas,
+7
drivers/vfio/vfio_iommu_type1.c
··· 647 647 648 648 while (npage) { 649 649 if (!batch->size) { 650 + /* 651 + * Large mappings may take a while to repeatedly refill 652 + * the batch, so conditionally relinquish the CPU when 653 + * needed to avoid stalls. 654 + */ 655 + cond_resched(); 656 + 650 657 /* Empty batch, so refill it. */ 651 658 ret = vaddr_get_pfns(mm, vaddr, npage, dma->prot, 652 659 &pfn, batch);
+2 -1
drivers/vfio/vfio_main.c
··· 583 583 584 584 lockdep_assert_held(&device->dev_set->lock); 585 585 586 - vfio_assert_device_open(device); 586 + if (!vfio_assert_device_open(device)) 587 + return; 587 588 if (device->open_count == 1) 588 589 vfio_df_device_last_close(df); 589 590 device->open_count--;
+30 -18
fs/btrfs/tree-log.c
··· 321 321 322 322 /* 323 323 * Ignore any items from the inode currently being processed. Needs 324 - * to be set every time we find a BTRFS_INODE_ITEM_KEY and we are in 325 - * the LOG_WALK_REPLAY_INODES stage. 324 + * to be set every time we find a BTRFS_INODE_ITEM_KEY. 326 325 */ 327 326 bool ignore_cur_inode; 328 327 ··· 2464 2465 2465 2466 nritems = btrfs_header_nritems(eb); 2466 2467 for (i = 0; i < nritems; i++) { 2468 + struct btrfs_inode_item *inode_item; 2469 + 2467 2470 btrfs_item_key_to_cpu(eb, &key, i); 2468 2471 2469 - /* inode keys are done during the first stage */ 2470 - if (key.type == BTRFS_INODE_ITEM_KEY && 2471 - wc->stage == LOG_WALK_REPLAY_INODES) { 2472 - struct btrfs_inode_item *inode_item; 2473 - u32 mode; 2474 - 2475 - inode_item = btrfs_item_ptr(eb, i, 2476 - struct btrfs_inode_item); 2472 + if (key.type == BTRFS_INODE_ITEM_KEY) { 2473 + inode_item = btrfs_item_ptr(eb, i, struct btrfs_inode_item); 2477 2474 /* 2478 - * If we have a tmpfile (O_TMPFILE) that got fsync'ed 2479 - * and never got linked before the fsync, skip it, as 2480 - * replaying it is pointless since it would be deleted 2481 - * later. We skip logging tmpfiles, but it's always 2482 - * possible we are replaying a log created with a kernel 2483 - * that used to log tmpfiles. 2475 + * An inode with no links is either: 2476 + * 2477 + * 1) A tmpfile (O_TMPFILE) that got fsync'ed and never 2478 + * got linked before the fsync, skip it, as replaying 2479 + * it is pointless since it would be deleted later. 2480 + * We skip logging tmpfiles, but it's always possible 2481 + * we are replaying a log created with a kernel that 2482 + * used to log tmpfiles; 2483 + * 2484 + * 2) A non-tmpfile which got its last link deleted 2485 + * while holding an open fd on it and later got 2486 + * fsynced through that fd. We always log the 2487 + * parent inodes when inode->last_unlink_trans is 2488 + * set to the current transaction, so ignore all the 2489 + * inode items for this inode. We will delete the 2490 + * inode when processing the parent directory with 2491 + * replay_dir_deletes(). 2484 2492 */ 2485 2493 if (btrfs_inode_nlink(eb, inode_item) == 0) { 2486 2494 wc->ignore_cur_inode = true; ··· 2495 2489 } else { 2496 2490 wc->ignore_cur_inode = false; 2497 2491 } 2498 - ret = replay_xattr_deletes(wc->trans, root, log, 2499 - path, key.objectid); 2492 + } 2493 + 2494 + /* Inode keys are done during the first stage. */ 2495 + if (key.type == BTRFS_INODE_ITEM_KEY && 2496 + wc->stage == LOG_WALK_REPLAY_INODES) { 2497 + u32 mode; 2498 + 2499 + ret = replay_xattr_deletes(wc->trans, root, log, path, key.objectid); 2500 2500 if (ret) 2501 2501 break; 2502 2502 mode = btrfs_inode_mode(eb, inode_item);
+12
fs/exfat/dir.c
··· 996 996 struct exfat_hint_femp candi_empty; 997 997 struct exfat_sb_info *sbi = EXFAT_SB(sb); 998 998 int num_entries = exfat_calc_num_entries(p_uniname); 999 + unsigned int clu_count = 0; 999 1000 1000 1001 if (num_entries < 0) 1001 1002 return num_entries; ··· 1134 1133 } else { 1135 1134 if (exfat_get_next_cluster(sb, &clu.dir)) 1136 1135 return -EIO; 1136 + 1137 + /* break if the cluster chain includes a loop */ 1138 + if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi))) 1139 + goto not_found; 1137 1140 } 1138 1141 } 1139 1142 ··· 1200 1195 int i, count = 0; 1201 1196 int dentries_per_clu; 1202 1197 unsigned int entry_type; 1198 + unsigned int clu_count = 0; 1203 1199 struct exfat_chain clu; 1204 1200 struct exfat_dentry *ep; 1205 1201 struct exfat_sb_info *sbi = EXFAT_SB(sb); ··· 1233 1227 } else { 1234 1228 if (exfat_get_next_cluster(sb, &(clu.dir))) 1235 1229 return -EIO; 1230 + 1231 + if (unlikely(++clu_count > sbi->used_clusters)) { 1232 + exfat_fs_error(sb, "FAT or bitmap is corrupted"); 1233 + return -EIO; 1234 + } 1235 + 1236 1236 } 1237 1237 } 1238 1238
+10
fs/exfat/fatent.c
··· 490 490 } 491 491 492 492 *ret_count = count; 493 + 494 + /* 495 + * since exfat_count_used_clusters() is not called, sbi->used_clusters 496 + * cannot be used here. 497 + */ 498 + if (unlikely(i == sbi->num_clusters && clu != EXFAT_EOF_CLUSTER)) { 499 + exfat_fs_error(sb, "The cluster chain has a loop"); 500 + return -EIO; 501 + } 502 + 493 503 return 0; 494 504 }
+2 -3
fs/exfat/file.c
··· 622 622 if (pos > valid_size) 623 623 pos = valid_size; 624 624 625 - if (iocb_is_dsync(iocb) && iocb->ki_pos > pos) { 626 - ssize_t err = vfs_fsync_range(file, pos, iocb->ki_pos - 1, 627 - iocb->ki_flags & IOCB_SYNC); 625 + if (iocb->ki_pos > pos) { 626 + ssize_t err = generic_write_sync(iocb, iocb->ki_pos - pos); 628 627 if (err < 0) 629 628 return err; 630 629 }
+5
fs/exfat/namei.c
··· 890 890 { 891 891 int i, dentries_per_clu; 892 892 unsigned int type; 893 + unsigned int clu_count = 0; 893 894 struct exfat_chain clu; 894 895 struct exfat_dentry *ep; 895 896 struct exfat_sb_info *sbi = EXFAT_SB(sb); ··· 927 926 } else { 928 927 if (exfat_get_next_cluster(sb, &(clu.dir))) 929 928 return -EIO; 929 + 930 + /* break if the cluster chain includes a loop */ 931 + if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi))) 932 + break; 930 933 } 931 934 } 932 935
+21 -11
fs/exfat/super.c
··· 341 341 INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); 342 342 } 343 343 344 - static int exfat_read_root(struct inode *inode) 344 + static int exfat_read_root(struct inode *inode, struct exfat_chain *root_clu) 345 345 { 346 346 struct super_block *sb = inode->i_sb; 347 347 struct exfat_sb_info *sbi = EXFAT_SB(sb); 348 348 struct exfat_inode_info *ei = EXFAT_I(inode); 349 - struct exfat_chain cdir; 350 - int num_subdirs, num_clu = 0; 349 + int num_subdirs; 351 350 352 351 exfat_chain_set(&ei->dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); 353 352 ei->entry = -1; ··· 359 360 ei->hint_stat.clu = sbi->root_dir; 360 361 ei->hint_femp.eidx = EXFAT_HINT_NONE; 361 362 362 - exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); 363 - if (exfat_count_num_clusters(sb, &cdir, &num_clu)) 364 - return -EIO; 365 - i_size_write(inode, num_clu << sbi->cluster_size_bits); 363 + i_size_write(inode, EXFAT_CLU_TO_B(root_clu->size, sbi)); 366 364 367 - num_subdirs = exfat_count_dir_entries(sb, &cdir); 365 + num_subdirs = exfat_count_dir_entries(sb, root_clu); 368 366 if (num_subdirs < 0) 369 367 return -EIO; 370 368 set_nlink(inode, num_subdirs + EXFAT_MIN_SUBDIR); ··· 574 578 } 575 579 576 580 /* mount the file system volume */ 577 - static int __exfat_fill_super(struct super_block *sb) 581 + static int __exfat_fill_super(struct super_block *sb, 582 + struct exfat_chain *root_clu) 578 583 { 579 584 int ret; 580 585 struct exfat_sb_info *sbi = EXFAT_SB(sb); ··· 589 592 ret = exfat_verify_boot_region(sb); 590 593 if (ret) { 591 594 exfat_err(sb, "invalid boot region"); 595 + goto free_bh; 596 + } 597 + 598 + /* 599 + * Call exfat_count_num_cluster() before searching for up-case and 600 + * bitmap directory entries to avoid infinite loop if they are missing 601 + * and the cluster chain includes a loop. 602 + */ 603 + exfat_chain_set(root_clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN); 604 + ret = exfat_count_num_clusters(sb, root_clu, &root_clu->size); 605 + if (ret) { 606 + exfat_err(sb, "failed to count the number of clusters in root"); 592 607 goto free_bh; 593 608 } 594 609 ··· 636 627 struct exfat_sb_info *sbi = sb->s_fs_info; 637 628 struct exfat_mount_options *opts = &sbi->options; 638 629 struct inode *root_inode; 630 + struct exfat_chain root_clu; 639 631 int err; 640 632 641 633 if (opts->allow_utime == (unsigned short)-1) ··· 655 645 sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS; 656 646 sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS; 657 647 658 - err = __exfat_fill_super(sb); 648 + err = __exfat_fill_super(sb, &root_clu); 659 649 if (err) { 660 650 exfat_err(sb, "failed to recognize exfat type"); 661 651 goto check_nls_io; ··· 690 680 691 681 root_inode->i_ino = EXFAT_ROOT_INO; 692 682 inode_set_iversion(root_inode, 1); 693 - err = exfat_read_root(root_inode); 683 + err = exfat_read_root(root_inode, &root_clu); 694 684 if (err) { 695 685 exfat_err(sb, "failed to initialize root inode"); 696 686 goto put_inode;
+4 -4
fs/f2fs/checkpoint.c
··· 82 82 if (folio_test_uptodate(folio)) 83 83 goto out; 84 84 85 - fio.page = &folio->page; 85 + fio.folio = folio; 86 86 87 87 err = f2fs_submit_page_bio(&fio); 88 88 if (err) { ··· 309 309 continue; 310 310 } 311 311 312 - fio.page = &folio->page; 312 + fio.folio = folio; 313 313 err = f2fs_submit_page_bio(&fio); 314 314 f2fs_folio_put(folio, err ? true : false); 315 315 ··· 485 485 folio_mark_uptodate(folio); 486 486 if (filemap_dirty_folio(mapping, folio)) { 487 487 inc_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_META); 488 - set_page_private_reference(&folio->page); 488 + folio_set_f2fs_reference(folio); 489 489 return true; 490 490 } 491 491 return false; ··· 1045 1045 inode_inc_dirty_pages(inode); 1046 1046 spin_unlock(&sbi->inode_lock[type]); 1047 1047 1048 - set_page_private_reference(&folio->page); 1048 + folio_set_f2fs_reference(folio); 1049 1049 } 1050 1050 1051 1051 void f2fs_remove_dirty_inode(struct inode *inode)
+60 -60
fs/f2fs/compress.c
··· 23 23 static struct kmem_cache *cic_entry_slab; 24 24 static struct kmem_cache *dic_entry_slab; 25 25 26 - static void *page_array_alloc(struct inode *inode, int nr) 26 + static void *page_array_alloc(struct f2fs_sb_info *sbi, int nr) 27 27 { 28 - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 29 28 unsigned int size = sizeof(struct page *) * nr; 30 29 31 30 if (likely(size <= sbi->page_array_slab_size)) 32 31 return f2fs_kmem_cache_alloc(sbi->page_array_slab, 33 - GFP_F2FS_ZERO, false, F2FS_I_SB(inode)); 32 + GFP_F2FS_ZERO, false, sbi); 34 33 return f2fs_kzalloc(sbi, size, GFP_NOFS); 35 34 } 36 35 37 - static void page_array_free(struct inode *inode, void *pages, int nr) 36 + static void page_array_free(struct f2fs_sb_info *sbi, void *pages, int nr) 38 37 { 39 - struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 40 38 unsigned int size = sizeof(struct page *) * nr; 41 39 42 40 if (!pages) ··· 71 73 return cc->cluster_idx << cc->log_cluster_size; 72 74 } 73 75 74 - bool f2fs_is_compressed_page(struct page *page) 76 + bool f2fs_is_compressed_page(struct folio *folio) 75 77 { 76 - if (!PagePrivate(page)) 78 + if (!folio->private) 77 79 return false; 78 - if (!page_private(page)) 79 - return false; 80 - if (page_private_nonpointer(page)) 80 + if (folio_test_f2fs_nonpointer(folio)) 81 81 return false; 82 82 83 - f2fs_bug_on(F2FS_P_SB(page), 84 - *((u32 *)page_private(page)) != F2FS_COMPRESSED_PAGE_MAGIC); 83 + f2fs_bug_on(F2FS_F_SB(folio), 84 + *((u32 *)folio->private) != F2FS_COMPRESSED_PAGE_MAGIC); 85 85 return true; 86 86 } 87 87 ··· 145 149 if (cc->rpages) 146 150 return 0; 147 151 148 - cc->rpages = page_array_alloc(cc->inode, cc->cluster_size); 152 + cc->rpages = page_array_alloc(F2FS_I_SB(cc->inode), cc->cluster_size); 149 153 return cc->rpages ? 0 : -ENOMEM; 150 154 } 151 155 152 156 void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse) 153 157 { 154 - page_array_free(cc->inode, cc->rpages, cc->cluster_size); 158 + page_array_free(F2FS_I_SB(cc->inode), cc->rpages, cc->cluster_size); 155 159 cc->rpages = NULL; 156 160 cc->nr_rpages = 0; 157 161 cc->nr_cpages = 0; ··· 212 216 ret = lzo1x_decompress_safe(dic->cbuf->cdata, dic->clen, 213 217 dic->rbuf, &dic->rlen); 214 218 if (ret != LZO_E_OK) { 215 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 219 + f2fs_err_ratelimited(dic->sbi, 216 220 "lzo decompress failed, ret:%d", ret); 217 221 return -EIO; 218 222 } 219 223 220 224 if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) { 221 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 225 + f2fs_err_ratelimited(dic->sbi, 222 226 "lzo invalid rlen:%zu, expected:%lu", 223 227 dic->rlen, PAGE_SIZE << dic->log_cluster_size); 224 228 return -EIO; ··· 292 296 ret = LZ4_decompress_safe(dic->cbuf->cdata, dic->rbuf, 293 297 dic->clen, dic->rlen); 294 298 if (ret < 0) { 295 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 299 + f2fs_err_ratelimited(dic->sbi, 296 300 "lz4 decompress failed, ret:%d", ret); 297 301 return -EIO; 298 302 } 299 303 300 304 if (ret != PAGE_SIZE << dic->log_cluster_size) { 301 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 305 + f2fs_err_ratelimited(dic->sbi, 302 306 "lz4 invalid ret:%d, expected:%lu", 303 307 ret, PAGE_SIZE << dic->log_cluster_size); 304 308 return -EIO; ··· 420 424 421 425 workspace_size = zstd_dstream_workspace_bound(max_window_size); 422 426 423 - workspace = f2fs_vmalloc(F2FS_I_SB(dic->inode), workspace_size); 427 + workspace = f2fs_vmalloc(dic->sbi, workspace_size); 424 428 if (!workspace) 425 429 return -ENOMEM; 426 430 427 431 stream = zstd_init_dstream(max_window_size, workspace, workspace_size); 428 432 if (!stream) { 429 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 433 + f2fs_err_ratelimited(dic->sbi, 430 434 "%s zstd_init_dstream failed", __func__); 431 435 vfree(workspace); 432 436 return -EIO; ··· 462 466 463 467 ret = zstd_decompress_stream(stream, &outbuf, &inbuf); 464 468 if (zstd_is_error(ret)) { 465 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 469 + f2fs_err_ratelimited(dic->sbi, 466 470 "%s zstd_decompress_stream failed, ret: %d", 467 471 __func__, zstd_get_error_code(ret)); 468 472 return -EIO; 469 473 } 470 474 471 475 if (dic->rlen != outbuf.pos) { 472 - f2fs_err_ratelimited(F2FS_I_SB(dic->inode), 476 + f2fs_err_ratelimited(dic->sbi, 473 477 "%s ZSTD invalid rlen:%zu, expected:%lu", 474 478 __func__, dic->rlen, 475 479 PAGE_SIZE << dic->log_cluster_size); ··· 618 622 619 623 static int f2fs_compress_pages(struct compress_ctx *cc) 620 624 { 625 + struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); 621 626 struct f2fs_inode_info *fi = F2FS_I(cc->inode); 622 627 const struct f2fs_compress_ops *cops = 623 628 f2fs_cops[fi->i_compress_algorithm]; ··· 639 642 cc->nr_cpages = DIV_ROUND_UP(max_len, PAGE_SIZE); 640 643 cc->valid_nr_cpages = cc->nr_cpages; 641 644 642 - cc->cpages = page_array_alloc(cc->inode, cc->nr_cpages); 645 + cc->cpages = page_array_alloc(sbi, cc->nr_cpages); 643 646 if (!cc->cpages) { 644 647 ret = -ENOMEM; 645 648 goto destroy_compress_ctx; ··· 713 716 if (cc->cpages[i]) 714 717 f2fs_compress_free_page(cc->cpages[i]); 715 718 } 716 - page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 719 + page_array_free(sbi, cc->cpages, cc->nr_cpages); 717 720 cc->cpages = NULL; 718 721 destroy_compress_ctx: 719 722 if (cops->destroy_compress_ctx) ··· 731 734 732 735 void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task) 733 736 { 734 - struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); 737 + struct f2fs_sb_info *sbi = dic->sbi; 735 738 struct f2fs_inode_info *fi = F2FS_I(dic->inode); 736 739 const struct f2fs_compress_ops *cops = 737 740 f2fs_cops[fi->i_compress_algorithm]; ··· 793 796 f2fs_decompress_end_io(dic, ret, in_task); 794 797 } 795 798 799 + static void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, 800 + struct folio *folio, nid_t ino, block_t blkaddr); 801 + 796 802 /* 797 803 * This is called when a page of a compressed cluster has been read from disk 798 804 * (or failed to be read from disk). It checks whether this page was the last 799 805 * page being waited on in the cluster, and if so, it decompresses the cluster 800 806 * (or in the case of a failure, cleans up without actually decompressing). 801 807 */ 802 - void f2fs_end_read_compressed_page(struct page *page, bool failed, 808 + void f2fs_end_read_compressed_page(struct folio *folio, bool failed, 803 809 block_t blkaddr, bool in_task) 804 810 { 805 - struct decompress_io_ctx *dic = 806 - (struct decompress_io_ctx *)page_private(page); 807 - struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); 811 + struct decompress_io_ctx *dic = folio->private; 812 + struct f2fs_sb_info *sbi = dic->sbi; 808 813 809 814 dec_page_count(sbi, F2FS_RD_DATA); 810 815 811 816 if (failed) 812 817 WRITE_ONCE(dic->failed, true); 813 818 else if (blkaddr && in_task) 814 - f2fs_cache_compressed_page(sbi, page, 819 + f2fs_cache_compressed_page(sbi, folio, 815 820 dic->inode->i_ino, blkaddr); 816 821 817 822 if (atomic_dec_and_test(&dic->remaining_pages)) ··· 1339 1340 cic->magic = F2FS_COMPRESSED_PAGE_MAGIC; 1340 1341 cic->inode = inode; 1341 1342 atomic_set(&cic->pending_pages, cc->valid_nr_cpages); 1342 - cic->rpages = page_array_alloc(cc->inode, cc->cluster_size); 1343 + cic->rpages = page_array_alloc(sbi, cc->cluster_size); 1343 1344 if (!cic->rpages) 1344 1345 goto out_put_cic; 1345 1346 ··· 1419 1420 (*submitted)++; 1420 1421 unlock_continue: 1421 1422 inode_dec_dirty_pages(cc->inode); 1422 - unlock_page(fio.page); 1423 + folio_unlock(fio.folio); 1423 1424 } 1424 1425 1425 1426 if (fio.compr_blocks) ··· 1441 1442 spin_unlock(&fi->i_size_lock); 1442 1443 1443 1444 f2fs_put_rpages(cc); 1444 - page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 1445 + page_array_free(sbi, cc->cpages, cc->nr_cpages); 1445 1446 cc->cpages = NULL; 1446 1447 f2fs_destroy_compress_ctx(cc, false); 1447 1448 return 0; 1448 1449 1449 1450 out_destroy_crypt: 1450 - page_array_free(cc->inode, cic->rpages, cc->cluster_size); 1451 + page_array_free(sbi, cic->rpages, cc->cluster_size); 1451 1452 1452 1453 for (--i; i >= 0; i--) { 1453 1454 if (!cc->cpages[i]) ··· 1468 1469 f2fs_compress_free_page(cc->cpages[i]); 1469 1470 cc->cpages[i] = NULL; 1470 1471 } 1471 - page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 1472 + page_array_free(sbi, cc->cpages, cc->nr_cpages); 1472 1473 cc->cpages = NULL; 1473 1474 return -EAGAIN; 1474 1475 } 1475 1476 1476 - void f2fs_compress_write_end_io(struct bio *bio, struct page *page) 1477 + void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio) 1477 1478 { 1479 + struct page *page = &folio->page; 1478 1480 struct f2fs_sb_info *sbi = bio->bi_private; 1479 - struct compress_io_ctx *cic = 1480 - (struct compress_io_ctx *)page_private(page); 1481 - enum count_type type = WB_DATA_TYPE(page, 1482 - f2fs_is_compressed_page(page)); 1481 + struct compress_io_ctx *cic = folio->private; 1482 + enum count_type type = WB_DATA_TYPE(folio, 1483 + f2fs_is_compressed_page(folio)); 1483 1484 int i; 1484 1485 1485 1486 if (unlikely(bio->bi_status != BLK_STS_OK)) ··· 1498 1499 end_page_writeback(cic->rpages[i]); 1499 1500 } 1500 1501 1501 - page_array_free(cic->inode, cic->rpages, cic->nr_rpages); 1502 + page_array_free(sbi, cic->rpages, cic->nr_rpages); 1502 1503 kmem_cache_free(cic_entry_slab, cic); 1503 1504 } 1504 1505 ··· 1632 1633 static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, 1633 1634 bool pre_alloc) 1634 1635 { 1635 - const struct f2fs_compress_ops *cops = 1636 - f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm]; 1636 + const struct f2fs_compress_ops *cops = f2fs_cops[dic->compress_algorithm]; 1637 1637 int i; 1638 1638 1639 - if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) 1639 + if (!allow_memalloc_for_decomp(dic->sbi, pre_alloc)) 1640 1640 return 0; 1641 1641 1642 - dic->tpages = page_array_alloc(dic->inode, dic->cluster_size); 1642 + dic->tpages = page_array_alloc(dic->sbi, dic->cluster_size); 1643 1643 if (!dic->tpages) 1644 1644 return -ENOMEM; 1645 1645 ··· 1668 1670 static void f2fs_release_decomp_mem(struct decompress_io_ctx *dic, 1669 1671 bool bypass_destroy_callback, bool pre_alloc) 1670 1672 { 1671 - const struct f2fs_compress_ops *cops = 1672 - f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm]; 1673 + const struct f2fs_compress_ops *cops = f2fs_cops[dic->compress_algorithm]; 1673 1674 1674 - if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) 1675 + if (!allow_memalloc_for_decomp(dic->sbi, pre_alloc)) 1675 1676 return; 1676 1677 1677 1678 if (!bypass_destroy_callback && cops->destroy_decompress_ctx) ··· 1697 1700 if (!dic) 1698 1701 return ERR_PTR(-ENOMEM); 1699 1702 1700 - dic->rpages = page_array_alloc(cc->inode, cc->cluster_size); 1703 + dic->rpages = page_array_alloc(sbi, cc->cluster_size); 1701 1704 if (!dic->rpages) { 1702 1705 kmem_cache_free(dic_entry_slab, dic); 1703 1706 return ERR_PTR(-ENOMEM); ··· 1705 1708 1706 1709 dic->magic = F2FS_COMPRESSED_PAGE_MAGIC; 1707 1710 dic->inode = cc->inode; 1711 + dic->sbi = sbi; 1712 + dic->compress_algorithm = F2FS_I(cc->inode)->i_compress_algorithm; 1708 1713 atomic_set(&dic->remaining_pages, cc->nr_cpages); 1709 1714 dic->cluster_idx = cc->cluster_idx; 1710 1715 dic->cluster_size = cc->cluster_size; ··· 1720 1721 dic->rpages[i] = cc->rpages[i]; 1721 1722 dic->nr_rpages = cc->cluster_size; 1722 1723 1723 - dic->cpages = page_array_alloc(dic->inode, dic->nr_cpages); 1724 + dic->cpages = page_array_alloc(sbi, dic->nr_cpages); 1724 1725 if (!dic->cpages) { 1725 1726 ret = -ENOMEM; 1726 1727 goto out_free; ··· 1750 1751 bool bypass_destroy_callback) 1751 1752 { 1752 1753 int i; 1754 + /* use sbi in dic to avoid UFA of dic->inode*/ 1755 + struct f2fs_sb_info *sbi = dic->sbi; 1753 1756 1754 1757 f2fs_release_decomp_mem(dic, bypass_destroy_callback, true); 1755 1758 ··· 1763 1762 continue; 1764 1763 f2fs_compress_free_page(dic->tpages[i]); 1765 1764 } 1766 - page_array_free(dic->inode, dic->tpages, dic->cluster_size); 1765 + page_array_free(sbi, dic->tpages, dic->cluster_size); 1767 1766 } 1768 1767 1769 1768 if (dic->cpages) { ··· 1772 1771 continue; 1773 1772 f2fs_compress_free_page(dic->cpages[i]); 1774 1773 } 1775 - page_array_free(dic->inode, dic->cpages, dic->nr_cpages); 1774 + page_array_free(sbi, dic->cpages, dic->nr_cpages); 1776 1775 } 1777 1776 1778 - page_array_free(dic->inode, dic->rpages, dic->nr_rpages); 1777 + page_array_free(sbi, dic->rpages, dic->nr_rpages); 1779 1778 kmem_cache_free(dic_entry_slab, dic); 1780 1779 } 1781 1780 ··· 1794 1793 f2fs_free_dic(dic, false); 1795 1794 } else { 1796 1795 INIT_WORK(&dic->free_work, f2fs_late_free_dic); 1797 - queue_work(F2FS_I_SB(dic->inode)->post_read_wq, 1798 - &dic->free_work); 1796 + queue_work(dic->sbi->post_read_wq, &dic->free_work); 1799 1797 } 1800 1798 } 1801 1799 } ··· 1921 1921 invalidate_mapping_pages(COMPRESS_MAPPING(sbi), blkaddr, blkaddr + len - 1); 1922 1922 } 1923 1923 1924 - void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page, 1925 - nid_t ino, block_t blkaddr) 1924 + static void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, 1925 + struct folio *folio, nid_t ino, block_t blkaddr) 1926 1926 { 1927 1927 struct folio *cfolio; 1928 1928 int ret; ··· 1953 1953 return; 1954 1954 } 1955 1955 1956 - set_page_private_data(&cfolio->page, ino); 1956 + folio_set_f2fs_data(cfolio, ino); 1957 1957 1958 - memcpy(folio_address(cfolio), page_address(page), PAGE_SIZE); 1958 + memcpy(folio_address(cfolio), folio_address(folio), PAGE_SIZE); 1959 1959 folio_mark_uptodate(cfolio); 1960 1960 f2fs_folio_put(cfolio, true); 1961 1961 } ··· 2012 2012 continue; 2013 2013 } 2014 2014 2015 - if (ino != get_page_private_data(&folio->page)) { 2015 + if (ino != folio_get_f2fs_data(folio)) { 2016 2016 folio_unlock(folio); 2017 2017 continue; 2018 2018 }
+99 -84
fs/f2fs/data.c
··· 47 47 bioset_exit(&f2fs_bioset); 48 48 } 49 49 50 - bool f2fs_is_cp_guaranteed(struct page *page) 50 + bool f2fs_is_cp_guaranteed(const struct folio *folio) 51 51 { 52 - struct address_space *mapping = page_folio(page)->mapping; 52 + struct address_space *mapping = folio->mapping; 53 53 struct inode *inode; 54 54 struct f2fs_sb_info *sbi; 55 55 56 - if (fscrypt_is_bounce_page(page)) 57 - return page_private_gcing(fscrypt_pagecache_page(page)); 56 + if (fscrypt_is_bounce_folio(folio)) 57 + return folio_test_f2fs_gcing(fscrypt_pagecache_folio(folio)); 58 58 59 59 inode = mapping->host; 60 60 sbi = F2FS_I_SB(inode); ··· 65 65 return true; 66 66 67 67 if ((S_ISREG(inode->i_mode) && IS_NOQUOTA(inode)) || 68 - page_private_gcing(page)) 68 + folio_test_f2fs_gcing(folio)) 69 69 return true; 70 70 return false; 71 71 } ··· 142 142 bio_for_each_folio_all(fi, bio) { 143 143 struct folio *folio = fi.folio; 144 144 145 - if (f2fs_is_compressed_page(&folio->page)) { 145 + if (f2fs_is_compressed_page(folio)) { 146 146 if (ctx && !ctx->decompression_attempted) 147 - f2fs_end_read_compressed_page(&folio->page, true, 0, 147 + f2fs_end_read_compressed_page(folio, true, 0, 148 148 in_task); 149 149 f2fs_put_folio_dic(folio, in_task); 150 150 continue; ··· 181 181 * as those were handled separately by f2fs_end_read_compressed_page(). 182 182 */ 183 183 if (may_have_compressed_pages) { 184 - struct bio_vec *bv; 185 - struct bvec_iter_all iter_all; 184 + struct folio_iter fi; 186 185 187 - bio_for_each_segment_all(bv, bio, iter_all) { 188 - struct page *page = bv->bv_page; 186 + bio_for_each_folio_all(fi, bio) { 187 + struct folio *folio = fi.folio; 189 188 190 - if (!f2fs_is_compressed_page(page) && 191 - !fsverity_verify_page(page)) { 189 + if (!f2fs_is_compressed_page(folio) && 190 + !fsverity_verify_page(&folio->page)) { 192 191 bio->bi_status = BLK_STS_IOERR; 193 192 break; 194 193 } ··· 232 233 static void f2fs_handle_step_decompress(struct bio_post_read_ctx *ctx, 233 234 bool in_task) 234 235 { 235 - struct bio_vec *bv; 236 - struct bvec_iter_all iter_all; 236 + struct folio_iter fi; 237 237 bool all_compressed = true; 238 238 block_t blkaddr = ctx->fs_blkaddr; 239 239 240 - bio_for_each_segment_all(bv, ctx->bio, iter_all) { 241 - struct page *page = bv->bv_page; 240 + bio_for_each_folio_all(fi, ctx->bio) { 241 + struct folio *folio = fi.folio; 242 242 243 - if (f2fs_is_compressed_page(page)) 244 - f2fs_end_read_compressed_page(page, false, blkaddr, 243 + if (f2fs_is_compressed_page(folio)) 244 + f2fs_end_read_compressed_page(folio, false, blkaddr, 245 245 in_task); 246 246 else 247 247 all_compressed = false; ··· 278 280 279 281 static void f2fs_read_end_io(struct bio *bio) 280 282 { 281 - struct f2fs_sb_info *sbi = F2FS_P_SB(bio_first_page_all(bio)); 283 + struct f2fs_sb_info *sbi = F2FS_F_SB(bio_first_folio_all(bio)); 282 284 struct bio_post_read_ctx *ctx; 283 - bool intask = in_task(); 285 + bool intask = in_task() && !irqs_disabled(); 284 286 285 287 iostat_update_and_unbind_ctx(bio); 286 288 ctx = bio->bi_private; ··· 337 339 } 338 340 339 341 #ifdef CONFIG_F2FS_FS_COMPRESSION 340 - if (f2fs_is_compressed_page(&folio->page)) { 341 - f2fs_compress_write_end_io(bio, &folio->page); 342 + if (f2fs_is_compressed_page(folio)) { 343 + f2fs_compress_write_end_io(bio, folio); 342 344 continue; 343 345 } 344 346 #endif 345 347 346 - type = WB_DATA_TYPE(&folio->page, false); 348 + type = WB_DATA_TYPE(folio, false); 347 349 348 350 if (unlikely(bio->bi_status != BLK_STS_OK)) { 349 351 mapping_set_error(folio->mapping, -EIO); ··· 353 355 } 354 356 355 357 f2fs_bug_on(sbi, is_node_folio(folio) && 356 - folio->index != nid_of_node(&folio->page)); 358 + folio->index != nid_of_node(folio)); 357 359 358 360 dec_page_count(sbi, type); 359 361 if (f2fs_in_warm_node_list(sbi, folio)) 360 362 f2fs_del_fsync_node_entry(sbi, folio); 361 - clear_page_private_gcing(&folio->page); 363 + folio_clear_f2fs_gcing(folio); 362 364 folio_end_writeback(folio); 363 365 } 364 366 if (!get_pages(sbi, F2FS_WB_CP_DATA) && ··· 417 419 static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio) 418 420 { 419 421 unsigned int temp_mask = GENMASK(NR_TEMP_TYPE - 1, 0); 420 - struct folio *fio_folio = page_folio(fio->page); 421 422 unsigned int fua_flag, meta_flag, io_flag; 422 423 blk_opf_t op_flags = 0; 423 424 ··· 444 447 op_flags |= REQ_FUA; 445 448 446 449 if (fio->type == DATA && 447 - F2FS_I(fio_folio->mapping->host)->ioprio_hint == F2FS_IOPRIO_WRITE) 450 + F2FS_I(fio->folio->mapping->host)->ioprio_hint == F2FS_IOPRIO_WRITE) 448 451 op_flags |= REQ_PRIO; 449 452 450 453 return op_flags; ··· 543 546 } 544 547 545 548 static bool __has_merged_page(struct bio *bio, struct inode *inode, 546 - struct page *page, nid_t ino) 549 + struct folio *folio, nid_t ino) 547 550 { 548 551 struct folio_iter fi; 549 552 550 553 if (!bio) 551 554 return false; 552 555 553 - if (!inode && !page && !ino) 556 + if (!inode && !folio && !ino) 554 557 return true; 555 558 556 559 bio_for_each_folio_all(fi, bio) { ··· 561 564 if (IS_ERR(target)) 562 565 continue; 563 566 } 564 - if (f2fs_is_compressed_page(&target->page)) { 567 + if (f2fs_is_compressed_page(target)) { 565 568 target = f2fs_compress_control_folio(target); 566 569 if (IS_ERR(target)) 567 570 continue; ··· 569 572 570 573 if (inode && inode == target->mapping->host) 571 574 return true; 572 - if (page && page == &target->page) 575 + if (folio && folio == target) 573 576 return true; 574 - if (ino && ino == ino_of_node(&target->page)) 577 + if (ino && ino == ino_of_node(target)) 575 578 return true; 576 579 } 577 580 ··· 638 641 } 639 642 640 643 static void __submit_merged_write_cond(struct f2fs_sb_info *sbi, 641 - struct inode *inode, struct page *page, 644 + struct inode *inode, struct folio *folio, 642 645 nid_t ino, enum page_type type, bool force) 643 646 { 644 647 enum temp_type temp; ··· 650 653 struct f2fs_bio_info *io = sbi->write_io[btype] + temp; 651 654 652 655 f2fs_down_read(&io->io_rwsem); 653 - ret = __has_merged_page(io->bio, inode, page, ino); 656 + ret = __has_merged_page(io->bio, inode, folio, ino); 654 657 f2fs_up_read(&io->io_rwsem); 655 658 } 656 659 if (ret) ··· 668 671 } 669 672 670 673 void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, 671 - struct inode *inode, struct page *page, 674 + struct inode *inode, struct folio *folio, 672 675 nid_t ino, enum page_type type) 673 676 { 674 - __submit_merged_write_cond(sbi, inode, page, ino, type, false); 677 + __submit_merged_write_cond(sbi, inode, folio, ino, type, false); 675 678 } 676 679 677 680 void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi) ··· 688 691 int f2fs_submit_page_bio(struct f2fs_io_info *fio) 689 692 { 690 693 struct bio *bio; 691 - struct folio *fio_folio = page_folio(fio->page); 694 + struct folio *fio_folio = fio->folio; 692 695 struct folio *data_folio = fio->encrypted_page ? 693 696 page_folio(fio->encrypted_page) : fio_folio; 694 697 ··· 710 713 wbc_account_cgroup_owner(fio->io_wbc, fio_folio, PAGE_SIZE); 711 714 712 715 inc_page_count(fio->sbi, is_read_io(fio->op) ? 713 - __read_io_type(data_folio) : WB_DATA_TYPE(fio->page, false)); 716 + __read_io_type(data_folio) : WB_DATA_TYPE(fio->folio, false)); 714 717 715 718 if (is_read_io(bio_op(bio))) 716 719 f2fs_submit_read_bio(fio->sbi, bio, fio->type); ··· 776 779 static int add_ipu_page(struct f2fs_io_info *fio, struct bio **bio, 777 780 struct page *page) 778 781 { 779 - struct folio *fio_folio = page_folio(fio->page); 782 + struct folio *fio_folio = fio->folio; 780 783 struct f2fs_sb_info *sbi = fio->sbi; 781 784 enum temp_type temp; 782 785 bool found = false; ··· 845 848 found = (target == be->bio); 846 849 else 847 850 found = __has_merged_page(be->bio, NULL, 848 - &folio->page, 0); 851 + folio, 0); 849 852 if (found) 850 853 break; 851 854 } ··· 862 865 found = (target == be->bio); 863 866 else 864 867 found = __has_merged_page(be->bio, NULL, 865 - &folio->page, 0); 868 + folio, 0); 866 869 if (found) { 867 870 target = be->bio; 868 871 del_bio_entry(be); ··· 883 886 int f2fs_merge_page_bio(struct f2fs_io_info *fio) 884 887 { 885 888 struct bio *bio = *fio->bio; 886 - struct page *page = fio->encrypted_page ? 887 - fio->encrypted_page : fio->page; 888 - struct folio *folio = page_folio(fio->page); 889 + struct folio *data_folio = fio->encrypted_page ? 890 + page_folio(fio->encrypted_page) : fio->folio; 891 + struct folio *folio = fio->folio; 889 892 890 893 if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr, 891 894 __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)) 892 895 return -EFSCORRUPTED; 893 896 894 - trace_f2fs_submit_folio_bio(page_folio(page), fio); 897 + trace_f2fs_submit_folio_bio(data_folio, fio); 895 898 896 899 if (bio && !page_is_mergeable(fio->sbi, bio, *fio->last_block, 897 900 fio->new_blkaddr)) ··· 902 905 f2fs_set_bio_crypt_ctx(bio, folio->mapping->host, 903 906 folio->index, fio, GFP_NOIO); 904 907 905 - add_bio_entry(fio->sbi, bio, page, fio->temp); 908 + add_bio_entry(fio->sbi, bio, &data_folio->page, fio->temp); 906 909 } else { 907 - if (add_ipu_page(fio, &bio, page)) 910 + if (add_ipu_page(fio, &bio, &data_folio->page)) 908 911 goto alloc_new; 909 912 } 910 913 911 914 if (fio->io_wbc) 912 915 wbc_account_cgroup_owner(fio->io_wbc, folio, folio_size(folio)); 913 916 914 - inc_page_count(fio->sbi, WB_DATA_TYPE(page, false)); 917 + inc_page_count(fio->sbi, WB_DATA_TYPE(data_folio, false)); 915 918 916 919 *fio->last_block = fio->new_blkaddr; 917 920 *fio->bio = bio; ··· 946 949 struct f2fs_sb_info *sbi = fio->sbi; 947 950 enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); 948 951 struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; 949 - struct page *bio_page; 952 + struct folio *bio_folio; 950 953 enum count_type type; 951 954 952 955 f2fs_bug_on(sbi, is_read_io(fio->op)); ··· 977 980 verify_fio_blkaddr(fio); 978 981 979 982 if (fio->encrypted_page) 980 - bio_page = fio->encrypted_page; 983 + bio_folio = page_folio(fio->encrypted_page); 981 984 else if (fio->compressed_page) 982 - bio_page = fio->compressed_page; 985 + bio_folio = page_folio(fio->compressed_page); 983 986 else 984 - bio_page = fio->page; 987 + bio_folio = fio->folio; 985 988 986 989 /* set submitted = true as a return value */ 987 990 fio->submitted = 1; 988 991 989 - type = WB_DATA_TYPE(bio_page, fio->compressed_page); 992 + type = WB_DATA_TYPE(bio_folio, fio->compressed_page); 990 993 inc_page_count(sbi, type); 991 994 992 995 if (io->bio && 993 996 (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, 994 997 fio->new_blkaddr) || 995 998 !f2fs_crypt_mergeable_bio(io->bio, fio_inode(fio), 996 - page_folio(bio_page)->index, fio))) 999 + bio_folio->index, fio))) 997 1000 __submit_merged_bio(io); 998 1001 alloc_new: 999 1002 if (io->bio == NULL) { 1000 1003 io->bio = __bio_alloc(fio, BIO_MAX_VECS); 1001 1004 f2fs_set_bio_crypt_ctx(io->bio, fio_inode(fio), 1002 - page_folio(bio_page)->index, fio, GFP_NOIO); 1005 + bio_folio->index, fio, GFP_NOIO); 1003 1006 io->fio = *fio; 1004 1007 } 1005 1008 1006 - if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) { 1009 + if (!bio_add_folio(io->bio, bio_folio, folio_size(bio_folio), 0)) { 1007 1010 __submit_merged_bio(io); 1008 1011 goto alloc_new; 1009 1012 } 1010 1013 1011 1014 if (fio->io_wbc) 1012 - wbc_account_cgroup_owner(fio->io_wbc, page_folio(fio->page), 1013 - PAGE_SIZE); 1015 + wbc_account_cgroup_owner(fio->io_wbc, fio->folio, 1016 + folio_size(fio->folio)); 1014 1017 1015 1018 io->last_block_in_bio = fio->new_blkaddr; 1016 1019 1017 - trace_f2fs_submit_folio_write(page_folio(fio->page), fio); 1020 + trace_f2fs_submit_folio_write(fio->folio, fio); 1018 1021 #ifdef CONFIG_BLK_DEV_ZONED 1019 1022 if (f2fs_sb_has_blkzoned(sbi) && btype < META && 1020 1023 is_end_zone_blkaddr(sbi, fio->new_blkaddr)) { ··· 1550 1553 unsigned int start_pgofs; 1551 1554 int bidx = 0; 1552 1555 bool is_hole; 1556 + bool lfs_dio_write; 1553 1557 1554 1558 if (!maxblocks) 1555 1559 return 0; 1560 + 1561 + lfs_dio_write = (flag == F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) && 1562 + map->m_may_create); 1556 1563 1557 1564 if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag)) 1558 1565 goto out; ··· 1573 1572 end = pgofs + maxblocks; 1574 1573 1575 1574 next_dnode: 1576 - if (map->m_may_create) 1575 + if (map->m_may_create) { 1576 + if (f2fs_lfs_mode(sbi)) 1577 + f2fs_balance_fs(sbi, true); 1577 1578 f2fs_map_lock(sbi, flag); 1579 + } 1578 1580 1579 1581 /* When reading holes, we need its node page */ 1580 1582 set_new_dnode(&dn, inode, NULL, NULL, 0); ··· 1593 1589 start_pgofs = pgofs; 1594 1590 prealloc = 0; 1595 1591 last_ofs_in_node = ofs_in_node = dn.ofs_in_node; 1596 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 1592 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 1597 1593 1598 1594 next_block: 1599 1595 blkaddr = f2fs_data_blkaddr(&dn); ··· 1607 1603 /* use out-place-update for direct IO under LFS mode */ 1608 1604 if (map->m_may_create && (is_hole || 1609 1605 (flag == F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) && 1610 - !f2fs_is_pinned_file(inode)))) { 1606 + !f2fs_is_pinned_file(inode) && map->m_last_pblk != blkaddr))) { 1611 1607 if (unlikely(f2fs_cp_error(sbi))) { 1612 1608 err = -EIO; 1613 1609 goto sync_out; ··· 1691 1687 1692 1688 if (map->m_multidev_dio) 1693 1689 map->m_bdev = FDEV(bidx).bdev; 1690 + 1691 + if (lfs_dio_write) 1692 + map->m_last_pblk = NULL_ADDR; 1694 1693 } else if (map_is_mergeable(sbi, map, blkaddr, flag, bidx, ofs)) { 1695 1694 ofs++; 1696 1695 map->m_len++; 1697 1696 } else { 1697 + if (lfs_dio_write && !f2fs_is_pinned_file(inode)) 1698 + map->m_last_pblk = blkaddr; 1698 1699 goto sync_out; 1699 1700 } 1700 1701 ··· 1722 1713 goto sync_out; 1723 1714 } 1724 1715 dn.ofs_in_node = end_offset; 1725 - } 1726 - 1727 - if (flag == F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) && 1728 - map->m_may_create) { 1729 - /* the next block to be allocated may not be contiguous. */ 1730 - if (GET_SEGOFF_FROM_SEG0(sbi, blkaddr) % BLKS_PER_SEC(sbi) == 1731 - CAP_BLKS_PER_SEC(sbi) - 1) 1732 - goto sync_out; 1733 1716 } 1734 1717 1735 1718 if (pgofs >= end) ··· 2304 2303 } 2305 2304 2306 2305 if (!bio) { 2307 - bio = f2fs_grab_read_bio(inode, blkaddr, nr_pages, 2306 + bio = f2fs_grab_read_bio(inode, blkaddr, nr_pages - i, 2308 2307 f2fs_ra_op_flags(rac), 2309 2308 folio->index, for_write); 2310 2309 if (IS_ERR(bio)) { ··· 2376 2375 unsigned nr_pages = rac ? readahead_count(rac) : 1; 2377 2376 unsigned max_nr_pages = nr_pages; 2378 2377 int ret = 0; 2378 + 2379 + #ifdef CONFIG_F2FS_FS_COMPRESSION 2380 + if (f2fs_compressed_file(inode)) { 2381 + index = rac ? readahead_index(rac) : folio->index; 2382 + max_nr_pages = round_up(index + nr_pages, cc.cluster_size) - 2383 + round_down(index, cc.cluster_size); 2384 + } 2385 + #endif 2379 2386 2380 2387 map.m_pblk = 0; 2381 2388 map.m_lblk = 0; ··· 2651 2642 2652 2643 int f2fs_do_write_data_page(struct f2fs_io_info *fio) 2653 2644 { 2654 - struct folio *folio = page_folio(fio->page); 2645 + struct folio *folio = fio->folio; 2655 2646 struct inode *inode = folio->mapping->host; 2656 2647 struct dnode_of_data dn; 2657 2648 struct node_info ni; ··· 2661 2652 2662 2653 /* Use COW inode to make dnode_of_data for atomic write */ 2663 2654 atomic_commit = f2fs_is_atomic_file(inode) && 2664 - page_private_atomic(folio_page(folio, 0)); 2655 + folio_test_f2fs_atomic(folio); 2665 2656 if (atomic_commit) 2666 2657 set_new_dnode(&dn, F2FS_I(inode)->cow_inode, NULL, NULL, 0); 2667 2658 else ··· 2692 2683 /* This page is already truncated */ 2693 2684 if (fio->old_blkaddr == NULL_ADDR) { 2694 2685 folio_clear_uptodate(folio); 2695 - clear_page_private_gcing(folio_page(folio, 0)); 2686 + folio_clear_f2fs_gcing(folio); 2696 2687 goto out_writepage; 2697 2688 } 2698 2689 got_it: ··· 2762 2753 trace_f2fs_do_write_data_page(folio, OPU); 2763 2754 set_inode_flag(inode, FI_APPEND_WRITE); 2764 2755 if (atomic_commit) 2765 - clear_page_private_atomic(folio_page(folio, 0)); 2756 + folio_clear_f2fs_atomic(folio); 2766 2757 out_writepage: 2767 2758 f2fs_put_dnode(&dn); 2768 2759 out: ··· 2780 2771 bool allow_balance) 2781 2772 { 2782 2773 struct inode *inode = folio->mapping->host; 2783 - struct page *page = folio_page(folio, 0); 2784 2774 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 2785 2775 loff_t i_size = i_size_read(inode); 2786 2776 const pgoff_t end_index = ((unsigned long long)i_size) ··· 2796 2788 .op = REQ_OP_WRITE, 2797 2789 .op_flags = wbc_to_write_flags(wbc), 2798 2790 .old_blkaddr = NULL_ADDR, 2799 - .page = page, 2791 + .folio = folio, 2800 2792 .encrypted_page = NULL, 2801 2793 .submitted = 0, 2802 2794 .compr_blocks = compr_blocks, ··· 2898 2890 inode_dec_dirty_pages(inode); 2899 2891 if (err) { 2900 2892 folio_clear_uptodate(folio); 2901 - clear_page_private_gcing(page); 2893 + folio_clear_f2fs_gcing(folio); 2902 2894 } 2903 2895 folio_unlock(folio); 2904 2896 if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode) && ··· 3384 3376 f2fs_do_read_inline_data(folio, ifolio); 3385 3377 set_inode_flag(inode, FI_DATA_EXIST); 3386 3378 if (inode->i_nlink) 3387 - set_page_private_inline(&ifolio->page); 3379 + folio_set_f2fs_inline(ifolio); 3388 3380 goto out; 3389 3381 } 3390 3382 err = f2fs_convert_inline_folio(&dn, folio); ··· 3706 3698 folio_mark_dirty(folio); 3707 3699 3708 3700 if (f2fs_is_atomic_file(inode)) 3709 - set_page_private_atomic(folio_page(folio, 0)); 3701 + folio_set_f2fs_atomic(folio); 3710 3702 3711 3703 if (pos + copied > i_size_read(inode) && 3712 3704 !f2fs_verity_in_progress(inode)) { ··· 3741 3733 f2fs_remove_dirty_inode(inode); 3742 3734 } 3743 3735 } 3744 - clear_page_private_all(&folio->page); 3736 + folio_detach_private(folio); 3745 3737 } 3746 3738 3747 3739 bool f2fs_release_folio(struct folio *folio, gfp_t wait) ··· 3750 3742 if (folio_test_dirty(folio)) 3751 3743 return false; 3752 3744 3753 - clear_page_private_all(&folio->page); 3745 + folio_detach_private(folio); 3754 3746 return true; 3755 3747 } 3756 3748 ··· 4168 4160 unsigned int flags, struct iomap *iomap, 4169 4161 struct iomap *srcmap) 4170 4162 { 4171 - struct f2fs_map_blocks map = {}; 4163 + struct f2fs_map_blocks map = { NULL, }; 4172 4164 pgoff_t next_pgofs = 0; 4173 4165 int err; 4174 4166 ··· 4177 4169 map.m_next_pgofs = &next_pgofs; 4178 4170 map.m_seg_type = f2fs_rw_hint_to_seg_type(F2FS_I_SB(inode), 4179 4171 inode->i_write_hint); 4172 + if (flags & IOMAP_WRITE && iomap->private) { 4173 + map.m_last_pblk = (unsigned long)iomap->private; 4174 + iomap->private = NULL; 4175 + } 4180 4176 4181 4177 /* 4182 4178 * If the blocks being overwritten are already allocated, ··· 4219 4207 iomap->flags |= IOMAP_F_MERGED; 4220 4208 iomap->bdev = map.m_bdev; 4221 4209 iomap->addr = F2FS_BLK_TO_BYTES(map.m_pblk); 4210 + 4211 + if (flags & IOMAP_WRITE && map.m_last_pblk) 4212 + iomap->private = (void *)map.m_last_pblk; 4222 4213 } else { 4223 4214 if (flags & IOMAP_WRITE) 4224 4215 return -ENOTBLK;
+9 -12
fs/f2fs/debug.c
··· 21 21 #include "gc.h" 22 22 23 23 static LIST_HEAD(f2fs_stat_list); 24 - static DEFINE_RAW_SPINLOCK(f2fs_stat_lock); 24 + static DEFINE_SPINLOCK(f2fs_stat_lock); 25 25 #ifdef CONFIG_DEBUG_FS 26 26 static struct dentry *f2fs_debugfs_root; 27 27 #endif ··· 91 91 seg_blks = get_seg_entry(sbi, j)->valid_blocks; 92 92 93 93 /* update segment stats */ 94 - if (IS_CURSEG(sbi, j)) 94 + if (is_curseg(sbi, j)) 95 95 dev_stats[i].devstats[0][DEVSTAT_INUSE]++; 96 96 else if (seg_blks == BLKS_PER_SEG(sbi)) 97 97 dev_stats[i].devstats[0][DEVSTAT_FULL]++; ··· 109 109 sec_blks = get_sec_entry(sbi, j)->valid_blocks; 110 110 111 111 /* update section stats */ 112 - if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, j))) 112 + if (is_cursec(sbi, GET_SEC_FROM_SEG(sbi, j))) 113 113 dev_stats[i].devstats[1][DEVSTAT_INUSE]++; 114 114 else if (sec_blks == BLKS_PER_SEC(sbi)) 115 115 dev_stats[i].devstats[1][DEVSTAT_FULL]++; ··· 439 439 { 440 440 struct f2fs_stat_info *si; 441 441 int i = 0, j = 0; 442 - unsigned long flags; 443 442 444 - raw_spin_lock_irqsave(&f2fs_stat_lock, flags); 443 + spin_lock(&f2fs_stat_lock); 445 444 list_for_each_entry(si, &f2fs_stat_list, stat_list) { 446 445 struct f2fs_sb_info *sbi = si->sbi; 447 446 ··· 752 753 seq_printf(s, " - paged : %llu KB\n", 753 754 si->page_mem >> 10); 754 755 } 755 - raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); 756 + spin_unlock(&f2fs_stat_lock); 756 757 return 0; 757 758 } 758 759 ··· 764 765 struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); 765 766 struct f2fs_stat_info *si; 766 767 struct f2fs_dev_stats *dev_stats; 767 - unsigned long flags; 768 768 int i; 769 769 770 770 si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL); ··· 815 817 816 818 atomic_set(&sbi->max_aw_cnt, 0); 817 819 818 - raw_spin_lock_irqsave(&f2fs_stat_lock, flags); 820 + spin_lock(&f2fs_stat_lock); 819 821 list_add_tail(&si->stat_list, &f2fs_stat_list); 820 - raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); 822 + spin_unlock(&f2fs_stat_lock); 821 823 822 824 return 0; 823 825 } ··· 825 827 void f2fs_destroy_stats(struct f2fs_sb_info *sbi) 826 828 { 827 829 struct f2fs_stat_info *si = F2FS_STAT(sbi); 828 - unsigned long flags; 829 830 830 - raw_spin_lock_irqsave(&f2fs_stat_lock, flags); 831 + spin_lock(&f2fs_stat_lock); 831 832 list_del(&si->stat_list); 832 - raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); 833 + spin_unlock(&f2fs_stat_lock); 833 834 834 835 kfree(si->dev_stats); 835 836 kfree(si);
+2 -2
fs/f2fs/dir.c
··· 454 454 f2fs_folio_wait_writeback(ifolio, NODE, true, true); 455 455 456 456 /* copy name info. to this inode folio */ 457 - ri = F2FS_INODE(&ifolio->page); 457 + ri = F2FS_INODE(ifolio); 458 458 ri->i_namelen = cpu_to_le32(fname->disk_name.len); 459 459 memcpy(ri->i_name, fname->disk_name.name, fname->disk_name.len); 460 460 if (IS_ENCRYPTED(dir)) { ··· 897 897 f2fs_clear_page_cache_dirty_tag(folio); 898 898 folio_clear_dirty_for_io(folio); 899 899 folio_clear_uptodate(folio); 900 - clear_page_private_all(&folio->page); 900 + folio_detach_private(folio); 901 901 902 902 inode_dec_dirty_pages(dir); 903 903 f2fs_remove_dirty_inode(dir);
+5 -5
fs/f2fs/extent_cache.c
··· 19 19 #include "node.h" 20 20 #include <trace/events/f2fs.h> 21 21 22 - bool sanity_check_extent_cache(struct inode *inode, struct page *ipage) 22 + bool sanity_check_extent_cache(struct inode *inode, struct folio *ifolio) 23 23 { 24 24 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 25 - struct f2fs_extent *i_ext = &F2FS_INODE(ipage)->i_ext; 25 + struct f2fs_extent *i_ext = &F2FS_INODE(ifolio)->i_ext; 26 26 struct extent_info ei; 27 27 int devi; 28 28 ··· 411 411 { 412 412 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 413 413 struct extent_tree_info *eti = &sbi->extent_tree[EX_READ]; 414 - struct f2fs_extent *i_ext = &F2FS_INODE(&ifolio->page)->i_ext; 414 + struct f2fs_extent *i_ext = &F2FS_INODE(ifolio)->i_ext; 415 415 struct extent_tree *et; 416 416 struct extent_node *en; 417 - struct extent_info ei; 417 + struct extent_info ei = {0}; 418 418 419 419 if (!__may_extent_tree(inode, EX_READ)) { 420 420 /* drop largest read extent */ ··· 934 934 if (!__may_extent_tree(dn->inode, type)) 935 935 return; 936 936 937 - ei.fofs = f2fs_start_bidx_of_node(ofs_of_node(&dn->node_folio->page), dn->inode) + 937 + ei.fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_folio), dn->inode) + 938 938 dn->ofs_in_node; 939 939 ei.len = 1; 940 940
+83 -68
fs/f2fs/f2fs.h
··· 386 386 struct rb_node rb_node; /* rb node located in rb-tree */ 387 387 struct discard_info di; /* discard info */ 388 388 struct list_head list; /* command list */ 389 - struct completion wait; /* compleation */ 389 + struct completion wait; /* completion */ 390 390 struct block_device *bdev; /* bdev */ 391 391 unsigned short ref; /* reference count */ 392 392 unsigned char state; /* state */ ··· 732 732 block_t m_lblk; 733 733 unsigned int m_len; 734 734 unsigned int m_flags; 735 + unsigned long m_last_pblk; /* last allocated block, only used for DIO in LFS mode */ 735 736 pgoff_t *m_next_pgofs; /* point next possible non-hole pgofs */ 736 737 pgoff_t *m_next_extent; /* point to next possible extent */ 737 738 int m_seg_type; ··· 876 875 /* linked in global inode list for cache donation */ 877 876 struct list_head gdonate_list; 878 877 pgoff_t donate_start, donate_end; /* inclusive */ 878 + atomic_t open_count; /* # of open files */ 879 879 880 880 struct task_struct *atomic_write_task; /* store atomic write task */ 881 881 struct extent_tree *extent_tree[NR_EXTENT_CACHES]; ··· 1125 1123 * f2fs monitors the number of several block types such as on-writeback, 1126 1124 * dirty dentry blocks, dirty node blocks, and dirty meta blocks. 1127 1125 */ 1128 - #define WB_DATA_TYPE(p, f) \ 1129 - (f || f2fs_is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA) 1126 + #define WB_DATA_TYPE(folio, f) \ 1127 + (f || f2fs_is_cp_guaranteed(folio) ? F2FS_WB_CP_DATA : F2FS_WB_DATA) 1130 1128 enum count_type { 1131 1129 F2FS_DIRTY_DENTS, 1132 1130 F2FS_DIRTY_DATA, ··· 1242 1240 blk_opf_t op_flags; /* req_flag_bits */ 1243 1241 block_t new_blkaddr; /* new block address to be written */ 1244 1242 block_t old_blkaddr; /* old block address before Cow */ 1245 - struct page *page; /* page to be written */ 1243 + union { 1244 + struct page *page; /* page to be written */ 1245 + struct folio *folio; 1246 + }; 1246 1247 struct page *encrypted_page; /* encrypted page */ 1247 1248 struct page *compressed_page; /* compressed page */ 1248 1249 struct list_head list; /* serialize IOs */ ··· 1291 1286 struct f2fs_dev_info { 1292 1287 struct file *bdev_file; 1293 1288 struct block_device *bdev; 1294 - char path[MAX_PATH_LEN]; 1289 + char path[MAX_PATH_LEN + 1]; 1295 1290 unsigned int total_segments; 1296 1291 block_t start_blk; 1297 1292 block_t end_blk; ··· 1432 1427 1433 1428 enum { 1434 1429 MEMORY_MODE_NORMAL, /* memory mode for normal devices */ 1435 - MEMORY_MODE_LOW, /* memory mode for low memry devices */ 1430 + MEMORY_MODE_LOW, /* memory mode for low memory devices */ 1436 1431 }; 1437 1432 1438 1433 enum errors_option { ··· 1496 1491 #define COMPRESS_DATA_RESERVED_SIZE 4 1497 1492 struct compress_data { 1498 1493 __le32 clen; /* compressed data size */ 1499 - __le32 chksum; /* compressed data chksum */ 1494 + __le32 chksum; /* compressed data checksum */ 1500 1495 __le32 reserved[COMPRESS_DATA_RESERVED_SIZE]; /* reserved */ 1501 1496 u8 cdata[]; /* compressed data */ 1502 1497 }; ··· 1541 1536 struct decompress_io_ctx { 1542 1537 u32 magic; /* magic number to indicate page is compressed */ 1543 1538 struct inode *inode; /* inode the context belong to */ 1539 + struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */ 1544 1540 pgoff_t cluster_idx; /* cluster index number */ 1545 1541 unsigned int cluster_size; /* page count in cluster */ 1546 1542 unsigned int log_cluster_size; /* log of cluster size */ ··· 1582 1576 1583 1577 bool failed; /* IO error occurred before decompression? */ 1584 1578 bool need_verity; /* need fs-verity verification after decompression? */ 1579 + unsigned char compress_algorithm; /* backup algorithm type */ 1585 1580 void *private; /* payload buffer for specified decompression algorithm */ 1586 1581 void *private2; /* extra payload buffer */ 1587 1582 struct work_struct verity_work; /* work to verify the decompressed pages */ ··· 1730 1723 1731 1724 /* for skip statistic */ 1732 1725 unsigned long long skipped_gc_rwsem; /* FG_GC only */ 1726 + 1727 + /* free sections reserved for pinned file */ 1728 + unsigned int reserved_pin_section; 1733 1729 1734 1730 /* threshold for gc trials on pinned files */ 1735 1731 unsigned short gc_pin_file_threshold; ··· 2023 2013 return F2FS_I_SB(mapping->host); 2024 2014 } 2025 2015 2026 - static inline struct f2fs_sb_info *F2FS_F_SB(struct folio *folio) 2016 + static inline struct f2fs_sb_info *F2FS_F_SB(const struct folio *folio) 2027 2017 { 2028 2018 return F2FS_M_SB(folio->mapping); 2029 - } 2030 - 2031 - static inline struct f2fs_sb_info *F2FS_P_SB(struct page *page) 2032 - { 2033 - return F2FS_F_SB(page_folio(page)); 2034 2019 } 2035 2020 2036 2021 static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) ··· 2048 2043 return (struct f2fs_checkpoint *)(sbi->ckpt); 2049 2044 } 2050 2045 2051 - static inline struct f2fs_node *F2FS_NODE(const struct page *page) 2046 + static inline struct f2fs_node *F2FS_NODE(const struct folio *folio) 2052 2047 { 2053 - return (struct f2fs_node *)page_address(page); 2048 + return (struct f2fs_node *)folio_address(folio); 2054 2049 } 2055 2050 2056 - static inline struct f2fs_inode *F2FS_INODE(struct page *page) 2051 + static inline struct f2fs_inode *F2FS_INODE(const struct folio *folio) 2057 2052 { 2058 - return &((struct f2fs_node *)page_address(page))->i; 2053 + return &((struct f2fs_node *)folio_address(folio))->i; 2059 2054 } 2060 2055 2061 2056 static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) ··· 2458 2453 } 2459 2454 2460 2455 #define PAGE_PRIVATE_GET_FUNC(name, flagname) \ 2456 + static inline bool folio_test_f2fs_##name(const struct folio *folio) \ 2457 + { \ 2458 + unsigned long priv = (unsigned long)folio->private; \ 2459 + unsigned long v = (1UL << PAGE_PRIVATE_NOT_POINTER) | \ 2460 + (1UL << PAGE_PRIVATE_##flagname); \ 2461 + return (priv & v) == v; \ 2462 + } \ 2461 2463 static inline bool page_private_##name(struct page *page) \ 2462 2464 { \ 2463 2465 return PagePrivate(page) && \ ··· 2473 2461 } 2474 2462 2475 2463 #define PAGE_PRIVATE_SET_FUNC(name, flagname) \ 2464 + static inline void folio_set_f2fs_##name(struct folio *folio) \ 2465 + { \ 2466 + unsigned long v = (1UL << PAGE_PRIVATE_NOT_POINTER) | \ 2467 + (1UL << PAGE_PRIVATE_##flagname); \ 2468 + if (!folio->private) \ 2469 + folio_attach_private(folio, (void *)v); \ 2470 + else { \ 2471 + v |= (unsigned long)folio->private; \ 2472 + folio->private = (void *)v; \ 2473 + } \ 2474 + } \ 2476 2475 static inline void set_page_private_##name(struct page *page) \ 2477 2476 { \ 2478 2477 if (!PagePrivate(page)) \ ··· 2493 2470 } 2494 2471 2495 2472 #define PAGE_PRIVATE_CLEAR_FUNC(name, flagname) \ 2473 + static inline void folio_clear_f2fs_##name(struct folio *folio) \ 2474 + { \ 2475 + unsigned long v = (unsigned long)folio->private; \ 2476 + \ 2477 + v &= ~(1UL << PAGE_PRIVATE_##flagname); \ 2478 + if (v == (1UL << PAGE_PRIVATE_NOT_POINTER)) \ 2479 + folio_detach_private(folio); \ 2480 + else \ 2481 + folio->private = (void *)v; \ 2482 + } \ 2496 2483 static inline void clear_page_private_##name(struct page *page) \ 2497 2484 { \ 2498 2485 clear_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \ ··· 2525 2492 PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION); 2526 2493 PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE); 2527 2494 2528 - static inline unsigned long get_page_private_data(struct page *page) 2495 + static inline unsigned long folio_get_f2fs_data(struct folio *folio) 2529 2496 { 2530 - unsigned long data = page_private(page); 2497 + unsigned long data = (unsigned long)folio->private; 2531 2498 2532 2499 if (!test_bit(PAGE_PRIVATE_NOT_POINTER, &data)) 2533 2500 return 0; 2534 2501 return data >> PAGE_PRIVATE_MAX; 2535 2502 } 2536 2503 2537 - static inline void set_page_private_data(struct page *page, unsigned long data) 2504 + static inline void folio_set_f2fs_data(struct folio *folio, unsigned long data) 2538 2505 { 2539 - if (!PagePrivate(page)) 2540 - attach_page_private(page, (void *)0); 2541 - set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); 2542 - page_private(page) |= data << PAGE_PRIVATE_MAX; 2543 - } 2506 + data = (1UL << PAGE_PRIVATE_NOT_POINTER) | (data << PAGE_PRIVATE_MAX); 2544 2507 2545 - static inline void clear_page_private_data(struct page *page) 2546 - { 2547 - page_private(page) &= GENMASK(PAGE_PRIVATE_MAX - 1, 0); 2548 - if (page_private(page) == BIT(PAGE_PRIVATE_NOT_POINTER)) 2549 - detach_page_private(page); 2550 - } 2551 - 2552 - static inline void clear_page_private_all(struct page *page) 2553 - { 2554 - clear_page_private_data(page); 2555 - clear_page_private_reference(page); 2556 - clear_page_private_gcing(page); 2557 - clear_page_private_inline(page); 2558 - clear_page_private_atomic(page); 2559 - 2560 - f2fs_bug_on(F2FS_P_SB(page), page_private(page)); 2508 + if (!folio_test_private(folio)) 2509 + folio_attach_private(folio, (void *)data); 2510 + else 2511 + folio->private = (void *)((unsigned long)folio->private | data); 2561 2512 } 2562 2513 2563 2514 static inline void dec_valid_block_count(struct f2fs_sb_info *sbi, ··· 3028 3011 3029 3012 #define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino) 3030 3013 3031 - static inline bool IS_INODE(struct page *page) 3014 + static inline bool IS_INODE(const struct folio *folio) 3032 3015 { 3033 - struct f2fs_node *p = F2FS_NODE(page); 3016 + struct f2fs_node *p = F2FS_NODE(folio); 3034 3017 3035 3018 return RAW_IS_INODE(p); 3036 3019 } ··· 3048 3031 3049 3032 static inline int f2fs_has_extra_attr(struct inode *inode); 3050 3033 static inline unsigned int get_dnode_base(struct inode *inode, 3051 - struct page *node_page) 3034 + struct folio *node_folio) 3052 3035 { 3053 - if (!IS_INODE(node_page)) 3036 + if (!IS_INODE(node_folio)) 3054 3037 return 0; 3055 3038 3056 3039 return inode ? get_extra_isize(inode) : 3057 - offset_in_addr(&F2FS_NODE(node_page)->i); 3040 + offset_in_addr(&F2FS_NODE(node_folio)->i); 3058 3041 } 3059 3042 3060 3043 static inline __le32 *get_dnode_addr(struct inode *inode, 3061 3044 struct folio *node_folio) 3062 3045 { 3063 - return blkaddr_in_node(F2FS_NODE(&node_folio->page)) + 3064 - get_dnode_base(inode, &node_folio->page); 3046 + return blkaddr_in_node(F2FS_NODE(node_folio)) + 3047 + get_dnode_base(inode, node_folio); 3065 3048 } 3066 3049 3067 3050 static inline block_t data_blkaddr(struct inode *inode, ··· 3383 3366 return addrs; 3384 3367 } 3385 3368 3386 - static inline void *inline_xattr_addr(struct inode *inode, struct folio *folio) 3369 + static inline 3370 + void *inline_xattr_addr(struct inode *inode, const struct folio *folio) 3387 3371 { 3388 - struct f2fs_inode *ri = F2FS_INODE(&folio->page); 3372 + struct f2fs_inode *ri = F2FS_INODE(folio); 3389 3373 3390 3374 return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE - 3391 3375 get_inline_xattr_addrs(inode)]); ··· 3646 3628 */ 3647 3629 void f2fs_set_inode_flags(struct inode *inode); 3648 3630 bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct folio *folio); 3649 - void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page); 3631 + void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct folio *folio); 3650 3632 struct inode *f2fs_iget(struct super_block *sb, unsigned long ino); 3651 3633 struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino); 3652 3634 int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink); 3653 3635 void f2fs_update_inode(struct inode *inode, struct folio *node_folio); 3654 3636 void f2fs_update_inode_page(struct inode *inode); 3655 3637 int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc); 3638 + void f2fs_remove_donate_inode(struct inode *inode); 3656 3639 void f2fs_evict_inode(struct inode *inode); 3657 3640 void f2fs_handle_failed_inode(struct inode *inode); 3658 3641 ··· 3803 3784 void f2fs_alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid); 3804 3785 int f2fs_try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink); 3805 3786 int f2fs_recover_inline_xattr(struct inode *inode, struct folio *folio); 3806 - int f2fs_recover_xattr_data(struct inode *inode, struct page *page); 3807 - int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page); 3787 + int f2fs_recover_xattr_data(struct inode *inode, struct folio *folio); 3788 + int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct folio *folio); 3808 3789 int f2fs_restore_node_summary(struct f2fs_sb_info *sbi, 3809 3790 unsigned int segno, struct f2fs_summary_block *sum); 3810 3791 int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc); ··· 3871 3852 bool recover_newaddr); 3872 3853 enum temp_type f2fs_get_segment_temp(struct f2fs_sb_info *sbi, 3873 3854 enum log_type seg_type); 3874 - int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, 3855 + int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct folio *folio, 3875 3856 block_t old_blkaddr, block_t *new_blkaddr, 3876 3857 struct f2fs_summary *sum, int type, 3877 3858 struct f2fs_io_info *fio); ··· 3905 3886 3906 3887 static inline struct inode *fio_inode(struct f2fs_io_info *fio) 3907 3888 { 3908 - return page_folio(fio->page)->mapping->host; 3889 + return fio->folio->mapping->host; 3909 3890 } 3910 3891 3911 3892 #define DEF_FRAGMENT_SIZE 4 ··· 3972 3953 */ 3973 3954 int __init f2fs_init_bioset(void); 3974 3955 void f2fs_destroy_bioset(void); 3975 - bool f2fs_is_cp_guaranteed(struct page *page); 3956 + bool f2fs_is_cp_guaranteed(const struct folio *folio); 3976 3957 int f2fs_init_bio_entry_cache(void); 3977 3958 void f2fs_destroy_bio_entry_cache(void); 3978 3959 void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, ··· 3980 3961 int f2fs_init_write_merge_io(struct f2fs_sb_info *sbi); 3981 3962 void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type); 3982 3963 void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, 3983 - struct inode *inode, struct page *page, 3964 + struct inode *inode, struct folio *folio, 3984 3965 nid_t ino, enum page_type type); 3985 3966 void f2fs_submit_merged_ipu_write(struct f2fs_sb_info *sbi, 3986 3967 struct bio **bio, struct folio *folio); ··· 4322 4303 * inline.c 4323 4304 */ 4324 4305 bool f2fs_may_inline_data(struct inode *inode); 4325 - bool f2fs_sanity_check_inline_data(struct inode *inode, struct page *ipage); 4306 + bool f2fs_sanity_check_inline_data(struct inode *inode, struct folio *ifolio); 4326 4307 bool f2fs_may_inline_dentry(struct inode *inode); 4327 4308 void f2fs_do_read_inline_data(struct folio *folio, struct folio *ifolio); 4328 4309 void f2fs_truncate_inline_inode(struct inode *inode, struct folio *ifolio, ··· 4364 4345 /* 4365 4346 * extent_cache.c 4366 4347 */ 4367 - bool sanity_check_extent_cache(struct inode *inode, struct page *ipage); 4348 + bool sanity_check_extent_cache(struct inode *inode, struct folio *ifolio); 4368 4349 void f2fs_init_extent_tree(struct inode *inode); 4369 4350 void f2fs_drop_extent_tree(struct inode *inode); 4370 4351 void f2fs_destroy_extent_node(struct inode *inode); ··· 4454 4435 CLUSTER_COMPR_BLKS, /* return # of compressed blocks in a cluster */ 4455 4436 CLUSTER_RAW_BLKS /* return # of raw blocks in a cluster */ 4456 4437 }; 4457 - bool f2fs_is_compressed_page(struct page *page); 4438 + bool f2fs_is_compressed_page(struct folio *folio); 4458 4439 struct folio *f2fs_compress_control_folio(struct folio *folio); 4459 4440 int f2fs_prepare_compress_overwrite(struct inode *inode, 4460 4441 struct page **pagep, pgoff_t index, void **fsdata); 4461 4442 bool f2fs_compress_write_end(struct inode *inode, void *fsdata, 4462 4443 pgoff_t index, unsigned copied); 4463 4444 int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock); 4464 - void f2fs_compress_write_end_io(struct bio *bio, struct page *page); 4445 + void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio); 4465 4446 bool f2fs_is_compress_backend_ready(struct inode *inode); 4466 4447 bool f2fs_is_compress_level_valid(int alg, int lvl); 4467 4448 int __init f2fs_init_compress_mempool(void); 4468 4449 void f2fs_destroy_compress_mempool(void); 4469 4450 void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task); 4470 - void f2fs_end_read_compressed_page(struct page *page, bool failed, 4451 + void f2fs_end_read_compressed_page(struct folio *folio, bool failed, 4471 4452 block_t blkaddr, bool in_task); 4472 4453 bool f2fs_cluster_is_empty(struct compress_ctx *cc); 4473 4454 bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index); ··· 4505 4486 struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi); 4506 4487 void f2fs_invalidate_compress_pages_range(struct f2fs_sb_info *sbi, 4507 4488 block_t blkaddr, unsigned int len); 4508 - void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page, 4509 - nid_t ino, block_t blkaddr); 4510 4489 bool f2fs_load_compressed_folio(struct f2fs_sb_info *sbi, struct folio *folio, 4511 4490 block_t blkaddr); 4512 4491 void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, nid_t ino); ··· 4521 4504 sbi->compr_saved_block += diff; \ 4522 4505 } while (0) 4523 4506 #else 4524 - static inline bool f2fs_is_compressed_page(struct page *page) { return false; } 4507 + static inline bool f2fs_is_compressed_page(struct folio *folio) { return false; } 4525 4508 static inline bool f2fs_is_compress_backend_ready(struct inode *inode) 4526 4509 { 4527 4510 if (!f2fs_compressed_file(inode)) ··· 4539 4522 static inline void f2fs_destroy_compress_mempool(void) { } 4540 4523 static inline void f2fs_decompress_cluster(struct decompress_io_ctx *dic, 4541 4524 bool in_task) { } 4542 - static inline void f2fs_end_read_compressed_page(struct page *page, 4525 + static inline void f2fs_end_read_compressed_page(struct folio *folio, 4543 4526 bool failed, block_t blkaddr, bool in_task) 4544 4527 { 4545 4528 WARN_ON_ONCE(1); ··· 4559 4542 static inline void f2fs_destroy_compress_cache(void) { } 4560 4543 static inline void f2fs_invalidate_compress_pages_range(struct f2fs_sb_info *sbi, 4561 4544 block_t blkaddr, unsigned int len) { } 4562 - static inline void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, 4563 - struct page *page, nid_t ino, block_t blkaddr) { } 4564 4545 static inline bool f2fs_load_compressed_folio(struct f2fs_sb_info *sbi, 4565 4546 struct folio *folio, block_t blkaddr) { return false; } 4566 4547 static inline void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi,
+62 -45
fs/f2fs/file.c
··· 489 489 } 490 490 } 491 491 492 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 492 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 493 493 494 494 /* find data/hole in dnode block */ 495 495 for (; dn.ofs_in_node < end_offset; ··· 629 629 if (err) 630 630 return err; 631 631 632 - return finish_preallocate_blocks(inode); 632 + err = finish_preallocate_blocks(inode); 633 + if (!err) 634 + atomic_inc(&F2FS_I(inode)->open_count); 635 + return err; 633 636 } 634 637 635 638 void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) ··· 711 708 * once we invalidate valid blkaddr in range [ofs, ofs + count], 712 709 * we will invalidate all blkaddr in the whole range. 713 710 */ 714 - fofs = f2fs_start_bidx_of_node(ofs_of_node(&dn->node_folio->page), 711 + fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_folio), 715 712 dn->inode) + ofs; 716 713 f2fs_update_read_extent_cache_range(dn, fofs, 0, len); 717 714 f2fs_update_age_extent_cache_range(dn, fofs, len); ··· 818 815 goto out; 819 816 } 820 817 821 - count = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 818 + count = ADDRS_PER_PAGE(dn.node_folio, inode); 822 819 823 820 count -= dn.ofs_in_node; 824 821 f2fs_bug_on(sbi, count < 0); 825 822 826 - if (dn.ofs_in_node || IS_INODE(&dn.node_folio->page)) { 823 + if (dn.ofs_in_node || IS_INODE(dn.node_folio)) { 827 824 f2fs_truncate_data_blocks_range(&dn, count); 828 825 free_from += count; 829 826 } ··· 1046 1043 { 1047 1044 struct inode *inode = d_inode(dentry); 1048 1045 struct f2fs_inode_info *fi = F2FS_I(inode); 1046 + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 1049 1047 int err; 1050 1048 1051 - if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) 1049 + if (unlikely(f2fs_cp_error(sbi))) 1052 1050 return -EIO; 1051 + 1052 + err = setattr_prepare(idmap, dentry, attr); 1053 + if (err) 1054 + return err; 1055 + 1056 + err = fscrypt_prepare_setattr(dentry, attr); 1057 + if (err) 1058 + return err; 1059 + 1060 + err = fsverity_prepare_setattr(dentry, attr); 1061 + if (err) 1062 + return err; 1053 1063 1054 1064 if (unlikely(IS_IMMUTABLE(inode))) 1055 1065 return -EPERM; ··· 1080 1064 !IS_ALIGNED(attr->ia_size, 1081 1065 F2FS_BLK_TO_BYTES(fi->i_cluster_size))) 1082 1066 return -EINVAL; 1067 + /* 1068 + * To prevent scattered pin block generation, we don't allow 1069 + * smaller/equal size unaligned truncation for pinned file. 1070 + * We only support overwrite IO to pinned file, so don't 1071 + * care about larger size truncation. 1072 + */ 1073 + if (f2fs_is_pinned_file(inode) && 1074 + attr->ia_size <= i_size_read(inode) && 1075 + !IS_ALIGNED(attr->ia_size, 1076 + F2FS_BLK_TO_BYTES(CAP_BLKS_PER_SEC(sbi)))) 1077 + return -EINVAL; 1083 1078 } 1084 - 1085 - err = setattr_prepare(idmap, dentry, attr); 1086 - if (err) 1087 - return err; 1088 - 1089 - err = fscrypt_prepare_setattr(dentry, attr); 1090 - if (err) 1091 - return err; 1092 - 1093 - err = fsverity_prepare_setattr(dentry, attr); 1094 - if (err) 1095 - return err; 1096 1079 1097 1080 if (is_quota_modification(idmap, inode, attr)) { 1098 1081 err = f2fs_dquot_initialize(inode); ··· 1100 1085 } 1101 1086 if (i_uid_needs_update(idmap, attr, inode) || 1102 1087 i_gid_needs_update(idmap, attr, inode)) { 1103 - f2fs_lock_op(F2FS_I_SB(inode)); 1088 + f2fs_lock_op(sbi); 1104 1089 err = dquot_transfer(idmap, inode, attr); 1105 1090 if (err) { 1106 - set_sbi_flag(F2FS_I_SB(inode), 1107 - SBI_QUOTA_NEED_REPAIR); 1108 - f2fs_unlock_op(F2FS_I_SB(inode)); 1091 + set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 1092 + f2fs_unlock_op(sbi); 1109 1093 return err; 1110 1094 } 1111 1095 /* ··· 1114 1100 i_uid_update(idmap, attr, inode); 1115 1101 i_gid_update(idmap, attr, inode); 1116 1102 f2fs_mark_inode_dirty_sync(inode, true); 1117 - f2fs_unlock_op(F2FS_I_SB(inode)); 1103 + f2fs_unlock_op(sbi); 1118 1104 } 1119 1105 1120 1106 if (attr->ia_valid & ATTR_SIZE) { ··· 1177 1163 f2fs_mark_inode_dirty_sync(inode, true); 1178 1164 1179 1165 /* inode change will produce dirty node pages flushed by checkpoint */ 1180 - f2fs_balance_fs(F2FS_I_SB(inode), true); 1166 + f2fs_balance_fs(sbi, true); 1181 1167 1182 1168 return err; 1183 1169 } ··· 1237 1223 return err; 1238 1224 } 1239 1225 1240 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 1226 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 1241 1227 count = min(end_offset - dn.ofs_in_node, pg_end - pg_start); 1242 1228 1243 1229 f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset); ··· 1336 1322 goto next; 1337 1323 } 1338 1324 1339 - done = min((pgoff_t)ADDRS_PER_PAGE(&dn.node_folio->page, inode) - 1325 + done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_folio, inode) - 1340 1326 dn.ofs_in_node, len); 1341 1327 for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) { 1342 1328 *blkaddr = f2fs_data_blkaddr(&dn); ··· 1425 1411 } 1426 1412 1427 1413 ilen = min((pgoff_t) 1428 - ADDRS_PER_PAGE(&dn.node_folio->page, dst_inode) - 1414 + ADDRS_PER_PAGE(dn.node_folio, dst_inode) - 1429 1415 dn.ofs_in_node, len - i); 1430 1416 do { 1431 1417 dn.data_blkaddr = f2fs_data_blkaddr(&dn); ··· 1467 1453 1468 1454 memcpy_folio(fdst, 0, fsrc, 0, PAGE_SIZE); 1469 1455 folio_mark_dirty(fdst); 1470 - set_page_private_gcing(&fdst->page); 1456 + folio_set_f2fs_gcing(fdst); 1471 1457 f2fs_folio_put(fdst, true); 1472 1458 f2fs_folio_put(fsrc, true); 1473 1459 ··· 1721 1707 goto out; 1722 1708 } 1723 1709 1724 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 1710 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 1725 1711 end = min(pg_end, end_offset - dn.ofs_in_node + index); 1726 1712 1727 1713 ret = f2fs_do_zero_range(&dn, index, end); ··· 1902 1888 } 1903 1889 } 1904 1890 1905 - if (has_not_enough_free_secs(sbi, 0, f2fs_sb_has_blkzoned(sbi) ? 1906 - ZONED_PIN_SEC_REQUIRED_COUNT : 1907 - GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) { 1891 + if (has_not_enough_free_secs(sbi, 0, 1892 + sbi->reserved_pin_section)) { 1908 1893 f2fs_down_write(&sbi->gc_lock); 1909 1894 stat_inc_gc_call_count(sbi, FOREGROUND); 1910 1895 err = f2fs_gc(sbi, &gc_control); ··· 2041 2028 2042 2029 static int f2fs_release_file(struct inode *inode, struct file *filp) 2043 2030 { 2031 + if (atomic_dec_and_test(&F2FS_I(inode)->open_count)) 2032 + f2fs_remove_donate_inode(inode); 2033 + 2044 2034 /* 2045 2035 * f2fs_release_file is called at every close calls. So we should 2046 2036 * not drop any inmemory pages by close called by other process. ··· 2994 2978 f2fs_folio_wait_writeback(folio, DATA, true, true); 2995 2979 2996 2980 folio_mark_dirty(folio); 2997 - set_page_private_gcing(&folio->page); 2981 + folio_set_f2fs_gcing(folio); 2998 2982 f2fs_folio_put(folio, true); 2999 2983 3000 2984 idx++; ··· 3892 3876 break; 3893 3877 } 3894 3878 3895 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 3879 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 3896 3880 count = min(end_offset - dn.ofs_in_node, last_idx - page_idx); 3897 3881 count = round_up(count, fi->i_cluster_size); 3898 3882 ··· 4070 4054 break; 4071 4055 } 4072 4056 4073 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 4057 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 4074 4058 count = min(end_offset - dn.ofs_in_node, last_idx - page_idx); 4075 4059 count = round_up(count, fi->i_cluster_size); 4076 4060 ··· 4234 4218 goto out; 4235 4219 } 4236 4220 4237 - end_offset = ADDRS_PER_PAGE(&dn.node_folio->page, inode); 4221 + end_offset = ADDRS_PER_PAGE(dn.node_folio, inode); 4238 4222 count = min(end_offset - dn.ofs_in_node, pg_end - index); 4239 4223 for (i = 0; i < count; i++, index++, dn.ofs_in_node++) { 4240 4224 struct block_device *cur_bdev; ··· 4431 4415 f2fs_folio_wait_writeback(folio, DATA, true, true); 4432 4416 4433 4417 folio_mark_dirty(folio); 4434 - set_page_private_gcing(&folio->page); 4418 + folio_set_f2fs_gcing(folio); 4435 4419 redirty_idx = folio_next_index(folio); 4436 4420 folio_unlock(folio); 4437 4421 folio_put_refs(folio, 2); ··· 4841 4825 struct inode *inode = file_inode(iocb->ki_filp); 4842 4826 const loff_t pos = iocb->ki_pos; 4843 4827 ssize_t ret; 4828 + bool dio; 4844 4829 4845 4830 if (!f2fs_is_compress_backend_ready(inode)) 4846 4831 return -EOPNOTSUPP; ··· 4850 4833 f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos, 4851 4834 iov_iter_count(to), READ); 4852 4835 4836 + dio = f2fs_should_use_dio(inode, iocb, to); 4837 + 4853 4838 /* In LFS mode, if there is inflight dio, wait for its completion */ 4854 4839 if (f2fs_lfs_mode(F2FS_I_SB(inode)) && 4855 - get_pages(F2FS_I_SB(inode), F2FS_DIO_WRITE)) 4840 + get_pages(F2FS_I_SB(inode), F2FS_DIO_WRITE) && 4841 + (!f2fs_is_pinned_file(inode) || !dio)) 4856 4842 inode_dio_wait(inode); 4857 4843 4858 - if (f2fs_should_use_dio(inode, iocb, to)) { 4844 + if (dio) { 4859 4845 ret = f2fs_dio_read_iter(iocb, to); 4860 4846 } else { 4861 4847 ret = filemap_read(iocb, to, 0); ··· 4866 4846 f2fs_update_iostat(F2FS_I_SB(inode), inode, 4867 4847 APP_BUFFERED_READ_IO, ret); 4868 4848 } 4869 - if (trace_f2fs_dataread_end_enabled()) 4870 - trace_f2fs_dataread_end(inode, pos, ret); 4849 + trace_f2fs_dataread_end(inode, pos, ret); 4871 4850 return ret; 4872 4851 } 4873 4852 ··· 4889 4870 f2fs_update_iostat(F2FS_I_SB(inode), inode, 4890 4871 APP_BUFFERED_READ_IO, ret); 4891 4872 4892 - if (trace_f2fs_dataread_end_enabled()) 4893 - trace_f2fs_dataread_end(inode, pos, ret); 4873 + trace_f2fs_dataread_end(inode, pos, ret); 4894 4874 return ret; 4895 4875 } 4896 4876 ··· 5234 5216 f2fs_dio_write_iter(iocb, from, &may_need_sync) : 5235 5217 f2fs_buffered_write_iter(iocb, from); 5236 5218 5237 - if (trace_f2fs_datawrite_end_enabled()) 5238 - trace_f2fs_datawrite_end(inode, orig_pos, ret); 5219 + trace_f2fs_datawrite_end(inode, orig_pos, ret); 5239 5220 } 5240 5221 5241 5222 /* Don't leave any preallocated blocks around past i_size. */
+29 -25
fs/f2fs/gc.c
··· 141 141 FOREGROUND : BACKGROUND); 142 142 143 143 sync_mode = (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC) || 144 - gc_control.one_time; 144 + (gc_control.one_time && gc_th->boost_gc_greedy); 145 145 146 146 /* foreground GC was been triggered via f2fs_balance_fs() */ 147 - if (foreground) 147 + if (foreground && !f2fs_sb_has_blkzoned(sbi)) 148 148 sync_mode = false; 149 149 150 150 gc_control.init_gc_type = sync_mode ? FG_GC : BG_GC; ··· 197 197 198 198 gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME; 199 199 gc_th->valid_thresh_ratio = DEF_GC_THREAD_VALID_THRESH_RATIO; 200 + gc_th->boost_gc_multiple = BOOST_GC_MULTIPLE; 201 + gc_th->boost_gc_greedy = GC_GREEDY; 200 202 201 203 if (f2fs_sb_has_blkzoned(sbi)) { 202 204 gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME_ZONED; ··· 280 278 { 281 279 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 282 280 283 - if (p->alloc_mode == SSR) { 284 - p->gc_mode = GC_GREEDY; 285 - p->dirty_bitmap = dirty_i->dirty_segmap[type]; 286 - p->max_search = dirty_i->nr_dirty[type]; 287 - p->ofs_unit = 1; 288 - } else if (p->alloc_mode == AT_SSR) { 281 + if (p->alloc_mode == SSR || p->alloc_mode == AT_SSR) { 289 282 p->gc_mode = GC_GREEDY; 290 283 p->dirty_bitmap = dirty_i->dirty_segmap[type]; 291 284 p->max_search = dirty_i->nr_dirty[type]; ··· 386 389 } 387 390 388 391 static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi, 389 - unsigned int segno, struct victim_sel_policy *p) 392 + unsigned int segno, struct victim_sel_policy *p, 393 + unsigned int valid_thresh_ratio) 390 394 { 391 395 if (p->alloc_mode == SSR) 392 396 return get_seg_entry(sbi, segno)->ckpt_valid_blocks; 393 397 394 - if (p->one_time_gc && (get_valid_blocks(sbi, segno, true) >= 395 - CAP_BLKS_PER_SEC(sbi) * sbi->gc_thread->valid_thresh_ratio / 396 - 100)) 398 + if (p->one_time_gc && (valid_thresh_ratio < 100) && 399 + (get_valid_blocks(sbi, segno, true) >= 400 + CAP_BLKS_PER_SEC(sbi) * valid_thresh_ratio / 100)) 397 401 return UINT_MAX; 398 402 399 403 /* alloc_mode == LFS */ ··· 775 777 unsigned int secno, last_victim; 776 778 unsigned int last_segment; 777 779 unsigned int nsearched; 780 + unsigned int valid_thresh_ratio = 100; 778 781 bool is_atgc; 779 782 int ret = 0; 780 783 ··· 785 786 p.alloc_mode = alloc_mode; 786 787 p.age = age; 787 788 p.age_threshold = sbi->am.age_threshold; 788 - p.one_time_gc = one_time; 789 + if (one_time) { 790 + p.one_time_gc = one_time; 791 + if (has_enough_free_secs(sbi, 0, NR_PERSISTENT_LOG)) 792 + valid_thresh_ratio = sbi->gc_thread->valid_thresh_ratio; 793 + } 789 794 790 795 retry: 791 796 select_policy(sbi, gc_type, type, &p); ··· 915 912 goto next; 916 913 } 917 914 918 - cost = get_gc_cost(sbi, segno, &p); 915 + cost = get_gc_cost(sbi, segno, &p, valid_thresh_ratio); 919 916 920 917 if (p.min_cost > cost) { 921 918 p.min_segno = segno; ··· 1165 1162 return false; 1166 1163 } 1167 1164 1168 - if (IS_INODE(&node_folio->page)) { 1169 - base = offset_in_addr(F2FS_INODE(&node_folio->page)); 1165 + if (IS_INODE(node_folio)) { 1166 + base = offset_in_addr(F2FS_INODE(node_folio)); 1170 1167 max_addrs = DEF_ADDRS_PER_INODE; 1171 1168 } else { 1172 1169 base = 0; ··· 1180 1177 return false; 1181 1178 } 1182 1179 1183 - *nofs = ofs_of_node(&node_folio->page); 1180 + *nofs = ofs_of_node(node_folio); 1184 1181 source_blkaddr = data_blkaddr(NULL, node_folio, ofs_in_node); 1185 1182 f2fs_folio_put(node_folio, true); 1186 1183 ··· 1252 1249 } 1253 1250 got_it: 1254 1251 /* read folio */ 1255 - fio.page = &folio->page; 1252 + fio.folio = folio; 1256 1253 fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr; 1257 1254 1258 1255 /* ··· 1356 1353 goto put_out; 1357 1354 1358 1355 /* read page */ 1359 - fio.page = &folio->page; 1356 + fio.folio = folio; 1360 1357 fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr; 1361 1358 1362 1359 if (lfs_mode) ··· 1476 1473 goto out; 1477 1474 } 1478 1475 folio_mark_dirty(folio); 1479 - set_page_private_gcing(&folio->page); 1476 + folio_set_f2fs_gcing(folio); 1480 1477 } else { 1481 1478 struct f2fs_io_info fio = { 1482 1479 .sbi = F2FS_I_SB(inode), ··· 1486 1483 .op = REQ_OP_WRITE, 1487 1484 .op_flags = REQ_SYNC, 1488 1485 .old_blkaddr = NULL_ADDR, 1489 - .page = &folio->page, 1486 + .folio = folio, 1490 1487 .encrypted_page = NULL, 1491 1488 .need_lock = LOCK_REQ, 1492 1489 .io_type = FS_GC_DATA_IO, ··· 1502 1499 f2fs_remove_dirty_inode(inode); 1503 1500 } 1504 1501 1505 - set_page_private_gcing(&folio->page); 1502 + folio_set_f2fs_gcing(folio); 1506 1503 1507 1504 err = f2fs_do_write_data_page(&fio); 1508 1505 if (err) { 1509 - clear_page_private_gcing(&folio->page); 1506 + folio_clear_f2fs_gcing(folio); 1510 1507 if (err == -ENOMEM) { 1511 1508 memalloc_retry_wait(GFP_NOFS); 1512 1509 goto retry; ··· 1752 1749 !has_enough_free_blocks(sbi, 1753 1750 sbi->gc_thread->boost_zoned_gc_percent)) 1754 1751 window_granularity *= 1755 - BOOST_GC_MULTIPLE; 1752 + sbi->gc_thread->boost_gc_multiple; 1756 1753 1757 1754 end_segno = start_segno + window_granularity; 1758 1755 } ··· 1894 1891 /* Let's run FG_GC, if we don't have enough space. */ 1895 1892 if (has_not_enough_free_secs(sbi, 0, 0)) { 1896 1893 gc_type = FG_GC; 1894 + gc_control->one_time = false; 1897 1895 1898 1896 /* 1899 1897 * For example, if there are many prefree_segments below given ··· 2068 2064 .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS), 2069 2065 }; 2070 2066 2071 - if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, segno))) 2067 + if (is_cursec(sbi, GET_SEC_FROM_SEG(sbi, segno))) 2072 2068 continue; 2073 2069 2074 2070 do_garbage_collect(sbi, segno, &gc_list, FG_GC, true, false);
+4 -1
fs/f2fs/gc.h
··· 68 68 unsigned int no_zoned_gc_percent; 69 69 unsigned int boost_zoned_gc_percent; 70 70 unsigned int valid_thresh_ratio; 71 + unsigned int boost_gc_multiple; 72 + unsigned int boost_gc_greedy; 71 73 }; 72 74 73 75 struct gc_inode_list { ··· 196 194 static inline bool need_to_boost_gc(struct f2fs_sb_info *sbi) 197 195 { 198 196 if (f2fs_sb_has_blkzoned(sbi)) 199 - return !has_enough_free_blocks(sbi, LIMIT_BOOST_ZONED_GC); 197 + return !has_enough_free_blocks(sbi, 198 + sbi->gc_thread->boost_zoned_gc_percent); 200 199 return has_enough_invalid_blocks(sbi); 201 200 }
+10 -10
fs/f2fs/inline.c
··· 33 33 return !f2fs_post_read_required(inode); 34 34 } 35 35 36 - static bool inode_has_blocks(struct inode *inode, struct page *ipage) 36 + static bool inode_has_blocks(struct inode *inode, struct folio *ifolio) 37 37 { 38 - struct f2fs_inode *ri = F2FS_INODE(ipage); 38 + struct f2fs_inode *ri = F2FS_INODE(ifolio); 39 39 int i; 40 40 41 41 if (F2FS_HAS_BLOCKS(inode)) ··· 48 48 return false; 49 49 } 50 50 51 - bool f2fs_sanity_check_inline_data(struct inode *inode, struct page *ipage) 51 + bool f2fs_sanity_check_inline_data(struct inode *inode, struct folio *ifolio) 52 52 { 53 53 if (!f2fs_has_inline_data(inode)) 54 54 return false; 55 55 56 - if (inode_has_blocks(inode, ipage)) 56 + if (inode_has_blocks(inode, ifolio)) 57 57 return false; 58 58 59 59 if (!support_inline_data(inode)) ··· 150 150 .type = DATA, 151 151 .op = REQ_OP_WRITE, 152 152 .op_flags = REQ_SYNC | REQ_PRIO, 153 - .page = &folio->page, 153 + .folio = folio, 154 154 .encrypted_page = NULL, 155 155 .io_type = FS_DATA_IO, 156 156 }; ··· 206 206 207 207 /* clear inline data and flag after data writeback */ 208 208 f2fs_truncate_inline_inode(dn->inode, dn->inode_folio, 0); 209 - clear_page_private_inline(&dn->inode_folio->page); 209 + folio_clear_f2fs_inline(dn->inode_folio); 210 210 clear_out: 211 211 stat_dec_inline_inode(dn->inode); 212 212 clear_inode_flag(dn->inode, FI_INLINE_DATA); ··· 286 286 set_inode_flag(inode, FI_APPEND_WRITE); 287 287 set_inode_flag(inode, FI_DATA_EXIST); 288 288 289 - clear_page_private_inline(&ifolio->page); 289 + folio_clear_f2fs_inline(ifolio); 290 290 f2fs_folio_put(ifolio, 1); 291 291 return 0; 292 292 } ··· 305 305 * x o -> remove data blocks, and then recover inline_data 306 306 * x x -> recover data blocks 307 307 */ 308 - if (IS_INODE(&nfolio->page)) 309 - ri = F2FS_INODE(&nfolio->page); 308 + if (IS_INODE(nfolio)) 309 + ri = F2FS_INODE(nfolio); 310 310 311 311 if (f2fs_has_inline_data(inode) && 312 312 ri && (ri->i_inline & F2FS_INLINE_DATA)) { ··· 825 825 826 826 byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits; 827 827 byteaddr += (char *)inline_data_addr(inode, ifolio) - 828 - (char *)F2FS_INODE(&ifolio->page); 828 + (char *)F2FS_INODE(ifolio); 829 829 err = fiemap_fill_next_extent(fieinfo, start, byteaddr, ilen, flags); 830 830 trace_f2fs_fiemap(inode, start, byteaddr, ilen, flags, err); 831 831 out:
+51 -33
fs/f2fs/inode.c
··· 108 108 f2fs_folio_wait_writeback(ifolio, NODE, true, true); 109 109 110 110 set_inode_flag(inode, FI_DATA_EXIST); 111 - set_raw_inline(inode, F2FS_INODE(&ifolio->page)); 111 + set_raw_inline(inode, F2FS_INODE(ifolio)); 112 112 folio_mark_dirty(ifolio); 113 113 return; 114 114 } ··· 116 116 return; 117 117 } 118 118 119 - static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page) 119 + static 120 + bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct folio *folio) 120 121 { 121 - struct f2fs_inode *ri = &F2FS_NODE(page)->i; 122 + struct f2fs_inode *ri = &F2FS_NODE(folio)->i; 122 123 123 124 if (!f2fs_sb_has_inode_chksum(sbi)) 124 125 return false; 125 126 126 - if (!IS_INODE(page) || !(ri->i_inline & F2FS_EXTRA_ATTR)) 127 + if (!IS_INODE(folio) || !(ri->i_inline & F2FS_EXTRA_ATTR)) 127 128 return false; 128 129 129 130 if (!F2FS_FITS_IN_INODE(ri, le16_to_cpu(ri->i_extra_isize), ··· 134 133 return true; 135 134 } 136 135 137 - static __u32 f2fs_inode_chksum(struct f2fs_sb_info *sbi, struct page *page) 136 + static __u32 f2fs_inode_chksum(struct f2fs_sb_info *sbi, struct folio *folio) 138 137 { 139 - struct f2fs_node *node = F2FS_NODE(page); 138 + struct f2fs_node *node = F2FS_NODE(folio); 140 139 struct f2fs_inode *ri = &node->i; 141 140 __le32 ino = node->footer.ino; 142 141 __le32 gen = ri->i_generation; ··· 165 164 return true; 166 165 167 166 #ifdef CONFIG_F2FS_CHECK_FS 168 - if (!f2fs_enable_inode_chksum(sbi, &folio->page)) 167 + if (!f2fs_enable_inode_chksum(sbi, folio)) 169 168 #else 170 - if (!f2fs_enable_inode_chksum(sbi, &folio->page) || 169 + if (!f2fs_enable_inode_chksum(sbi, folio) || 171 170 folio_test_dirty(folio) || 172 171 folio_test_writeback(folio)) 173 172 #endif 174 173 return true; 175 174 176 - ri = &F2FS_NODE(&folio->page)->i; 175 + ri = &F2FS_NODE(folio)->i; 177 176 provided = le32_to_cpu(ri->i_inode_checksum); 178 - calculated = f2fs_inode_chksum(sbi, &folio->page); 177 + calculated = f2fs_inode_chksum(sbi, folio); 179 178 180 179 if (provided != calculated) 181 180 f2fs_warn(sbi, "checksum invalid, nid = %lu, ino_of_node = %x, %x vs. %x", 182 - folio->index, ino_of_node(&folio->page), 181 + folio->index, ino_of_node(folio), 183 182 provided, calculated); 184 183 185 184 return provided == calculated; 186 185 } 187 186 188 - void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page) 187 + void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct folio *folio) 189 188 { 190 - struct f2fs_inode *ri = &F2FS_NODE(page)->i; 189 + struct f2fs_inode *ri = &F2FS_NODE(folio)->i; 191 190 192 - if (!f2fs_enable_inode_chksum(sbi, page)) 191 + if (!f2fs_enable_inode_chksum(sbi, folio)) 193 192 return; 194 193 195 - ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page)); 194 + ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, folio)); 196 195 } 197 196 198 197 static bool sanity_check_compress_inode(struct inode *inode, ··· 267 266 return false; 268 267 } 269 268 270 - static bool sanity_check_inode(struct inode *inode, struct page *node_page) 269 + static bool sanity_check_inode(struct inode *inode, struct folio *node_folio) 271 270 { 272 271 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 273 272 struct f2fs_inode_info *fi = F2FS_I(inode); 274 - struct f2fs_inode *ri = F2FS_INODE(node_page); 273 + struct f2fs_inode *ri = F2FS_INODE(node_folio); 275 274 unsigned long long iblocks; 276 275 277 - iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks); 276 + iblocks = le64_to_cpu(F2FS_INODE(node_folio)->i_blocks); 278 277 if (!iblocks) { 279 278 f2fs_warn(sbi, "%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, run fsck to fix.", 280 279 __func__, inode->i_ino, iblocks); 281 280 return false; 282 281 } 283 282 284 - if (ino_of_node(node_page) != nid_of_node(node_page)) { 283 + if (ino_of_node(node_folio) != nid_of_node(node_folio)) { 285 284 f2fs_warn(sbi, "%s: corrupted inode footer i_ino=%lx, ino,nid: [%u, %u] run fsck to fix.", 286 285 __func__, inode->i_ino, 287 - ino_of_node(node_page), nid_of_node(node_page)); 286 + ino_of_node(node_folio), nid_of_node(node_folio)); 288 287 return false; 289 288 } 290 289 291 - if (ino_of_node(node_page) == fi->i_xattr_nid) { 290 + if (ino_of_node(node_folio) == fi->i_xattr_nid) { 292 291 f2fs_warn(sbi, "%s: corrupted inode i_ino=%lx, xnid=%x, run fsck to fix.", 293 292 __func__, inode->i_ino, fi->i_xattr_nid); 294 293 return false; ··· 355 354 } 356 355 } 357 356 358 - if (f2fs_sanity_check_inline_data(inode, node_page)) { 357 + if (f2fs_sanity_check_inline_data(inode, node_folio)) { 359 358 f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix", 360 359 __func__, inode->i_ino, inode->i_mode); 361 360 return false; ··· 420 419 if (IS_ERR(node_folio)) 421 420 return PTR_ERR(node_folio); 422 421 423 - ri = F2FS_INODE(&node_folio->page); 422 + ri = F2FS_INODE(node_folio); 424 423 425 424 inode->i_mode = le16_to_cpu(ri->i_mode); 426 425 i_uid_write(inode, le32_to_cpu(ri->i_uid)); ··· 470 469 fi->i_inline_xattr_size = 0; 471 470 } 472 471 473 - if (!sanity_check_inode(inode, &node_folio->page)) { 472 + if (!sanity_check_inode(inode, node_folio)) { 474 473 f2fs_folio_put(node_folio, true); 475 474 set_sbi_flag(sbi, SBI_NEED_FSCK); 476 475 f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); ··· 482 481 __recover_inline_status(inode, node_folio); 483 482 484 483 /* try to recover cold bit for non-dir inode */ 485 - if (!S_ISDIR(inode->i_mode) && !is_cold_node(&node_folio->page)) { 484 + if (!S_ISDIR(inode->i_mode) && !is_cold_node(node_folio)) { 486 485 f2fs_folio_wait_writeback(node_folio, NODE, true, true); 487 - set_cold_node(&node_folio->page, false); 486 + set_cold_node(node_folio, false); 488 487 folio_mark_dirty(node_folio); 489 488 } 490 489 ··· 532 531 533 532 init_idisk_time(inode); 534 533 535 - if (!sanity_check_extent_cache(inode, &node_folio->page)) { 534 + if (!sanity_check_extent_cache(inode, node_folio)) { 536 535 f2fs_folio_put(node_folio, true); 537 536 f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); 538 537 return -EFSCORRUPTED; ··· 670 669 671 670 f2fs_inode_synced(inode); 672 671 673 - ri = F2FS_INODE(&node_folio->page); 672 + ri = F2FS_INODE(node_folio); 674 673 675 674 ri->i_mode = cpu_to_le16(inode->i_mode); 676 675 ri->i_advise = fi->i_advise; ··· 749 748 750 749 /* deleted inode */ 751 750 if (inode->i_nlink == 0) 752 - clear_page_private_inline(&node_folio->page); 751 + folio_clear_f2fs_inline(node_folio); 753 752 754 753 init_idisk_time(inode); 755 754 #ifdef CONFIG_F2FS_CHECK_FS 756 - f2fs_inode_chksum_set(F2FS_I_SB(inode), &node_folio->page); 755 + f2fs_inode_chksum_set(F2FS_I_SB(inode), node_folio); 757 756 #endif 758 757 } 759 758 ··· 821 820 return 0; 822 821 } 823 822 824 - static void f2fs_remove_donate_inode(struct inode *inode) 823 + void f2fs_remove_donate_inode(struct inode *inode) 825 824 { 826 825 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 827 826 ··· 934 933 f2fs_update_inode_page(inode); 935 934 if (dquot_initialize_needed(inode)) 936 935 set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 936 + 937 + /* 938 + * If both f2fs_truncate() and f2fs_update_inode_page() failed 939 + * due to fuzzed corrupted inode, call f2fs_inode_synced() to 940 + * avoid triggering later f2fs_bug_on(). 941 + */ 942 + if (is_inode_flag_set(inode, FI_DIRTY_INODE)) { 943 + f2fs_warn(sbi, 944 + "f2fs_evict_inode: inode is dirty, ino:%lu", 945 + inode->i_ino); 946 + f2fs_inode_synced(inode); 947 + set_sbi_flag(sbi, SBI_NEED_FSCK); 948 + } 937 949 } 938 950 if (freeze_protected) 939 951 sb_end_intwrite(inode->i_sb); ··· 963 949 if (likely(!f2fs_cp_error(sbi) && 964 950 !is_sbi_flag_set(sbi, SBI_CP_DISABLED))) 965 951 f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE)); 966 - else 967 - f2fs_inode_synced(inode); 952 + 953 + /* 954 + * anyway, it needs to remove the inode from sbi->inode_list[DIRTY_META] 955 + * list to avoid UAF in f2fs_sync_inode_meta() during checkpoint. 956 + */ 957 + f2fs_inode_synced(inode); 968 958 969 959 /* for the case f2fs_new_inode() was failed, .i_ino is zero, skip it */ 970 960 if (inode->i_ino)
+6 -6
fs/f2fs/namei.c
··· 1298 1298 struct inode *inode, 1299 1299 struct delayed_call *done) 1300 1300 { 1301 - struct page *page; 1301 + struct folio *folio; 1302 1302 const char *target; 1303 1303 1304 1304 if (!dentry) 1305 1305 return ERR_PTR(-ECHILD); 1306 1306 1307 - page = read_mapping_page(inode->i_mapping, 0, NULL); 1308 - if (IS_ERR(page)) 1309 - return ERR_CAST(page); 1307 + folio = read_mapping_folio(inode->i_mapping, 0, NULL); 1308 + if (IS_ERR(folio)) 1309 + return ERR_CAST(folio); 1310 1310 1311 - target = fscrypt_get_symlink(inode, page_address(page), 1311 + target = fscrypt_get_symlink(inode, folio_address(folio), 1312 1312 inode->i_sb->s_blocksize, done); 1313 - put_page(page); 1313 + folio_put(folio); 1314 1314 return target; 1315 1315 } 1316 1316
+148 -113
fs/f2fs/node.c
··· 135 135 return f2fs_get_meta_folio_retry(sbi, current_nat_addr(sbi, nid)); 136 136 } 137 137 138 - static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) 138 + static struct folio *get_next_nat_folio(struct f2fs_sb_info *sbi, nid_t nid) 139 139 { 140 140 struct folio *src_folio; 141 141 struct folio *dst_folio; ··· 149 149 /* get current nat block page with lock */ 150 150 src_folio = get_current_nat_folio(sbi, nid); 151 151 if (IS_ERR(src_folio)) 152 - return &src_folio->page; 152 + return src_folio; 153 153 dst_folio = f2fs_grab_meta_folio(sbi, dst_off); 154 154 f2fs_bug_on(sbi, folio_test_dirty(src_folio)); 155 155 ··· 161 161 162 162 set_to_next_nat(nm_i, nid); 163 163 164 - return &dst_folio->page; 164 + return dst_folio; 165 165 } 166 166 167 167 static struct nat_entry *__alloc_nat_entry(struct f2fs_sb_info *sbi, ··· 185 185 186 186 /* must be locked by nat_tree_lock */ 187 187 static struct nat_entry *__init_nat_entry(struct f2fs_nm_info *nm_i, 188 - struct nat_entry *ne, struct f2fs_nat_entry *raw_ne, bool no_fail) 188 + struct nat_entry *ne, struct f2fs_nat_entry *raw_ne, bool no_fail, bool init_dirty) 189 189 { 190 190 if (no_fail) 191 191 f2fs_radix_tree_insert(&nm_i->nat_root, nat_get_nid(ne), ne); ··· 194 194 195 195 if (raw_ne) 196 196 node_info_from_raw_nat(&ne->ni, raw_ne); 197 + 198 + if (init_dirty) { 199 + INIT_LIST_HEAD(&ne->list); 200 + nm_i->nat_cnt[TOTAL_NAT]++; 201 + return ne; 202 + } 197 203 198 204 spin_lock(&nm_i->nat_list_lock); 199 205 list_add_tail(&ne->list, &nm_i->nat_entries); ··· 210 204 return ne; 211 205 } 212 206 213 - static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n) 207 + static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n, bool for_dirty) 214 208 { 215 209 struct nat_entry *ne; 216 210 217 211 ne = radix_tree_lookup(&nm_i->nat_root, n); 218 212 219 - /* for recent accessed nat entry, move it to tail of lru list */ 220 - if (ne && !get_nat_flag(ne, IS_DIRTY)) { 213 + /* 214 + * for recent accessed nat entry which will not be dirtied soon 215 + * later, move it to tail of lru list. 216 + */ 217 + if (ne && !get_nat_flag(ne, IS_DIRTY) && !for_dirty) { 221 218 spin_lock(&nm_i->nat_list_lock); 222 219 if (!list_empty(&ne->list)) 223 220 list_move_tail(&ne->list, &nm_i->nat_entries); ··· 265 256 } 266 257 267 258 static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, 268 - struct nat_entry *ne) 259 + struct nat_entry *ne, bool init_dirty) 269 260 { 270 261 struct nat_entry_set *head; 271 262 bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR; ··· 288 279 goto refresh_list; 289 280 290 281 nm_i->nat_cnt[DIRTY_NAT]++; 291 - nm_i->nat_cnt[RECLAIMABLE_NAT]--; 282 + if (!init_dirty) 283 + nm_i->nat_cnt[RECLAIMABLE_NAT]--; 292 284 set_nat_flag(ne, IS_DIRTY, true); 293 285 refresh_list: 294 286 spin_lock(&nm_i->nat_list_lock); ··· 322 312 323 313 bool f2fs_in_warm_node_list(struct f2fs_sb_info *sbi, struct folio *folio) 324 314 { 325 - return is_node_folio(folio) && IS_DNODE(&folio->page) && 326 - is_cold_node(&folio->page); 315 + return is_node_folio(folio) && IS_DNODE(folio) && is_cold_node(folio); 327 316 } 328 317 329 318 void f2fs_init_fsync_node_info(struct f2fs_sb_info *sbi) ··· 393 384 bool need = false; 394 385 395 386 f2fs_down_read(&nm_i->nat_tree_lock); 396 - e = __lookup_nat_cache(nm_i, nid); 387 + e = __lookup_nat_cache(nm_i, nid, false); 397 388 if (e) { 398 389 if (!get_nat_flag(e, IS_CHECKPOINTED) && 399 390 !get_nat_flag(e, HAS_FSYNCED_INODE)) ··· 410 401 bool is_cp = true; 411 402 412 403 f2fs_down_read(&nm_i->nat_tree_lock); 413 - e = __lookup_nat_cache(nm_i, nid); 404 + e = __lookup_nat_cache(nm_i, nid, false); 414 405 if (e && !get_nat_flag(e, IS_CHECKPOINTED)) 415 406 is_cp = false; 416 407 f2fs_up_read(&nm_i->nat_tree_lock); ··· 424 415 bool need_update = true; 425 416 426 417 f2fs_down_read(&nm_i->nat_tree_lock); 427 - e = __lookup_nat_cache(nm_i, ino); 418 + e = __lookup_nat_cache(nm_i, ino, false); 428 419 if (e && get_nat_flag(e, HAS_LAST_FSYNC) && 429 420 (get_nat_flag(e, IS_CHECKPOINTED) || 430 421 get_nat_flag(e, HAS_FSYNCED_INODE))) ··· 449 440 return; 450 441 451 442 f2fs_down_write(&nm_i->nat_tree_lock); 452 - e = __lookup_nat_cache(nm_i, nid); 443 + e = __lookup_nat_cache(nm_i, nid, false); 453 444 if (!e) 454 - e = __init_nat_entry(nm_i, new, ne, false); 445 + e = __init_nat_entry(nm_i, new, ne, false, false); 455 446 else 456 447 f2fs_bug_on(sbi, nat_get_ino(e) != le32_to_cpu(ne->ino) || 457 448 nat_get_blkaddr(e) != ··· 468 459 struct f2fs_nm_info *nm_i = NM_I(sbi); 469 460 struct nat_entry *e; 470 461 struct nat_entry *new = __alloc_nat_entry(sbi, ni->nid, true); 462 + bool init_dirty = false; 471 463 472 464 f2fs_down_write(&nm_i->nat_tree_lock); 473 - e = __lookup_nat_cache(nm_i, ni->nid); 465 + e = __lookup_nat_cache(nm_i, ni->nid, true); 474 466 if (!e) { 475 - e = __init_nat_entry(nm_i, new, NULL, true); 467 + init_dirty = true; 468 + e = __init_nat_entry(nm_i, new, NULL, true, true); 476 469 copy_node_info(&e->ni, ni); 477 470 f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR); 478 471 } else if (new_blkaddr == NEW_ADDR) { ··· 510 499 nat_set_blkaddr(e, new_blkaddr); 511 500 if (!__is_valid_data_blkaddr(new_blkaddr)) 512 501 set_nat_flag(e, IS_CHECKPOINTED, false); 513 - __set_nat_cache_dirty(nm_i, e); 502 + __set_nat_cache_dirty(nm_i, e, init_dirty); 514 503 515 504 /* update fsync_mark if its inode nat entry is still alive */ 516 505 if (ni->nid != ni->ino) 517 - e = __lookup_nat_cache(nm_i, ni->ino); 506 + e = __lookup_nat_cache(nm_i, ni->ino, false); 518 507 if (e) { 519 508 if (fsync_done && ni->nid == ni->ino) 520 509 set_nat_flag(e, HAS_FSYNCED_INODE, true); ··· 566 555 struct f2fs_nat_entry ne; 567 556 struct nat_entry *e; 568 557 pgoff_t index; 569 - block_t blkaddr; 570 558 int i; 559 + bool need_cache = true; 571 560 572 561 ni->flag = 0; 573 562 ni->nid = nid; 574 563 retry: 575 564 /* Check nat cache */ 576 565 f2fs_down_read(&nm_i->nat_tree_lock); 577 - e = __lookup_nat_cache(nm_i, nid); 566 + e = __lookup_nat_cache(nm_i, nid, false); 578 567 if (e) { 579 568 ni->ino = nat_get_ino(e); 580 569 ni->blk_addr = nat_get_blkaddr(e); 581 570 ni->version = nat_get_version(e); 582 571 f2fs_up_read(&nm_i->nat_tree_lock); 572 + if (IS_ENABLED(CONFIG_F2FS_CHECK_FS)) { 573 + need_cache = false; 574 + goto sanity_check; 575 + } 583 576 return 0; 584 577 } 585 578 ··· 609 594 up_read(&curseg->journal_rwsem); 610 595 if (i >= 0) { 611 596 f2fs_up_read(&nm_i->nat_tree_lock); 612 - goto cache; 597 + goto sanity_check; 613 598 } 614 599 615 600 /* Fill node_info from nat page */ ··· 624 609 ne = nat_blk->entries[nid - start_nid]; 625 610 node_info_from_raw_nat(ni, &ne); 626 611 f2fs_folio_put(folio, true); 627 - cache: 628 - blkaddr = le32_to_cpu(ne.block_addr); 629 - if (__is_valid_data_blkaddr(blkaddr) && 630 - !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) 631 - return -EFAULT; 612 + sanity_check: 613 + if (__is_valid_data_blkaddr(ni->blk_addr) && 614 + !f2fs_is_valid_blkaddr(sbi, ni->blk_addr, 615 + DATA_GENERIC_ENHANCE)) { 616 + set_sbi_flag(sbi, SBI_NEED_FSCK); 617 + f2fs_err_ratelimited(sbi, 618 + "f2fs_get_node_info of %pS: inconsistent nat entry, " 619 + "ino:%u, nid:%u, blkaddr:%u, ver:%u, flag:%u", 620 + __builtin_return_address(0), 621 + ni->ino, ni->nid, ni->blk_addr, ni->version, ni->flag); 622 + f2fs_handle_error(sbi, ERROR_INCONSISTENT_NAT); 623 + return -EFSCORRUPTED; 624 + } 632 625 633 626 /* cache nat entry */ 634 - cache_nat_entry(sbi, nid, &ne); 627 + if (need_cache) 628 + cache_nat_entry(sbi, nid, &ne); 635 629 return 0; 636 630 } 637 631 ··· 660 636 end = start + n; 661 637 end = min(end, (int)NIDS_PER_BLOCK); 662 638 for (i = start; i < end; i++) { 663 - nid = get_nid(&parent->page, i, false); 639 + nid = get_nid(parent, i, false); 664 640 f2fs_ra_node_page(sbi, nid); 665 641 } 666 642 ··· 819 795 820 796 parent = nfolio[0]; 821 797 if (level != 0) 822 - nids[1] = get_nid(&parent->page, offset[0], true); 798 + nids[1] = get_nid(parent, offset[0], true); 823 799 dn->inode_folio = nfolio[0]; 824 800 dn->inode_folio_locked = true; 825 801 826 802 /* get indirect or direct nodes */ 827 803 for (i = 1; i <= level; i++) { 828 804 bool done = false; 805 + 806 + if (nids[i] && nids[i] == dn->inode->i_ino) { 807 + err = -EFSCORRUPTED; 808 + f2fs_err_ratelimited(sbi, 809 + "inode mapping table is corrupted, run fsck to fix it, " 810 + "ino:%lu, nid:%u, level:%d, offset:%d", 811 + dn->inode->i_ino, nids[i], level, offset[level]); 812 + set_sbi_flag(sbi, SBI_NEED_FSCK); 813 + goto release_pages; 814 + } 829 815 830 816 if (!nids[i] && mode == ALLOC_NODE) { 831 817 /* alloc new node */ ··· 880 846 } 881 847 if (i < level) { 882 848 parent = nfolio[i]; 883 - nids[i + 1] = get_nid(&parent->page, offset[i], false); 849 + nids[i + 1] = get_nid(parent, offset[i], false); 884 850 } 885 851 } 886 852 dn->nid = nids[level]; ··· 995 961 else if (IS_ERR(folio)) 996 962 return PTR_ERR(folio); 997 963 998 - if (IS_INODE(&folio->page) || ino_of_node(&folio->page) != dn->inode->i_ino) { 964 + if (IS_INODE(folio) || ino_of_node(folio) != dn->inode->i_ino) { 999 965 f2fs_err(sbi, "incorrect node reference, ino: %lu, nid: %u, ino_of_node: %u", 1000 - dn->inode->i_ino, dn->nid, ino_of_node(&folio->page)); 966 + dn->inode->i_ino, dn->nid, ino_of_node(folio)); 1001 967 set_sbi_flag(sbi, SBI_NEED_FSCK); 1002 968 f2fs_handle_error(sbi, ERROR_INVALID_NODE_REFERENCE); 1003 969 f2fs_folio_put(folio, true); ··· 1041 1007 1042 1008 f2fs_ra_node_pages(folio, ofs, NIDS_PER_BLOCK); 1043 1009 1044 - rn = F2FS_NODE(&folio->page); 1010 + rn = F2FS_NODE(folio); 1045 1011 if (depth < 3) { 1046 1012 for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) { 1047 1013 child_nid = le32_to_cpu(rn->in.nid[i]); ··· 1104 1070 int i; 1105 1071 int idx = depth - 2; 1106 1072 1107 - nid[0] = get_nid(&dn->inode_folio->page, offset[0], true); 1073 + nid[0] = get_nid(dn->inode_folio, offset[0], true); 1108 1074 if (!nid[0]) 1109 1075 return 0; 1110 1076 ··· 1117 1083 idx = i - 1; 1118 1084 goto fail; 1119 1085 } 1120 - nid[i + 1] = get_nid(&folios[i]->page, offset[i + 1], false); 1086 + nid[i + 1] = get_nid(folios[i], offset[i + 1], false); 1121 1087 } 1122 1088 1123 1089 f2fs_ra_node_pages(folios[idx], offset[idx + 1], NIDS_PER_BLOCK); 1124 1090 1125 1091 /* free direct nodes linked to a partial indirect node */ 1126 1092 for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) { 1127 - child_nid = get_nid(&folios[idx]->page, i, false); 1093 + child_nid = get_nid(folios[idx], i, false); 1128 1094 if (!child_nid) 1129 1095 continue; 1130 1096 dn->nid = child_nid; ··· 1193 1159 set_new_dnode(&dn, inode, folio, NULL, 0); 1194 1160 folio_unlock(folio); 1195 1161 1196 - ri = F2FS_INODE(&folio->page); 1162 + ri = F2FS_INODE(folio); 1197 1163 switch (level) { 1198 1164 case 0: 1199 1165 case 1: ··· 1222 1188 1223 1189 skip_partial: 1224 1190 while (cont) { 1225 - dn.nid = get_nid(&folio->page, offset[0], true); 1191 + dn.nid = get_nid(folio, offset[0], true); 1226 1192 switch (offset[0]) { 1227 1193 case NODE_DIR1_BLOCK: 1228 1194 case NODE_DIR2_BLOCK: ··· 1254 1220 } 1255 1221 if (err < 0) 1256 1222 goto fail; 1257 - if (offset[1] == 0 && get_nid(&folio->page, offset[0], true)) { 1223 + if (offset[1] == 0 && get_nid(folio, offset[0], true)) { 1258 1224 folio_lock(folio); 1259 1225 BUG_ON(!is_node_folio(folio)); 1260 1226 set_nid(folio, offset[0], 0, true); ··· 1401 1367 set_node_addr(sbi, &new_ni, NEW_ADDR, false); 1402 1368 1403 1369 f2fs_folio_wait_writeback(folio, NODE, true, true); 1404 - fill_node_footer(&folio->page, dn->nid, dn->inode->i_ino, ofs, true); 1405 - set_cold_node(&folio->page, S_ISDIR(dn->inode->i_mode)); 1370 + fill_node_footer(folio, dn->nid, dn->inode->i_ino, ofs, true); 1371 + set_cold_node(folio, S_ISDIR(dn->inode->i_mode)); 1406 1372 if (!folio_test_uptodate(folio)) 1407 1373 folio_mark_uptodate(folio); 1408 1374 if (folio_mark_dirty(folio)) ··· 1434 1400 .type = NODE, 1435 1401 .op = REQ_OP_READ, 1436 1402 .op_flags = op_flags, 1437 - .page = &folio->page, 1403 + .folio = folio, 1438 1404 .encrypted_page = NULL, 1439 1405 }; 1440 1406 int err; ··· 1496 1462 struct folio *folio, pgoff_t nid, 1497 1463 enum node_type ntype) 1498 1464 { 1499 - struct page *page = &folio->page; 1500 - 1501 - if (unlikely(nid != nid_of_node(page) || 1502 - (ntype == NODE_TYPE_INODE && !IS_INODE(page)) || 1465 + if (unlikely(nid != nid_of_node(folio) || 1466 + (ntype == NODE_TYPE_INODE && !IS_INODE(folio)) || 1503 1467 (ntype == NODE_TYPE_XATTR && 1504 - !f2fs_has_xattr_block(ofs_of_node(page))) || 1468 + !f2fs_has_xattr_block(ofs_of_node(folio))) || 1505 1469 time_to_inject(sbi, FAULT_INCONSISTENT_FOOTER))) { 1506 1470 f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, " 1507 1471 "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", 1508 - ntype, nid, nid_of_node(page), ino_of_node(page), 1509 - ofs_of_node(page), cpver_of_node(page), 1472 + ntype, nid, nid_of_node(folio), ino_of_node(folio), 1473 + ofs_of_node(folio), cpver_of_node(folio), 1510 1474 next_blkaddr_of_node(folio)); 1511 1475 set_sbi_flag(sbi, SBI_NEED_FSCK); 1512 1476 f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); ··· 1585 1553 static struct folio *f2fs_get_node_folio_ra(struct folio *parent, int start) 1586 1554 { 1587 1555 struct f2fs_sb_info *sbi = F2FS_F_SB(parent); 1588 - nid_t nid = get_nid(&parent->page, start, false); 1556 + nid_t nid = get_nid(parent, start, false); 1589 1557 1590 1558 return __get_node_folio(sbi, nid, parent, start, NODE_TYPE_REGULAR); 1591 1559 } ··· 1650 1618 return ERR_PTR(-EIO); 1651 1619 } 1652 1620 1653 - if (!IS_DNODE(&folio->page) || !is_cold_node(&folio->page)) 1621 + if (!IS_DNODE(folio) || !is_cold_node(folio)) 1654 1622 continue; 1655 - if (ino_of_node(&folio->page) != ino) 1623 + if (ino_of_node(folio) != ino) 1656 1624 continue; 1657 1625 1658 1626 folio_lock(folio); ··· 1662 1630 folio_unlock(folio); 1663 1631 continue; 1664 1632 } 1665 - if (ino_of_node(&folio->page) != ino) 1633 + if (ino_of_node(folio) != ino) 1666 1634 goto continue_unlock; 1667 1635 1668 1636 if (!folio_test_dirty(folio)) { ··· 1692 1660 struct node_info ni; 1693 1661 struct f2fs_io_info fio = { 1694 1662 .sbi = sbi, 1695 - .ino = ino_of_node(&folio->page), 1663 + .ino = ino_of_node(folio), 1696 1664 .type = NODE, 1697 1665 .op = REQ_OP_WRITE, 1698 1666 .op_flags = wbc_to_write_flags(wbc), 1699 - .page = &folio->page, 1667 + .folio = folio, 1700 1668 .encrypted_page = NULL, 1701 1669 .submitted = 0, 1702 1670 .io_type = io_type, ··· 1721 1689 1722 1690 if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) && 1723 1691 wbc->sync_mode == WB_SYNC_NONE && 1724 - IS_DNODE(&folio->page) && is_cold_node(&folio->page)) 1692 + IS_DNODE(folio) && is_cold_node(folio)) 1725 1693 goto redirty_out; 1726 1694 1727 1695 /* get old block addr of this node page */ 1728 - nid = nid_of_node(&folio->page); 1696 + nid = nid_of_node(folio); 1729 1697 f2fs_bug_on(sbi, folio->index != nid); 1730 1698 1731 1699 if (f2fs_get_node_info(sbi, nid, &ni, !do_balance)) ··· 1763 1731 1764 1732 fio.old_blkaddr = ni.blk_addr; 1765 1733 f2fs_do_write_node_page(nid, &fio); 1766 - set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(&folio->page)); 1734 + set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(folio)); 1767 1735 dec_page_count(sbi, F2FS_DIRTY_NODES); 1768 1736 f2fs_up_read(&sbi->node_write); 1769 1737 ··· 1859 1827 goto out; 1860 1828 } 1861 1829 1862 - if (!IS_DNODE(&folio->page) || !is_cold_node(&folio->page)) 1830 + if (!IS_DNODE(folio) || !is_cold_node(folio)) 1863 1831 continue; 1864 - if (ino_of_node(&folio->page) != ino) 1832 + if (ino_of_node(folio) != ino) 1865 1833 continue; 1866 1834 1867 1835 folio_lock(folio); ··· 1871 1839 folio_unlock(folio); 1872 1840 continue; 1873 1841 } 1874 - if (ino_of_node(&folio->page) != ino) 1842 + if (ino_of_node(folio) != ino) 1875 1843 goto continue_unlock; 1876 1844 1877 1845 if (!folio_test_dirty(folio) && folio != last_folio) { ··· 1881 1849 1882 1850 f2fs_folio_wait_writeback(folio, NODE, true, true); 1883 1851 1884 - set_fsync_mark(&folio->page, 0); 1885 - set_dentry_mark(&folio->page, 0); 1852 + set_fsync_mark(folio, 0); 1853 + set_dentry_mark(folio, 0); 1886 1854 1887 1855 if (!atomic || folio == last_folio) { 1888 - set_fsync_mark(&folio->page, 1); 1856 + set_fsync_mark(folio, 1); 1889 1857 percpu_counter_inc(&sbi->rf_node_block_count); 1890 - if (IS_INODE(&folio->page)) { 1858 + if (IS_INODE(folio)) { 1891 1859 if (is_inode_flag_set(inode, 1892 1860 FI_DIRTY_INODE)) 1893 1861 f2fs_update_inode(inode, folio); 1894 - set_dentry_mark(&folio->page, 1862 + set_dentry_mark(folio, 1895 1863 f2fs_need_dentry_mark(sbi, ino)); 1896 1864 } 1897 1865 /* may be written by other thread */ ··· 1967 1935 { 1968 1936 struct f2fs_sb_info *sbi = F2FS_F_SB(folio); 1969 1937 struct inode *inode; 1970 - nid_t ino = ino_of_node(&folio->page); 1938 + nid_t ino = ino_of_node(folio); 1971 1939 1972 1940 inode = find_inode_nowait(sbi->sb, ino, f2fs_match_ino, NULL); 1973 1941 if (!inode) ··· 1996 1964 for (i = 0; i < nr_folios; i++) { 1997 1965 struct folio *folio = fbatch.folios[i]; 1998 1966 1999 - if (!IS_INODE(&folio->page)) 1967 + if (!IS_INODE(folio)) 2000 1968 continue; 2001 1969 2002 1970 folio_lock(folio); ··· 2007 1975 goto unlock; 2008 1976 2009 1977 /* flush inline_data, if it's async context. */ 2010 - if (page_private_inline(&folio->page)) { 2011 - clear_page_private_inline(&folio->page); 1978 + if (folio_test_f2fs_inline(folio)) { 1979 + folio_clear_f2fs_inline(folio); 2012 1980 folio_unlock(folio); 2013 - flush_inline_data(sbi, ino_of_node(&folio->page)); 1981 + flush_inline_data(sbi, ino_of_node(folio)); 2014 1982 continue; 2015 1983 } 2016 1984 unlock: ··· 2059 2027 * 1. dentry dnodes 2060 2028 * 2. file dnodes 2061 2029 */ 2062 - if (step == 0 && IS_DNODE(&folio->page)) 2030 + if (step == 0 && IS_DNODE(folio)) 2063 2031 continue; 2064 - if (step == 1 && (!IS_DNODE(&folio->page) || 2065 - is_cold_node(&folio->page))) 2032 + if (step == 1 && (!IS_DNODE(folio) || 2033 + is_cold_node(folio))) 2066 2034 continue; 2067 - if (step == 2 && (!IS_DNODE(&folio->page) || 2068 - !is_cold_node(&folio->page))) 2035 + if (step == 2 && (!IS_DNODE(folio) || 2036 + !is_cold_node(folio))) 2069 2037 continue; 2070 2038 lock_node: 2071 2039 if (wbc->sync_mode == WB_SYNC_ALL) ··· 2089 2057 goto write_node; 2090 2058 2091 2059 /* flush inline_data */ 2092 - if (page_private_inline(&folio->page)) { 2093 - clear_page_private_inline(&folio->page); 2060 + if (folio_test_f2fs_inline(folio)) { 2061 + folio_clear_f2fs_inline(folio); 2094 2062 folio_unlock(folio); 2095 - flush_inline_data(sbi, ino_of_node(&folio->page)); 2063 + flush_inline_data(sbi, ino_of_node(folio)); 2096 2064 goto lock_node; 2097 2065 } 2098 2066 2099 2067 /* flush dirty inode */ 2100 - if (IS_INODE(&folio->page) && flush_dirty_inode(folio)) 2068 + if (IS_INODE(folio) && flush_dirty_inode(folio)) 2101 2069 goto lock_node; 2102 2070 write_node: 2103 2071 f2fs_folio_wait_writeback(folio, NODE, true, true); ··· 2105 2073 if (!folio_clear_dirty_for_io(folio)) 2106 2074 goto continue_unlock; 2107 2075 2108 - set_fsync_mark(&folio->page, 0); 2109 - set_dentry_mark(&folio->page, 0); 2076 + set_fsync_mark(folio, 0); 2077 + set_dentry_mark(folio, 0); 2110 2078 2111 2079 if (!__write_node_folio(folio, false, &submitted, 2112 2080 wbc, do_balance, io_type, NULL)) { ··· 2233 2201 if (!folio_test_uptodate(folio)) 2234 2202 folio_mark_uptodate(folio); 2235 2203 #ifdef CONFIG_F2FS_CHECK_FS 2236 - if (IS_INODE(&folio->page)) 2237 - f2fs_inode_chksum_set(F2FS_M_SB(mapping), &folio->page); 2204 + if (IS_INODE(folio)) 2205 + f2fs_inode_chksum_set(F2FS_M_SB(mapping), folio); 2238 2206 #endif 2239 2207 if (filemap_dirty_folio(mapping, folio)) { 2240 2208 inc_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_NODES); 2241 - set_page_private_reference(&folio->page); 2209 + folio_set_f2fs_reference(folio); 2242 2210 return true; 2243 2211 } 2244 2212 return false; ··· 2383 2351 * - __remove_nid_from_list(PREALLOC_NID) 2384 2352 * - __insert_nid_to_list(FREE_NID) 2385 2353 */ 2386 - ne = __lookup_nat_cache(nm_i, nid); 2354 + ne = __lookup_nat_cache(nm_i, nid, false); 2387 2355 if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) || 2388 2356 nat_get_blkaddr(ne) != NULL_ADDR)) 2389 2357 goto err_out; ··· 2746 2714 if (IS_ERR(ifolio)) 2747 2715 return PTR_ERR(ifolio); 2748 2716 2749 - ri = F2FS_INODE(&folio->page); 2717 + ri = F2FS_INODE(folio); 2750 2718 if (ri->i_inline & F2FS_INLINE_XATTR) { 2751 2719 if (!f2fs_has_inline_xattr(inode)) { 2752 2720 set_inode_flag(inode, FI_INLINE_XATTR); ··· 2772 2740 return 0; 2773 2741 } 2774 2742 2775 - int f2fs_recover_xattr_data(struct inode *inode, struct page *page) 2743 + int f2fs_recover_xattr_data(struct inode *inode, struct folio *folio) 2776 2744 { 2777 2745 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 2778 2746 nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid; ··· 2810 2778 f2fs_update_inode_page(inode); 2811 2779 2812 2780 /* 3: update and set xattr node page dirty */ 2813 - if (page) { 2814 - memcpy(F2FS_NODE(&xfolio->page), F2FS_NODE(page), 2781 + if (folio) { 2782 + memcpy(F2FS_NODE(xfolio), F2FS_NODE(folio), 2815 2783 VALID_XATTR_BLOCK_SIZE); 2816 2784 folio_mark_dirty(xfolio); 2817 2785 } ··· 2820 2788 return 0; 2821 2789 } 2822 2790 2823 - int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) 2791 + int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct folio *folio) 2824 2792 { 2825 2793 struct f2fs_inode *src, *dst; 2826 - nid_t ino = ino_of_node(page); 2794 + nid_t ino = ino_of_node(folio); 2827 2795 struct node_info old_ni, new_ni; 2828 2796 struct folio *ifolio; 2829 2797 int err; ··· 2846 2814 2847 2815 if (!folio_test_uptodate(ifolio)) 2848 2816 folio_mark_uptodate(ifolio); 2849 - fill_node_footer(&ifolio->page, ino, ino, 0, true); 2850 - set_cold_node(&ifolio->page, false); 2817 + fill_node_footer(ifolio, ino, ino, 0, true); 2818 + set_cold_node(ifolio, false); 2851 2819 2852 - src = F2FS_INODE(page); 2853 - dst = F2FS_INODE(&ifolio->page); 2820 + src = F2FS_INODE(folio); 2821 + dst = F2FS_INODE(ifolio); 2854 2822 2855 2823 memcpy(dst, src, offsetof(struct f2fs_inode, i_ext)); 2856 2824 dst->i_size = 0; ··· 2916 2884 if (IS_ERR(folio)) 2917 2885 return PTR_ERR(folio); 2918 2886 2919 - rn = F2FS_NODE(&folio->page); 2887 + rn = F2FS_NODE(folio); 2920 2888 sum_entry->nid = rn->footer.nid; 2921 2889 sum_entry->version = 0; 2922 2890 sum_entry->ofs_in_node = 0; ··· 2936 2904 struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); 2937 2905 struct f2fs_journal *journal = curseg->journal; 2938 2906 int i; 2907 + bool init_dirty; 2939 2908 2940 2909 down_write(&curseg->journal_rwsem); 2941 2910 for (i = 0; i < nats_in_cursum(journal); i++) { ··· 2947 2914 if (f2fs_check_nid_range(sbi, nid)) 2948 2915 continue; 2949 2916 2917 + init_dirty = false; 2918 + 2950 2919 raw_ne = nat_in_journal(journal, i); 2951 2920 2952 - ne = __lookup_nat_cache(nm_i, nid); 2921 + ne = __lookup_nat_cache(nm_i, nid, true); 2953 2922 if (!ne) { 2923 + init_dirty = true; 2954 2924 ne = __alloc_nat_entry(sbi, nid, true); 2955 - __init_nat_entry(nm_i, ne, &raw_ne, true); 2925 + __init_nat_entry(nm_i, ne, &raw_ne, true, true); 2956 2926 } 2957 2927 2958 2928 /* ··· 2970 2934 spin_unlock(&nm_i->nid_list_lock); 2971 2935 } 2972 2936 2973 - __set_nat_cache_dirty(nm_i, ne); 2937 + __set_nat_cache_dirty(nm_i, ne, init_dirty); 2974 2938 } 2975 2939 update_nats_in_cursum(journal, -i); 2976 2940 up_write(&curseg->journal_rwsem); ··· 2995 2959 } 2996 2960 2997 2961 static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid, 2998 - struct page *page) 2962 + const struct f2fs_nat_block *nat_blk) 2999 2963 { 3000 2964 struct f2fs_nm_info *nm_i = NM_I(sbi); 3001 2965 unsigned int nat_index = start_nid / NAT_ENTRY_PER_BLOCK; 3002 - struct f2fs_nat_block *nat_blk = page_address(page); 3003 2966 int valid = 0; 3004 2967 int i = 0; 3005 2968 ··· 3035 3000 bool to_journal = true; 3036 3001 struct f2fs_nat_block *nat_blk; 3037 3002 struct nat_entry *ne, *cur; 3038 - struct page *page = NULL; 3003 + struct folio *folio = NULL; 3039 3004 3040 3005 /* 3041 3006 * there are two steps to flush nat entries: ··· 3049 3014 if (to_journal) { 3050 3015 down_write(&curseg->journal_rwsem); 3051 3016 } else { 3052 - page = get_next_nat_page(sbi, start_nid); 3053 - if (IS_ERR(page)) 3054 - return PTR_ERR(page); 3017 + folio = get_next_nat_folio(sbi, start_nid); 3018 + if (IS_ERR(folio)) 3019 + return PTR_ERR(folio); 3055 3020 3056 - nat_blk = page_address(page); 3021 + nat_blk = folio_address(folio); 3057 3022 f2fs_bug_on(sbi, !nat_blk); 3058 3023 } 3059 3024 ··· 3089 3054 if (to_journal) { 3090 3055 up_write(&curseg->journal_rwsem); 3091 3056 } else { 3092 - __update_nat_bits(sbi, start_nid, page); 3093 - f2fs_put_page(page, 1); 3057 + __update_nat_bits(sbi, start_nid, nat_blk); 3058 + f2fs_folio_put(folio, true); 3094 3059 } 3095 3060 3096 3061 /* Allow dirty nats by node block allocation in write_begin */ ··· 3430 3395 } 3431 3396 kvfree(nm_i->free_nid_count); 3432 3397 3433 - kvfree(nm_i->nat_bitmap); 3398 + kfree(nm_i->nat_bitmap); 3434 3399 kvfree(nm_i->nat_bits); 3435 3400 #ifdef CONFIG_F2FS_CHECK_FS 3436 - kvfree(nm_i->nat_bitmap_mir); 3401 + kfree(nm_i->nat_bitmap_mir); 3437 3402 #endif 3438 3403 sbi->nm_info = NULL; 3439 3404 kfree(nm_i);
+39 -38
fs/f2fs/node.h
··· 31 31 /* control total # of nats */ 32 32 #define DEF_NAT_CACHE_THRESHOLD 100000 33 33 34 - /* control total # of node writes used for roll-fowrad recovery */ 34 + /* control total # of node writes used for roll-forward recovery */ 35 35 #define DEF_RF_NODE_BLOCKS 0 36 36 37 37 /* vector size for gang look-up from nat cache that consists of radix tree */ ··· 243 243 #endif 244 244 } 245 245 246 - static inline nid_t ino_of_node(struct page *node_page) 246 + static inline nid_t ino_of_node(const struct folio *node_folio) 247 247 { 248 - struct f2fs_node *rn = F2FS_NODE(node_page); 248 + struct f2fs_node *rn = F2FS_NODE(node_folio); 249 249 return le32_to_cpu(rn->footer.ino); 250 250 } 251 251 252 - static inline nid_t nid_of_node(struct page *node_page) 252 + static inline nid_t nid_of_node(const struct folio *node_folio) 253 253 { 254 - struct f2fs_node *rn = F2FS_NODE(node_page); 254 + struct f2fs_node *rn = F2FS_NODE(node_folio); 255 255 return le32_to_cpu(rn->footer.nid); 256 256 } 257 257 258 - static inline unsigned int ofs_of_node(const struct page *node_page) 258 + static inline unsigned int ofs_of_node(const struct folio *node_folio) 259 259 { 260 - struct f2fs_node *rn = F2FS_NODE(node_page); 260 + struct f2fs_node *rn = F2FS_NODE(node_folio); 261 261 unsigned flag = le32_to_cpu(rn->footer.flag); 262 262 return flag >> OFFSET_BIT_SHIFT; 263 263 } 264 264 265 - static inline __u64 cpver_of_node(struct page *node_page) 265 + static inline __u64 cpver_of_node(const struct folio *node_folio) 266 266 { 267 - struct f2fs_node *rn = F2FS_NODE(node_page); 267 + struct f2fs_node *rn = F2FS_NODE(node_folio); 268 268 return le64_to_cpu(rn->footer.cp_ver); 269 269 } 270 270 271 - static inline block_t next_blkaddr_of_node(struct folio *node_folio) 271 + static inline block_t next_blkaddr_of_node(const struct folio *node_folio) 272 272 { 273 - struct f2fs_node *rn = F2FS_NODE(&node_folio->page); 273 + struct f2fs_node *rn = F2FS_NODE(node_folio); 274 274 return le32_to_cpu(rn->footer.next_blkaddr); 275 275 } 276 276 277 - static inline void fill_node_footer(struct page *page, nid_t nid, 277 + static inline void fill_node_footer(const struct folio *folio, nid_t nid, 278 278 nid_t ino, unsigned int ofs, bool reset) 279 279 { 280 - struct f2fs_node *rn = F2FS_NODE(page); 280 + struct f2fs_node *rn = F2FS_NODE(folio); 281 281 unsigned int old_flag = 0; 282 282 283 283 if (reset) ··· 293 293 (old_flag & OFFSET_BIT_MASK)); 294 294 } 295 295 296 - static inline void copy_node_footer(struct page *dst, struct page *src) 296 + static inline void copy_node_footer(const struct folio *dst, 297 + const struct folio *src) 297 298 { 298 299 struct f2fs_node *src_rn = F2FS_NODE(src); 299 300 struct f2fs_node *dst_rn = F2FS_NODE(dst); 300 301 memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer)); 301 302 } 302 303 303 - static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) 304 + static inline void fill_node_footer_blkaddr(struct folio *folio, block_t blkaddr) 304 305 { 305 - struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page)); 306 - struct f2fs_node *rn = F2FS_NODE(page); 306 + struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_F_SB(folio)); 307 + struct f2fs_node *rn = F2FS_NODE(folio); 307 308 __u64 cp_ver = cur_cp_version(ckpt); 308 309 309 310 if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) ··· 314 313 rn->footer.next_blkaddr = cpu_to_le32(blkaddr); 315 314 } 316 315 317 - static inline bool is_recoverable_dnode(struct page *page) 316 + static inline bool is_recoverable_dnode(const struct folio *folio) 318 317 { 319 - struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page)); 318 + struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_F_SB(folio)); 320 319 __u64 cp_ver = cur_cp_version(ckpt); 321 320 322 321 /* Don't care crc part, if fsck.f2fs sets it. */ 323 322 if (__is_set_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG)) 324 - return (cp_ver << 32) == (cpver_of_node(page) << 32); 323 + return (cp_ver << 32) == (cpver_of_node(folio) << 32); 325 324 326 325 if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) 327 326 cp_ver |= (cur_cp_crc(ckpt) << 32); 328 327 329 - return cp_ver == cpver_of_node(page); 328 + return cp_ver == cpver_of_node(folio); 330 329 } 331 330 332 331 /* ··· 350 349 * `- indirect node ((6 + 2N) + (N - 1)(N + 1)) 351 350 * `- direct node 352 351 */ 353 - static inline bool IS_DNODE(const struct page *node_page) 352 + static inline bool IS_DNODE(const struct folio *node_folio) 354 353 { 355 - unsigned int ofs = ofs_of_node(node_page); 354 + unsigned int ofs = ofs_of_node(node_folio); 356 355 357 356 if (f2fs_has_xattr_block(ofs)) 358 357 return true; ··· 370 369 371 370 static inline int set_nid(struct folio *folio, int off, nid_t nid, bool i) 372 371 { 373 - struct f2fs_node *rn = F2FS_NODE(&folio->page); 372 + struct f2fs_node *rn = F2FS_NODE(folio); 374 373 375 374 f2fs_folio_wait_writeback(folio, NODE, true, true); 376 375 ··· 381 380 return folio_mark_dirty(folio); 382 381 } 383 382 384 - static inline nid_t get_nid(struct page *p, int off, bool i) 383 + static inline nid_t get_nid(const struct folio *folio, int off, bool i) 385 384 { 386 - struct f2fs_node *rn = F2FS_NODE(p); 385 + struct f2fs_node *rn = F2FS_NODE(folio); 387 386 388 387 if (i) 389 388 return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]); ··· 397 396 * - Mark cold data pages in page cache 398 397 */ 399 398 400 - static inline int is_node(const struct page *page, int type) 399 + static inline int is_node(const struct folio *folio, int type) 401 400 { 402 - struct f2fs_node *rn = F2FS_NODE(page); 401 + struct f2fs_node *rn = F2FS_NODE(folio); 403 402 return le32_to_cpu(rn->footer.flag) & BIT(type); 404 403 } 405 404 406 - #define is_cold_node(page) is_node(page, COLD_BIT_SHIFT) 407 - #define is_fsync_dnode(page) is_node(page, FSYNC_BIT_SHIFT) 408 - #define is_dent_dnode(page) is_node(page, DENT_BIT_SHIFT) 405 + #define is_cold_node(folio) is_node(folio, COLD_BIT_SHIFT) 406 + #define is_fsync_dnode(folio) is_node(folio, FSYNC_BIT_SHIFT) 407 + #define is_dent_dnode(folio) is_node(folio, DENT_BIT_SHIFT) 409 408 410 - static inline void set_cold_node(struct page *page, bool is_dir) 409 + static inline void set_cold_node(const struct folio *folio, bool is_dir) 411 410 { 412 - struct f2fs_node *rn = F2FS_NODE(page); 411 + struct f2fs_node *rn = F2FS_NODE(folio); 413 412 unsigned int flag = le32_to_cpu(rn->footer.flag); 414 413 415 414 if (is_dir) ··· 419 418 rn->footer.flag = cpu_to_le32(flag); 420 419 } 421 420 422 - static inline void set_mark(struct page *page, int mark, int type) 421 + static inline void set_mark(struct folio *folio, int mark, int type) 423 422 { 424 - struct f2fs_node *rn = F2FS_NODE(page); 423 + struct f2fs_node *rn = F2FS_NODE(folio); 425 424 unsigned int flag = le32_to_cpu(rn->footer.flag); 426 425 if (mark) 427 426 flag |= BIT(type); ··· 430 429 rn->footer.flag = cpu_to_le32(flag); 431 430 432 431 #ifdef CONFIG_F2FS_CHECK_FS 433 - f2fs_inode_chksum_set(F2FS_P_SB(page), page); 432 + f2fs_inode_chksum_set(F2FS_F_SB(folio), folio); 434 433 #endif 435 434 } 436 - #define set_dentry_mark(page, mark) set_mark(page, mark, DENT_BIT_SHIFT) 437 - #define set_fsync_mark(page, mark) set_mark(page, mark, FSYNC_BIT_SHIFT) 435 + #define set_dentry_mark(folio, mark) set_mark(folio, mark, DENT_BIT_SHIFT) 436 + #define set_fsync_mark(folio, mark) set_mark(folio, mark, FSYNC_BIT_SHIFT)
+70 -46
fs/f2fs/recovery.c
··· 157 157 return 0; 158 158 } 159 159 160 - static int recover_dentry(struct inode *inode, struct page *ipage, 160 + static int recover_dentry(struct inode *inode, struct folio *ifolio, 161 161 struct list_head *dir_list) 162 162 { 163 - struct f2fs_inode *raw_inode = F2FS_INODE(ipage); 163 + struct f2fs_inode *raw_inode = F2FS_INODE(ifolio); 164 164 nid_t pino = le32_to_cpu(raw_inode->i_pino); 165 165 struct f2fs_dir_entry *de; 166 166 struct f2fs_filename fname; ··· 233 233 else 234 234 name = raw_inode->i_name; 235 235 f2fs_notice(F2FS_I_SB(inode), "%s: ino = %x, name = %s, dir = %lx, err = %d", 236 - __func__, ino_of_node(ipage), name, 236 + __func__, ino_of_node(ifolio), name, 237 237 IS_ERR(dir) ? 0 : dir->i_ino, err); 238 238 return err; 239 239 } 240 240 241 - static int recover_quota_data(struct inode *inode, struct page *page) 241 + static int recover_quota_data(struct inode *inode, struct folio *folio) 242 242 { 243 - struct f2fs_inode *raw = F2FS_INODE(page); 243 + struct f2fs_inode *raw = F2FS_INODE(folio); 244 244 struct iattr attr; 245 245 uid_t i_uid = le32_to_cpu(raw->i_uid); 246 246 gid_t i_gid = le32_to_cpu(raw->i_gid); ··· 277 277 clear_inode_flag(inode, FI_DATA_EXIST); 278 278 } 279 279 280 - static int recover_inode(struct inode *inode, struct page *page) 280 + static int recover_inode(struct inode *inode, struct folio *folio) 281 281 { 282 - struct f2fs_inode *raw = F2FS_INODE(page); 282 + struct f2fs_inode *raw = F2FS_INODE(folio); 283 283 struct f2fs_inode_info *fi = F2FS_I(inode); 284 284 char *name; 285 285 int err; 286 286 287 287 inode->i_mode = le16_to_cpu(raw->i_mode); 288 288 289 - err = recover_quota_data(inode, page); 289 + err = recover_quota_data(inode, folio); 290 290 if (err) 291 291 return err; 292 292 ··· 333 333 if (file_enc_name(inode)) 334 334 name = "<encrypted>"; 335 335 else 336 - name = F2FS_INODE(page)->i_name; 336 + name = F2FS_INODE(folio)->i_name; 337 337 338 338 f2fs_notice(F2FS_I_SB(inode), "recover_inode: ino = %x, name = %s, inline = %x", 339 - ino_of_node(page), name, raw->i_inline); 339 + ino_of_node(folio), name, raw->i_inline); 340 340 return 0; 341 341 } 342 342 ··· 375 375 if (IS_ERR(folio)) 376 376 return PTR_ERR(folio); 377 377 378 - if (!is_recoverable_dnode(&folio->page)) { 378 + if (!is_recoverable_dnode(folio)) { 379 379 f2fs_folio_put(folio, true); 380 380 *is_detecting = false; 381 381 return 0; ··· 424 424 break; 425 425 } 426 426 427 - if (!is_recoverable_dnode(&folio->page)) { 427 + if (!is_recoverable_dnode(folio)) { 428 428 f2fs_folio_put(folio, true); 429 429 break; 430 430 } 431 431 432 - if (!is_fsync_dnode(&folio->page)) 432 + if (!is_fsync_dnode(folio)) 433 433 goto next; 434 434 435 - entry = get_fsync_inode(head, ino_of_node(&folio->page)); 435 + entry = get_fsync_inode(head, ino_of_node(folio)); 436 436 if (!entry) { 437 437 bool quota_inode = false; 438 438 439 439 if (!check_only && 440 - IS_INODE(&folio->page) && 441 - is_dent_dnode(&folio->page)) { 442 - err = f2fs_recover_inode_page(sbi, &folio->page); 440 + IS_INODE(folio) && 441 + is_dent_dnode(folio)) { 442 + err = f2fs_recover_inode_page(sbi, folio); 443 443 if (err) { 444 444 f2fs_folio_put(folio, true); 445 445 break; ··· 451 451 * CP | dnode(F) | inode(DF) 452 452 * For this case, we should not give up now. 453 453 */ 454 - entry = add_fsync_inode(sbi, head, ino_of_node(&folio->page), 454 + entry = add_fsync_inode(sbi, head, ino_of_node(folio), 455 455 quota_inode); 456 456 if (IS_ERR(entry)) { 457 457 err = PTR_ERR(entry); ··· 463 463 } 464 464 entry->blkaddr = blkaddr; 465 465 466 - if (IS_INODE(&folio->page) && is_dent_dnode(&folio->page)) 466 + if (IS_INODE(folio) && is_dent_dnode(folio)) 467 467 entry->last_dentry = blkaddr; 468 468 next: 469 469 /* check next segment */ ··· 527 527 nid = le32_to_cpu(sum.nid); 528 528 ofs_in_node = le16_to_cpu(sum.ofs_in_node); 529 529 530 - max_addrs = ADDRS_PER_PAGE(&dn->node_folio->page, dn->inode); 530 + max_addrs = ADDRS_PER_PAGE(dn->node_folio, dn->inode); 531 531 if (ofs_in_node >= max_addrs) { 532 532 f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%lu, nid:%u, max:%u", 533 533 ofs_in_node, dn->inode->i_ino, nid, max_addrs); ··· 552 552 if (IS_ERR(node_folio)) 553 553 return PTR_ERR(node_folio); 554 554 555 - offset = ofs_of_node(&node_folio->page); 556 - ino = ino_of_node(&node_folio->page); 555 + offset = ofs_of_node(node_folio); 556 + ino = ino_of_node(node_folio); 557 557 f2fs_folio_put(node_folio, true); 558 558 559 559 if (ino != dn->inode->i_ino) { ··· 624 624 { 625 625 struct dnode_of_data dn; 626 626 struct node_info ni; 627 - unsigned int start, end; 627 + unsigned int start = 0, end = 0, index; 628 628 int err = 0, recovered = 0; 629 629 630 630 /* step 1: recover xattr */ 631 - if (IS_INODE(&folio->page)) { 631 + if (IS_INODE(folio)) { 632 632 err = f2fs_recover_inline_xattr(inode, folio); 633 633 if (err) 634 634 goto out; 635 - } else if (f2fs_has_xattr_block(ofs_of_node(&folio->page))) { 636 - err = f2fs_recover_xattr_data(inode, &folio->page); 635 + } else if (f2fs_has_xattr_block(ofs_of_node(folio))) { 636 + err = f2fs_recover_xattr_data(inode, folio); 637 637 if (!err) 638 638 recovered++; 639 639 goto out; ··· 648 648 } 649 649 650 650 /* step 3: recover data indices */ 651 - start = f2fs_start_bidx_of_node(ofs_of_node(&folio->page), inode); 652 - end = start + ADDRS_PER_PAGE(&folio->page, inode); 651 + start = f2fs_start_bidx_of_node(ofs_of_node(folio), inode); 652 + end = start + ADDRS_PER_PAGE(folio, inode); 653 653 654 654 set_new_dnode(&dn, inode, NULL, NULL, 0); 655 655 retry_dn: ··· 668 668 if (err) 669 669 goto err; 670 670 671 - f2fs_bug_on(sbi, ni.ino != ino_of_node(&folio->page)); 671 + f2fs_bug_on(sbi, ni.ino != ino_of_node(folio)); 672 672 673 - if (ofs_of_node(&dn.node_folio->page) != ofs_of_node(&folio->page)) { 673 + if (ofs_of_node(dn.node_folio) != ofs_of_node(folio)) { 674 674 f2fs_warn(sbi, "Inconsistent ofs_of_node, ino:%lu, ofs:%u, %u", 675 - inode->i_ino, ofs_of_node(&dn.node_folio->page), 676 - ofs_of_node(&folio->page)); 675 + inode->i_ino, ofs_of_node(dn.node_folio), 676 + ofs_of_node(folio)); 677 677 err = -EFSCORRUPTED; 678 678 f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); 679 679 goto err; 680 680 } 681 681 682 - for (; start < end; start++, dn.ofs_in_node++) { 682 + for (index = start; index < end; index++, dn.ofs_in_node++) { 683 683 block_t src, dest; 684 684 685 685 src = f2fs_data_blkaddr(&dn); ··· 708 708 } 709 709 710 710 if (!file_keep_isize(inode) && 711 - (i_size_read(inode) <= ((loff_t)start << PAGE_SHIFT))) 711 + (i_size_read(inode) <= ((loff_t)index << PAGE_SHIFT))) 712 712 f2fs_i_size_write(inode, 713 - (loff_t)(start + 1) << PAGE_SHIFT); 713 + (loff_t)(index + 1) << PAGE_SHIFT); 714 714 715 715 /* 716 716 * dest is reserved block, invalidate src block ··· 758 758 } 759 759 } 760 760 761 - copy_node_footer(&dn.node_folio->page, &folio->page); 762 - fill_node_footer(&dn.node_folio->page, dn.nid, ni.ino, 763 - ofs_of_node(&folio->page), false); 761 + copy_node_footer(dn.node_folio, folio); 762 + fill_node_footer(dn.node_folio, dn.nid, ni.ino, 763 + ofs_of_node(folio), false); 764 764 folio_mark_dirty(dn.node_folio); 765 765 err: 766 766 f2fs_put_dnode(&dn); 767 767 out: 768 - f2fs_notice(sbi, "recover_data: ino = %lx (i_size: %s) recovered = %d, err = %d", 769 - inode->i_ino, file_keep_isize(inode) ? "keep" : "recover", 770 - recovered, err); 768 + f2fs_notice(sbi, "recover_data: ino = %lx, nid = %x (i_size: %s), " 769 + "range (%u, %u), recovered = %d, err = %d", 770 + inode->i_ino, nid_of_node(folio), 771 + file_keep_isize(inode) ? "keep" : "recover", 772 + start, end, recovered, err); 771 773 return err; 772 774 } 773 775 ··· 780 778 int err = 0; 781 779 block_t blkaddr; 782 780 unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS; 781 + unsigned int recoverable_dnode = 0; 782 + unsigned int fsynced_dnode = 0; 783 + unsigned int total_dnode = 0; 784 + unsigned int recovered_inode = 0; 785 + unsigned int recovered_dentry = 0; 786 + unsigned int recovered_dnode = 0; 787 + 788 + f2fs_notice(sbi, "do_recover_data: start to recover dnode"); 783 789 784 790 /* get node pages in the current segment */ 785 791 curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); ··· 806 796 break; 807 797 } 808 798 809 - if (!is_recoverable_dnode(&folio->page)) { 799 + if (!is_recoverable_dnode(folio)) { 810 800 f2fs_folio_put(folio, true); 811 801 break; 812 802 } 803 + recoverable_dnode++; 813 804 814 - entry = get_fsync_inode(inode_list, ino_of_node(&folio->page)); 805 + entry = get_fsync_inode(inode_list, ino_of_node(folio)); 815 806 if (!entry) 816 807 goto next; 808 + fsynced_dnode++; 817 809 /* 818 810 * inode(x) | CP | inode(x) | dnode(F) 819 811 * In this case, we can lose the latest inode(x). 820 812 * So, call recover_inode for the inode update. 821 813 */ 822 - if (IS_INODE(&folio->page)) { 823 - err = recover_inode(entry->inode, &folio->page); 814 + if (IS_INODE(folio)) { 815 + err = recover_inode(entry->inode, folio); 824 816 if (err) { 825 817 f2fs_folio_put(folio, true); 826 818 break; 827 819 } 820 + recovered_inode++; 828 821 } 829 822 if (entry->last_dentry == blkaddr) { 830 - err = recover_dentry(entry->inode, &folio->page, dir_list); 823 + err = recover_dentry(entry->inode, folio, dir_list); 831 824 if (err) { 832 825 f2fs_folio_put(folio, true); 833 826 break; 834 827 } 828 + recovered_dentry++; 835 829 } 836 830 err = do_recover_data(sbi, entry->inode, folio); 837 831 if (err) { 838 832 f2fs_folio_put(folio, true); 839 833 break; 840 834 } 835 + recovered_dnode++; 841 836 842 837 if (entry->blkaddr == blkaddr) 843 838 list_move_tail(&entry->list, tmp_inode_list); ··· 855 840 f2fs_folio_put(folio, true); 856 841 857 842 f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks); 843 + total_dnode++; 858 844 } 859 845 if (!err) 860 846 err = f2fs_allocate_new_segments(sbi); 847 + 848 + f2fs_notice(sbi, "do_recover_data: dnode: (recoverable: %u, fsynced: %u, " 849 + "total: %u), recovered: (inode: %u, dentry: %u, dnode: %u), err: %d", 850 + recoverable_dnode, fsynced_dnode, total_dnode, recovered_inode, 851 + recovered_dentry, recovered_dnode, err); 861 852 return err; 862 853 } 863 854 ··· 875 854 int ret = 0; 876 855 unsigned long s_flags = sbi->sb->s_flags; 877 856 bool need_writecp = false; 857 + 858 + f2fs_notice(sbi, "f2fs_recover_fsync_data: recovery fsync data, " 859 + "check_only: %d", check_only); 878 860 879 861 if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE)) 880 862 f2fs_info(sbi, "recover fsync data on readonly fs");
+34 -28
fs/f2fs/segment.c
··· 334 334 goto next; 335 335 } 336 336 337 - blen = min((pgoff_t)ADDRS_PER_PAGE(&dn.node_folio->page, cow_inode), 337 + blen = min((pgoff_t)ADDRS_PER_PAGE(dn.node_folio, cow_inode), 338 338 len); 339 339 index = off; 340 340 for (i = 0; i < blen; i++, dn.ofs_in_node++, index++) { ··· 455 455 } else { 456 456 struct f2fs_gc_control gc_control = { 457 457 .victim_segno = NULL_SEGNO, 458 - .init_gc_type = BG_GC, 458 + .init_gc_type = f2fs_sb_has_blkzoned(sbi) ? 459 + FG_GC : BG_GC, 459 460 .no_bg_gc = true, 460 461 .should_migrate_blocks = false, 461 462 .err_gc_skipped = false, ··· 773 772 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 774 773 775 774 /* need not be added */ 776 - if (IS_CURSEG(sbi, segno)) 775 + if (is_curseg(sbi, segno)) 777 776 return; 778 777 779 778 if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) ··· 800 799 !valid_blocks) || 801 800 valid_blocks == CAP_BLKS_PER_SEC(sbi)); 802 801 803 - if (!IS_CURSEC(sbi, secno)) 802 + if (!is_cursec(sbi, secno)) 804 803 set_bit(secno, dirty_i->dirty_secmap); 805 804 } 806 805 } ··· 839 838 return; 840 839 } 841 840 842 - if (!IS_CURSEC(sbi, secno)) 841 + if (!is_cursec(sbi, secno)) 843 842 set_bit(secno, dirty_i->dirty_secmap); 844 843 } 845 844 } ··· 856 855 unsigned short valid_blocks, ckpt_valid_blocks; 857 856 unsigned int usable_blocks; 858 857 859 - if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno)) 858 + if (segno == NULL_SEGNO || is_curseg(sbi, segno)) 860 859 return; 861 860 862 861 usable_blocks = f2fs_usable_blks_in_seg(sbi, segno); ··· 889 888 for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { 890 889 if (get_valid_blocks(sbi, segno, false)) 891 890 continue; 892 - if (IS_CURSEG(sbi, segno)) 891 + if (is_curseg(sbi, segno)) 893 892 continue; 894 893 __locate_dirty_segment(sbi, segno, PRE); 895 894 __remove_dirty_segment(sbi, segno, DIRTY); ··· 2108 2107 if (!force) { 2109 2108 if (!f2fs_realtime_discard_enable(sbi) || 2110 2109 (!se->valid_blocks && 2111 - !IS_CURSEG(sbi, cpc->trim_start)) || 2110 + !is_curseg(sbi, cpc->trim_start)) || 2112 2111 SM_I(sbi)->dcc_info->nr_discards >= 2113 2112 SM_I(sbi)->dcc_info->max_discards) 2114 2113 return false; ··· 2236 2235 next: 2237 2236 secno = GET_SEC_FROM_SEG(sbi, start); 2238 2237 start_segno = GET_SEG_FROM_SEC(sbi, secno); 2239 - if (!IS_CURSEC(sbi, secno) && 2238 + if (!is_cursec(sbi, secno) && 2240 2239 !get_valid_blocks(sbi, start, true)) 2241 2240 f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno), 2242 2241 BLKS_PER_SEC(sbi)); ··· 3620 3619 else 3621 3620 return CURSEG_COLD_DATA; 3622 3621 } else { 3623 - if (IS_DNODE(fio->page) && is_cold_node(fio->page)) 3622 + if (IS_DNODE(fio->folio) && is_cold_node(fio->folio)) 3624 3623 return CURSEG_WARM_NODE; 3625 3624 else 3626 3625 return CURSEG_COLD_NODE; ··· 3666 3665 if (file_is_cold(inode) || f2fs_need_compress_data(inode)) 3667 3666 return CURSEG_COLD_DATA; 3668 3667 3669 - type = __get_age_segment_type(inode, 3670 - page_folio(fio->page)->index); 3668 + type = __get_age_segment_type(inode, fio->folio->index); 3671 3669 if (type != NO_CHECK_TYPE) 3672 3670 return type; 3673 3671 ··· 3677 3677 return f2fs_rw_hint_to_seg_type(F2FS_I_SB(inode), 3678 3678 inode->i_write_hint); 3679 3679 } else { 3680 - if (IS_DNODE(fio->page)) 3681 - return is_cold_node(fio->page) ? CURSEG_WARM_NODE : 3680 + if (IS_DNODE(fio->folio)) 3681 + return is_cold_node(fio->folio) ? CURSEG_WARM_NODE : 3682 3682 CURSEG_HOT_NODE; 3683 3683 return CURSEG_COLD_NODE; 3684 3684 } ··· 3746 3746 get_random_u32_inclusive(1, sbi->max_fragment_hole); 3747 3747 } 3748 3748 3749 - int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, 3749 + int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct folio *folio, 3750 3750 block_t old_blkaddr, block_t *new_blkaddr, 3751 3751 struct f2fs_summary *sum, int type, 3752 3752 struct f2fs_io_info *fio) ··· 3850 3850 3851 3851 up_write(&sit_i->sentry_lock); 3852 3852 3853 - if (page && IS_NODESEG(curseg->seg_type)) { 3854 - fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg)); 3853 + if (folio && IS_NODESEG(curseg->seg_type)) { 3854 + fill_node_footer_blkaddr(folio, NEXT_FREE_BLKADDR(sbi, curseg)); 3855 3855 3856 - f2fs_inode_chksum_set(sbi, page); 3856 + f2fs_inode_chksum_set(sbi, folio); 3857 3857 } 3858 3858 3859 3859 if (fio) { ··· 3931 3931 3932 3932 static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) 3933 3933 { 3934 - struct folio *folio = page_folio(fio->page); 3934 + struct folio *folio = fio->folio; 3935 3935 enum log_type type = __get_segment_type(fio); 3936 3936 int seg_type = log_type_to_seg_type(type); 3937 3937 bool keep_order = (f2fs_lfs_mode(fio->sbi) && ··· 3940 3940 if (keep_order) 3941 3941 f2fs_down_read(&fio->sbi->io_order_lock); 3942 3942 3943 - if (f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, 3943 + if (f2fs_allocate_data_block(fio->sbi, folio, fio->old_blkaddr, 3944 3944 &fio->new_blkaddr, sum, type, fio)) { 3945 3945 if (fscrypt_inode_uses_fs_layer_crypto(folio->mapping->host)) 3946 3946 fscrypt_finalize_bounce_page(&fio->encrypted_page); 3947 3947 folio_end_writeback(folio); 3948 3948 if (f2fs_in_warm_node_list(fio->sbi, folio)) 3949 3949 f2fs_del_fsync_node_entry(fio->sbi, folio); 3950 + f2fs_bug_on(fio->sbi, !is_set_ckpt_flags(fio->sbi, 3951 + CP_ERROR_FLAG)); 3950 3952 goto out; 3951 3953 } 3954 + 3955 + f2fs_bug_on(fio->sbi, !f2fs_is_valid_blkaddr_raw(fio->sbi, 3956 + fio->new_blkaddr, DATA_GENERIC_ENHANCE)); 3957 + 3952 3958 if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) 3953 3959 f2fs_invalidate_internal_cache(fio->sbi, fio->old_blkaddr, 1); 3954 3960 ··· 3978 3972 .op_flags = REQ_SYNC | REQ_META | REQ_PRIO, 3979 3973 .old_blkaddr = folio->index, 3980 3974 .new_blkaddr = folio->index, 3981 - .page = folio_page(folio, 0), 3975 + .folio = folio, 3982 3976 .encrypted_page = NULL, 3983 3977 .in_list = 0, 3984 3978 }; ··· 4106 4100 4107 4101 if (!recover_curseg) { 4108 4102 /* for recovery flow */ 4109 - if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) { 4103 + if (se->valid_blocks == 0 && !is_curseg(sbi, segno)) { 4110 4104 if (old_blkaddr == NULL_ADDR) 4111 4105 type = CURSEG_COLD_DATA; 4112 4106 else 4113 4107 type = CURSEG_WARM_DATA; 4114 4108 } 4115 4109 } else { 4116 - if (IS_CURSEG(sbi, segno)) { 4110 + if (is_curseg(sbi, segno)) { 4117 4111 /* se->type is volatile as SSR allocation */ 4118 4112 type = __f2fs_get_curseg(sbi, segno); 4119 4113 f2fs_bug_on(sbi, type == NO_CHECK_TYPE); ··· 4197 4191 struct f2fs_sb_info *sbi = F2FS_F_SB(folio); 4198 4192 4199 4193 /* submit cached LFS IO */ 4200 - f2fs_submit_merged_write_cond(sbi, NULL, &folio->page, 0, type); 4194 + f2fs_submit_merged_write_cond(sbi, NULL, folio, 0, type); 4201 4195 /* submit cached IPU IO */ 4202 4196 f2fs_submit_merged_ipu_write(sbi, NULL, folio); 4203 4197 if (ordered) { ··· 5149 5143 5150 5144 if (!valid_blocks || valid_blocks == CAP_BLKS_PER_SEC(sbi)) 5151 5145 continue; 5152 - if (IS_CURSEC(sbi, secno)) 5146 + if (is_cursec(sbi, secno)) 5153 5147 continue; 5154 5148 set_bit(secno, dirty_i->dirty_secmap); 5155 5149 } ··· 5285 5279 * Get # of valid block of the zone. 5286 5280 */ 5287 5281 valid_block_cnt = get_valid_blocks(sbi, zone_segno, true); 5288 - if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno))) { 5282 + if (is_cursec(sbi, GET_SEC_FROM_SEG(sbi, zone_segno))) { 5289 5283 f2fs_notice(sbi, "Open zones: valid block[0x%x,0x%x] cond[%s]", 5290 5284 zone_segno, valid_block_cnt, 5291 5285 blk_zone_cond_str(zone->cond)); ··· 5812 5806 kvfree(sit_i->dirty_sentries_bitmap); 5813 5807 5814 5808 SM_I(sbi)->sit_info = NULL; 5815 - kvfree(sit_i->sit_bitmap); 5809 + kfree(sit_i->sit_bitmap); 5816 5810 #ifdef CONFIG_F2FS_CHECK_FS 5817 - kvfree(sit_i->sit_bitmap_mir); 5811 + kfree(sit_i->sit_bitmap_mir); 5818 5812 kvfree(sit_i->invalid_segmap); 5819 5813 #endif 5820 5814 kfree(sit_i);
+26 -33
fs/f2fs/segment.h
··· 34 34 f2fs_bug_on(sbi, seg_type >= NR_PERSISTENT_LOG); 35 35 } 36 36 37 - #define IS_CURSEG(sbi, seg) \ 38 - (((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ 39 - ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \ 40 - ((seg) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \ 41 - ((seg) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \ 42 - ((seg) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \ 43 - ((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno) || \ 44 - ((seg) == CURSEG_I(sbi, CURSEG_COLD_DATA_PINNED)->segno) || \ 45 - ((seg) == CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC)->segno)) 46 - 47 - #define IS_CURSEC(sbi, secno) \ 48 - (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ 49 - SEGS_PER_SEC(sbi)) || \ 50 - ((secno) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \ 51 - SEGS_PER_SEC(sbi)) || \ 52 - ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \ 53 - SEGS_PER_SEC(sbi)) || \ 54 - ((secno) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \ 55 - SEGS_PER_SEC(sbi)) || \ 56 - ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ 57 - SEGS_PER_SEC(sbi)) || \ 58 - ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ 59 - SEGS_PER_SEC(sbi)) || \ 60 - ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA_PINNED)->segno / \ 61 - SEGS_PER_SEC(sbi)) || \ 62 - ((secno) == CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC)->segno / \ 63 - SEGS_PER_SEC(sbi))) 64 - 65 37 #define MAIN_BLKADDR(sbi) \ 66 38 (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ 67 39 le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr)) ··· 290 318 return (struct curseg_info *)(SM_I(sbi)->curseg_array + type); 291 319 } 292 320 321 + static inline bool is_curseg(struct f2fs_sb_info *sbi, unsigned int segno) 322 + { 323 + int i; 324 + 325 + for (i = CURSEG_HOT_DATA; i < NO_CHECK_TYPE; i++) { 326 + if (segno == CURSEG_I(sbi, i)->segno) 327 + return true; 328 + } 329 + return false; 330 + } 331 + 332 + static inline bool is_cursec(struct f2fs_sb_info *sbi, unsigned int secno) 333 + { 334 + int i; 335 + 336 + for (i = CURSEG_HOT_DATA; i < NO_CHECK_TYPE; i++) { 337 + if (secno == GET_SEC_FROM_SEG(sbi, CURSEG_I(sbi, i)->segno)) 338 + return true; 339 + } 340 + return false; 341 + } 342 + 293 343 static inline struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, 294 344 unsigned int segno) 295 345 { ··· 503 509 504 510 free_i->free_segments++; 505 511 506 - if (!inmem && IS_CURSEC(sbi, secno)) 512 + if (!inmem && is_cursec(sbi, secno)) 507 513 goto unlock_out; 508 514 509 515 /* check large section */ ··· 668 674 unsigned int dent_blocks = total_dent_blocks % CAP_BLKS_PER_SEC(sbi); 669 675 unsigned int data_blocks = 0; 670 676 671 - if (f2fs_lfs_mode(sbi) && 672 - unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { 677 + if (f2fs_lfs_mode(sbi)) { 673 678 total_data_blocks = get_pages(sbi, F2FS_DIRTY_DATA); 674 679 data_secs = total_data_blocks / CAP_BLKS_PER_SEC(sbi); 675 680 data_blocks = total_data_blocks % CAP_BLKS_PER_SEC(sbi); ··· 677 684 if (lower_p) 678 685 *lower_p = node_secs + dent_secs + data_secs; 679 686 if (upper_p) 680 - *upper_p = node_secs + dent_secs + 687 + *upper_p = node_secs + dent_secs + data_secs + 681 688 (node_blocks ? 1 : 0) + (dent_blocks ? 1 : 0) + 682 689 (data_blocks ? 1 : 0); 683 690 if (curseg_p) ··· 979 986 980 987 static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno) 981 988 { 982 - if (IS_CURSEC(sbi, secno) || (sbi->cur_victim_sec == secno)) 989 + if (is_cursec(sbi, secno) || (sbi->cur_victim_sec == secno)) 983 990 return true; 984 991 return false; 985 992 }
+1235 -950
fs/f2fs/super.c
··· 27 27 #include <linux/part_stat.h> 28 28 #include <linux/zstd.h> 29 29 #include <linux/lz4.h> 30 + #include <linux/ctype.h> 31 + #include <linux/fs_parser.h> 30 32 31 33 #include "f2fs.h" 32 34 #include "node.h" ··· 127 125 Opt_disable_roll_forward, 128 126 Opt_norecovery, 129 127 Opt_discard, 130 - Opt_nodiscard, 131 128 Opt_noheap, 132 129 Opt_heap, 133 130 Opt_user_xattr, 134 - Opt_nouser_xattr, 135 131 Opt_acl, 136 - Opt_noacl, 137 132 Opt_active_logs, 138 133 Opt_disable_ext_identify, 139 134 Opt_inline_xattr, 140 - Opt_noinline_xattr, 141 135 Opt_inline_xattr_size, 142 136 Opt_inline_data, 143 137 Opt_inline_dentry, 144 - Opt_noinline_dentry, 145 138 Opt_flush_merge, 146 - Opt_noflush_merge, 147 139 Opt_barrier, 148 - Opt_nobarrier, 149 140 Opt_fastboot, 150 141 Opt_extent_cache, 151 - Opt_noextent_cache, 152 - Opt_noinline_data, 153 142 Opt_data_flush, 154 143 Opt_reserve_root, 155 144 Opt_resgid, ··· 149 156 Opt_fault_injection, 150 157 Opt_fault_type, 151 158 Opt_lazytime, 152 - Opt_nolazytime, 153 159 Opt_quota, 154 - Opt_noquota, 155 160 Opt_usrquota, 156 161 Opt_grpquota, 157 162 Opt_prjquota, 158 163 Opt_usrjquota, 159 164 Opt_grpjquota, 160 165 Opt_prjjquota, 161 - Opt_offusrjquota, 162 - Opt_offgrpjquota, 163 - Opt_offprjjquota, 164 - Opt_jqfmt_vfsold, 165 - Opt_jqfmt_vfsv0, 166 - Opt_jqfmt_vfsv1, 167 166 Opt_alloc, 168 167 Opt_fsync, 169 168 Opt_test_dummy_encryption, ··· 165 180 Opt_checkpoint_disable_cap_perc, 166 181 Opt_checkpoint_enable, 167 182 Opt_checkpoint_merge, 168 - Opt_nocheckpoint_merge, 169 183 Opt_compress_algorithm, 170 184 Opt_compress_log_size, 171 - Opt_compress_extension, 172 185 Opt_nocompress_extension, 186 + Opt_compress_extension, 173 187 Opt_compress_chksum, 174 188 Opt_compress_mode, 175 189 Opt_compress_cache, 176 190 Opt_atgc, 177 191 Opt_gc_merge, 178 - Opt_nogc_merge, 179 192 Opt_discard_unit, 180 193 Opt_memory_mode, 181 194 Opt_age_extent_cache, 182 195 Opt_errors, 183 196 Opt_nat_bits, 197 + Opt_jqfmt, 198 + Opt_checkpoint, 184 199 Opt_err, 185 200 }; 186 201 187 - static match_table_t f2fs_tokens = { 188 - {Opt_gc_background, "background_gc=%s"}, 189 - {Opt_disable_roll_forward, "disable_roll_forward"}, 190 - {Opt_norecovery, "norecovery"}, 191 - {Opt_discard, "discard"}, 192 - {Opt_nodiscard, "nodiscard"}, 193 - {Opt_noheap, "no_heap"}, 194 - {Opt_heap, "heap"}, 195 - {Opt_user_xattr, "user_xattr"}, 196 - {Opt_nouser_xattr, "nouser_xattr"}, 197 - {Opt_acl, "acl"}, 198 - {Opt_noacl, "noacl"}, 199 - {Opt_active_logs, "active_logs=%u"}, 200 - {Opt_disable_ext_identify, "disable_ext_identify"}, 201 - {Opt_inline_xattr, "inline_xattr"}, 202 - {Opt_noinline_xattr, "noinline_xattr"}, 203 - {Opt_inline_xattr_size, "inline_xattr_size=%u"}, 204 - {Opt_inline_data, "inline_data"}, 205 - {Opt_inline_dentry, "inline_dentry"}, 206 - {Opt_noinline_dentry, "noinline_dentry"}, 207 - {Opt_flush_merge, "flush_merge"}, 208 - {Opt_noflush_merge, "noflush_merge"}, 209 - {Opt_barrier, "barrier"}, 210 - {Opt_nobarrier, "nobarrier"}, 211 - {Opt_fastboot, "fastboot"}, 212 - {Opt_extent_cache, "extent_cache"}, 213 - {Opt_noextent_cache, "noextent_cache"}, 214 - {Opt_noinline_data, "noinline_data"}, 215 - {Opt_data_flush, "data_flush"}, 216 - {Opt_reserve_root, "reserve_root=%u"}, 217 - {Opt_resgid, "resgid=%u"}, 218 - {Opt_resuid, "resuid=%u"}, 219 - {Opt_mode, "mode=%s"}, 220 - {Opt_fault_injection, "fault_injection=%u"}, 221 - {Opt_fault_type, "fault_type=%u"}, 222 - {Opt_lazytime, "lazytime"}, 223 - {Opt_nolazytime, "nolazytime"}, 224 - {Opt_quota, "quota"}, 225 - {Opt_noquota, "noquota"}, 226 - {Opt_usrquota, "usrquota"}, 227 - {Opt_grpquota, "grpquota"}, 228 - {Opt_prjquota, "prjquota"}, 229 - {Opt_usrjquota, "usrjquota=%s"}, 230 - {Opt_grpjquota, "grpjquota=%s"}, 231 - {Opt_prjjquota, "prjjquota=%s"}, 232 - {Opt_offusrjquota, "usrjquota="}, 233 - {Opt_offgrpjquota, "grpjquota="}, 234 - {Opt_offprjjquota, "prjjquota="}, 235 - {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, 236 - {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, 237 - {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, 238 - {Opt_alloc, "alloc_mode=%s"}, 239 - {Opt_fsync, "fsync_mode=%s"}, 240 - {Opt_test_dummy_encryption, "test_dummy_encryption=%s"}, 241 - {Opt_test_dummy_encryption, "test_dummy_encryption"}, 242 - {Opt_inlinecrypt, "inlinecrypt"}, 243 - {Opt_checkpoint_disable, "checkpoint=disable"}, 244 - {Opt_checkpoint_disable_cap, "checkpoint=disable:%u"}, 245 - {Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"}, 246 - {Opt_checkpoint_enable, "checkpoint=enable"}, 247 - {Opt_checkpoint_merge, "checkpoint_merge"}, 248 - {Opt_nocheckpoint_merge, "nocheckpoint_merge"}, 249 - {Opt_compress_algorithm, "compress_algorithm=%s"}, 250 - {Opt_compress_log_size, "compress_log_size=%u"}, 251 - {Opt_compress_extension, "compress_extension=%s"}, 252 - {Opt_nocompress_extension, "nocompress_extension=%s"}, 253 - {Opt_compress_chksum, "compress_chksum"}, 254 - {Opt_compress_mode, "compress_mode=%s"}, 255 - {Opt_compress_cache, "compress_cache"}, 256 - {Opt_atgc, "atgc"}, 257 - {Opt_gc_merge, "gc_merge"}, 258 - {Opt_nogc_merge, "nogc_merge"}, 259 - {Opt_discard_unit, "discard_unit=%s"}, 260 - {Opt_memory_mode, "memory=%s"}, 261 - {Opt_age_extent_cache, "age_extent_cache"}, 262 - {Opt_errors, "errors=%s"}, 263 - {Opt_nat_bits, "nat_bits"}, 202 + static const struct constant_table f2fs_param_background_gc[] = { 203 + {"on", BGGC_MODE_ON}, 204 + {"off", BGGC_MODE_OFF}, 205 + {"sync", BGGC_MODE_SYNC}, 206 + {} 207 + }; 208 + 209 + static const struct constant_table f2fs_param_mode[] = { 210 + {"adaptive", FS_MODE_ADAPTIVE}, 211 + {"lfs", FS_MODE_LFS}, 212 + {"fragment:segment", FS_MODE_FRAGMENT_SEG}, 213 + {"fragment:block", FS_MODE_FRAGMENT_BLK}, 214 + {} 215 + }; 216 + 217 + static const struct constant_table f2fs_param_jqfmt[] = { 218 + {"vfsold", QFMT_VFS_OLD}, 219 + {"vfsv0", QFMT_VFS_V0}, 220 + {"vfsv1", QFMT_VFS_V1}, 221 + {} 222 + }; 223 + 224 + static const struct constant_table f2fs_param_alloc_mode[] = { 225 + {"default", ALLOC_MODE_DEFAULT}, 226 + {"reuse", ALLOC_MODE_REUSE}, 227 + {} 228 + }; 229 + static const struct constant_table f2fs_param_fsync_mode[] = { 230 + {"posix", FSYNC_MODE_POSIX}, 231 + {"strict", FSYNC_MODE_STRICT}, 232 + {"nobarrier", FSYNC_MODE_NOBARRIER}, 233 + {} 234 + }; 235 + 236 + static const struct constant_table f2fs_param_compress_mode[] = { 237 + {"fs", COMPR_MODE_FS}, 238 + {"user", COMPR_MODE_USER}, 239 + {} 240 + }; 241 + 242 + static const struct constant_table f2fs_param_discard_unit[] = { 243 + {"block", DISCARD_UNIT_BLOCK}, 244 + {"segment", DISCARD_UNIT_SEGMENT}, 245 + {"section", DISCARD_UNIT_SECTION}, 246 + {} 247 + }; 248 + 249 + static const struct constant_table f2fs_param_memory_mode[] = { 250 + {"normal", MEMORY_MODE_NORMAL}, 251 + {"low", MEMORY_MODE_LOW}, 252 + {} 253 + }; 254 + 255 + static const struct constant_table f2fs_param_errors[] = { 256 + {"remount-ro", MOUNT_ERRORS_READONLY}, 257 + {"continue", MOUNT_ERRORS_CONTINUE}, 258 + {"panic", MOUNT_ERRORS_PANIC}, 259 + {} 260 + }; 261 + 262 + static const struct fs_parameter_spec f2fs_param_specs[] = { 263 + fsparam_enum("background_gc", Opt_gc_background, f2fs_param_background_gc), 264 + fsparam_flag("disable_roll_forward", Opt_disable_roll_forward), 265 + fsparam_flag("norecovery", Opt_norecovery), 266 + fsparam_flag_no("discard", Opt_discard), 267 + fsparam_flag("no_heap", Opt_noheap), 268 + fsparam_flag("heap", Opt_heap), 269 + fsparam_flag_no("user_xattr", Opt_user_xattr), 270 + fsparam_flag_no("acl", Opt_acl), 271 + fsparam_s32("active_logs", Opt_active_logs), 272 + fsparam_flag("disable_ext_identify", Opt_disable_ext_identify), 273 + fsparam_flag_no("inline_xattr", Opt_inline_xattr), 274 + fsparam_s32("inline_xattr_size", Opt_inline_xattr_size), 275 + fsparam_flag_no("inline_data", Opt_inline_data), 276 + fsparam_flag_no("inline_dentry", Opt_inline_dentry), 277 + fsparam_flag_no("flush_merge", Opt_flush_merge), 278 + fsparam_flag_no("barrier", Opt_barrier), 279 + fsparam_flag("fastboot", Opt_fastboot), 280 + fsparam_flag_no("extent_cache", Opt_extent_cache), 281 + fsparam_flag("data_flush", Opt_data_flush), 282 + fsparam_u32("reserve_root", Opt_reserve_root), 283 + fsparam_gid("resgid", Opt_resgid), 284 + fsparam_uid("resuid", Opt_resuid), 285 + fsparam_enum("mode", Opt_mode, f2fs_param_mode), 286 + fsparam_s32("fault_injection", Opt_fault_injection), 287 + fsparam_u32("fault_type", Opt_fault_type), 288 + fsparam_flag_no("lazytime", Opt_lazytime), 289 + fsparam_flag_no("quota", Opt_quota), 290 + fsparam_flag("usrquota", Opt_usrquota), 291 + fsparam_flag("grpquota", Opt_grpquota), 292 + fsparam_flag("prjquota", Opt_prjquota), 293 + fsparam_string_empty("usrjquota", Opt_usrjquota), 294 + fsparam_string_empty("grpjquota", Opt_grpjquota), 295 + fsparam_string_empty("prjjquota", Opt_prjjquota), 296 + fsparam_flag("nat_bits", Opt_nat_bits), 297 + fsparam_enum("jqfmt", Opt_jqfmt, f2fs_param_jqfmt), 298 + fsparam_enum("alloc_mode", Opt_alloc, f2fs_param_alloc_mode), 299 + fsparam_enum("fsync_mode", Opt_fsync, f2fs_param_fsync_mode), 300 + fsparam_string("test_dummy_encryption", Opt_test_dummy_encryption), 301 + fsparam_flag("test_dummy_encryption", Opt_test_dummy_encryption), 302 + fsparam_flag("inlinecrypt", Opt_inlinecrypt), 303 + fsparam_string("checkpoint", Opt_checkpoint), 304 + fsparam_flag_no("checkpoint_merge", Opt_checkpoint_merge), 305 + fsparam_string("compress_algorithm", Opt_compress_algorithm), 306 + fsparam_u32("compress_log_size", Opt_compress_log_size), 307 + fsparam_string("compress_extension", Opt_compress_extension), 308 + fsparam_string("nocompress_extension", Opt_nocompress_extension), 309 + fsparam_flag("compress_chksum", Opt_compress_chksum), 310 + fsparam_enum("compress_mode", Opt_compress_mode, f2fs_param_compress_mode), 311 + fsparam_flag("compress_cache", Opt_compress_cache), 312 + fsparam_flag("atgc", Opt_atgc), 313 + fsparam_flag_no("gc_merge", Opt_gc_merge), 314 + fsparam_enum("discard_unit", Opt_discard_unit, f2fs_param_discard_unit), 315 + fsparam_enum("memory", Opt_memory_mode, f2fs_param_memory_mode), 316 + fsparam_flag("age_extent_cache", Opt_age_extent_cache), 317 + fsparam_enum("errors", Opt_errors, f2fs_param_errors), 318 + {} 319 + }; 320 + 321 + /* Resort to a match_table for this interestingly formatted option */ 322 + static match_table_t f2fs_checkpoint_tokens = { 323 + {Opt_checkpoint_disable, "disable"}, 324 + {Opt_checkpoint_disable_cap, "disable:%u"}, 325 + {Opt_checkpoint_disable_cap_perc, "disable:%u%%"}, 326 + {Opt_checkpoint_enable, "enable"}, 264 327 {Opt_err, NULL}, 265 328 }; 266 329 330 + #define F2FS_SPEC_background_gc (1 << 0) 331 + #define F2FS_SPEC_inline_xattr_size (1 << 1) 332 + #define F2FS_SPEC_active_logs (1 << 2) 333 + #define F2FS_SPEC_reserve_root (1 << 3) 334 + #define F2FS_SPEC_resgid (1 << 4) 335 + #define F2FS_SPEC_resuid (1 << 5) 336 + #define F2FS_SPEC_mode (1 << 6) 337 + #define F2FS_SPEC_fault_injection (1 << 7) 338 + #define F2FS_SPEC_fault_type (1 << 8) 339 + #define F2FS_SPEC_jqfmt (1 << 9) 340 + #define F2FS_SPEC_alloc_mode (1 << 10) 341 + #define F2FS_SPEC_fsync_mode (1 << 11) 342 + #define F2FS_SPEC_checkpoint_disable_cap (1 << 12) 343 + #define F2FS_SPEC_checkpoint_disable_cap_perc (1 << 13) 344 + #define F2FS_SPEC_compress_level (1 << 14) 345 + #define F2FS_SPEC_compress_algorithm (1 << 15) 346 + #define F2FS_SPEC_compress_log_size (1 << 16) 347 + #define F2FS_SPEC_compress_extension (1 << 17) 348 + #define F2FS_SPEC_nocompress_extension (1 << 18) 349 + #define F2FS_SPEC_compress_chksum (1 << 19) 350 + #define F2FS_SPEC_compress_mode (1 << 20) 351 + #define F2FS_SPEC_discard_unit (1 << 21) 352 + #define F2FS_SPEC_memory_mode (1 << 22) 353 + #define F2FS_SPEC_errors (1 << 23) 354 + 355 + struct f2fs_fs_context { 356 + struct f2fs_mount_info info; 357 + unsigned int opt_mask; /* Bits changed */ 358 + unsigned int spec_mask; 359 + unsigned short qname_mask; 360 + }; 361 + 362 + #define F2FS_CTX_INFO(ctx) ((ctx)->info) 363 + 364 + static inline void ctx_set_opt(struct f2fs_fs_context *ctx, 365 + unsigned int flag) 366 + { 367 + ctx->info.opt |= flag; 368 + ctx->opt_mask |= flag; 369 + } 370 + 371 + static inline void ctx_clear_opt(struct f2fs_fs_context *ctx, 372 + unsigned int flag) 373 + { 374 + ctx->info.opt &= ~flag; 375 + ctx->opt_mask |= flag; 376 + } 377 + 378 + static inline bool ctx_test_opt(struct f2fs_fs_context *ctx, 379 + unsigned int flag) 380 + { 381 + return ctx->info.opt & flag; 382 + } 383 + 267 384 void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate, 268 - const char *fmt, ...) 385 + const char *fmt, ...) 269 386 { 270 387 struct va_format vaf; 271 388 va_list args; ··· 379 292 vaf.fmt = printk_skip_level(fmt); 380 293 vaf.va = &args; 381 294 if (limit_rate) 382 - printk_ratelimited("%c%cF2FS-fs (%s): %pV\n", 383 - KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); 295 + if (sbi) 296 + printk_ratelimited("%c%cF2FS-fs (%s): %pV\n", 297 + KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); 298 + else 299 + printk_ratelimited("%c%cF2FS-fs: %pV\n", 300 + KERN_SOH_ASCII, level, &vaf); 384 301 else 385 - printk("%c%cF2FS-fs (%s): %pV\n", 386 - KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); 302 + if (sbi) 303 + printk("%c%cF2FS-fs (%s): %pV\n", 304 + KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); 305 + else 306 + printk("%c%cF2FS-fs: %pV\n", 307 + KERN_SOH_ASCII, level, &vaf); 387 308 388 309 va_end(args); 389 310 } ··· 485 390 #ifdef CONFIG_QUOTA 486 391 static const char * const quotatypes[] = INITQFNAMES; 487 392 #define QTYPE2NAME(t) (quotatypes[t]) 488 - static int f2fs_set_qf_name(struct f2fs_sb_info *sbi, int qtype, 489 - substring_t *args) 393 + /* 394 + * Note the name of the specified quota file. 395 + */ 396 + static int f2fs_note_qf_name(struct fs_context *fc, int qtype, 397 + struct fs_parameter *param) 490 398 { 491 - struct super_block *sb = sbi->sb; 399 + struct f2fs_fs_context *ctx = fc->fs_private; 492 400 char *qname; 493 - int ret = -EINVAL; 494 401 495 - if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) { 496 - f2fs_err(sbi, "Cannot change journaled quota options when quota turned on"); 402 + if (param->size < 1) { 403 + f2fs_err(NULL, "Missing quota name"); 497 404 return -EINVAL; 498 405 } 499 - if (f2fs_sb_has_quota_ino(sbi)) { 500 - f2fs_info(sbi, "QUOTA feature is enabled, so ignore qf_name"); 406 + if (strchr(param->string, '/')) { 407 + f2fs_err(NULL, "quotafile must be on filesystem root"); 408 + return -EINVAL; 409 + } 410 + if (ctx->info.s_qf_names[qtype]) { 411 + if (strcmp(ctx->info.s_qf_names[qtype], param->string) != 0) { 412 + f2fs_err(NULL, "Quota file already specified"); 413 + return -EINVAL; 414 + } 501 415 return 0; 502 416 } 503 417 504 - qname = match_strdup(args); 418 + qname = kmemdup_nul(param->string, param->size, GFP_KERNEL); 505 419 if (!qname) { 506 - f2fs_err(sbi, "Not enough memory for storing quotafile name"); 420 + f2fs_err(NULL, "Not enough memory for storing quotafile name"); 507 421 return -ENOMEM; 508 422 } 509 - if (F2FS_OPTION(sbi).s_qf_names[qtype]) { 510 - if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0) 511 - ret = 0; 512 - else 513 - f2fs_err(sbi, "%s quota file already specified", 514 - QTYPE2NAME(qtype)); 515 - goto errout; 516 - } 517 - if (strchr(qname, '/')) { 518 - f2fs_err(sbi, "quotafile must be on filesystem root"); 519 - goto errout; 520 - } 521 - F2FS_OPTION(sbi).s_qf_names[qtype] = qname; 522 - set_opt(sbi, QUOTA); 523 - return 0; 524 - errout: 525 - kfree(qname); 526 - return ret; 527 - } 528 - 529 - static int f2fs_clear_qf_name(struct f2fs_sb_info *sbi, int qtype) 530 - { 531 - struct super_block *sb = sbi->sb; 532 - 533 - if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) { 534 - f2fs_err(sbi, "Cannot change journaled quota options when quota turned on"); 535 - return -EINVAL; 536 - } 537 - kfree(F2FS_OPTION(sbi).s_qf_names[qtype]); 538 - F2FS_OPTION(sbi).s_qf_names[qtype] = NULL; 423 + F2FS_CTX_INFO(ctx).s_qf_names[qtype] = qname; 424 + ctx->qname_mask |= 1 << qtype; 539 425 return 0; 540 426 } 541 427 542 - static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) 428 + /* 429 + * Clear the name of the specified quota file. 430 + */ 431 + static int f2fs_unnote_qf_name(struct fs_context *fc, int qtype) 543 432 { 544 - /* 545 - * We do the test below only for project quotas. 'usrquota' and 546 - * 'grpquota' mount options are allowed even without quota feature 547 - * to support legacy quotas in quota files. 548 - */ 549 - if (test_opt(sbi, PRJQUOTA) && !f2fs_sb_has_project_quota(sbi)) { 550 - f2fs_err(sbi, "Project quota feature not enabled. Cannot enable project quota enforcement."); 551 - return -1; 552 - } 553 - if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] || 554 - F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] || 555 - F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) { 556 - if (test_opt(sbi, USRQUOTA) && 557 - F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) 558 - clear_opt(sbi, USRQUOTA); 433 + struct f2fs_fs_context *ctx = fc->fs_private; 559 434 560 - if (test_opt(sbi, GRPQUOTA) && 561 - F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) 562 - clear_opt(sbi, GRPQUOTA); 563 - 564 - if (test_opt(sbi, PRJQUOTA) && 565 - F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) 566 - clear_opt(sbi, PRJQUOTA); 567 - 568 - if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) || 569 - test_opt(sbi, PRJQUOTA)) { 570 - f2fs_err(sbi, "old and new quota format mixing"); 571 - return -1; 572 - } 573 - 574 - if (!F2FS_OPTION(sbi).s_jquota_fmt) { 575 - f2fs_err(sbi, "journaled quota format not specified"); 576 - return -1; 577 - } 578 - } 579 - 580 - if (f2fs_sb_has_quota_ino(sbi) && F2FS_OPTION(sbi).s_jquota_fmt) { 581 - f2fs_info(sbi, "QUOTA feature is enabled, so ignore jquota_fmt"); 582 - F2FS_OPTION(sbi).s_jquota_fmt = 0; 583 - } 435 + kfree(ctx->info.s_qf_names[qtype]); 436 + ctx->info.s_qf_names[qtype] = NULL; 437 + ctx->qname_mask |= 1 << qtype; 584 438 return 0; 439 + } 440 + 441 + static void f2fs_unnote_qf_name_all(struct fs_context *fc) 442 + { 443 + int i; 444 + 445 + for (i = 0; i < MAXQUOTAS; i++) 446 + f2fs_unnote_qf_name(fc, i); 585 447 } 586 448 #endif 587 449 588 - static int f2fs_set_test_dummy_encryption(struct f2fs_sb_info *sbi, 589 - const char *opt, 590 - const substring_t *arg, 591 - bool is_remount) 450 + static int f2fs_parse_test_dummy_encryption(const struct fs_parameter *param, 451 + struct f2fs_fs_context *ctx) 592 452 { 593 - struct fs_parameter param = { 594 - .type = fs_value_is_string, 595 - .string = arg->from ? arg->from : "", 596 - }; 597 - struct fscrypt_dummy_policy *policy = 598 - &F2FS_OPTION(sbi).dummy_enc_policy; 599 453 int err; 600 454 601 455 if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) { 602 - f2fs_warn(sbi, "test_dummy_encryption option not supported"); 456 + f2fs_warn(NULL, "test_dummy_encryption option not supported"); 603 457 return -EINVAL; 604 458 } 605 - 606 - if (!f2fs_sb_has_encrypt(sbi)) { 607 - f2fs_err(sbi, "Encrypt feature is off"); 608 - return -EINVAL; 609 - } 610 - 611 - /* 612 - * This mount option is just for testing, and it's not worthwhile to 613 - * implement the extra complexity (e.g. RCU protection) that would be 614 - * needed to allow it to be set or changed during remount. We do allow 615 - * it to be specified during remount, but only if there is no change. 616 - */ 617 - if (is_remount && !fscrypt_is_dummy_policy_set(policy)) { 618 - f2fs_warn(sbi, "Can't set test_dummy_encryption on remount"); 619 - return -EINVAL; 620 - } 621 - 622 - err = fscrypt_parse_test_dummy_encryption(&param, policy); 459 + err = fscrypt_parse_test_dummy_encryption(param, 460 + &ctx->info.dummy_enc_policy); 623 461 if (err) { 624 - if (err == -EEXIST) 625 - f2fs_warn(sbi, 626 - "Can't change test_dummy_encryption on remount"); 627 - else if (err == -EINVAL) 628 - f2fs_warn(sbi, "Value of option \"%s\" is unrecognized", 629 - opt); 462 + if (err == -EINVAL) 463 + f2fs_warn(NULL, "Value of option \"%s\" is unrecognized", 464 + param->key); 465 + else if (err == -EEXIST) 466 + f2fs_warn(NULL, "Conflicting test_dummy_encryption options"); 630 467 else 631 - f2fs_warn(sbi, "Error processing option \"%s\" [%d]", 632 - opt, err); 468 + f2fs_warn(NULL, "Error processing option \"%s\" [%d]", 469 + param->key, err); 633 470 return -EINVAL; 634 471 } 635 - f2fs_warn(sbi, "Test dummy encryption mode enabled"); 636 472 return 0; 637 473 } 638 474 639 475 #ifdef CONFIG_F2FS_FS_COMPRESSION 640 - static bool is_compress_extension_exist(struct f2fs_sb_info *sbi, 476 + static bool is_compress_extension_exist(struct f2fs_mount_info *info, 641 477 const char *new_ext, bool is_ext) 642 478 { 643 479 unsigned char (*ext)[F2FS_EXTENSION_LEN]; ··· 576 550 int i; 577 551 578 552 if (is_ext) { 579 - ext = F2FS_OPTION(sbi).extensions; 580 - ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 553 + ext = info->extensions; 554 + ext_cnt = info->compress_ext_cnt; 581 555 } else { 582 - ext = F2FS_OPTION(sbi).noextensions; 583 - ext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 556 + ext = info->noextensions; 557 + ext_cnt = info->nocompress_ext_cnt; 584 558 } 585 559 586 560 for (i = 0; i < ext_cnt; i++) { ··· 598 572 * extension will be treated as special cases and will not be compressed. 599 573 * 3. Don't allow the non-compress extension specifies all files. 600 574 */ 601 - static int f2fs_test_compress_extension(struct f2fs_sb_info *sbi) 575 + static int f2fs_test_compress_extension(unsigned char (*noext)[F2FS_EXTENSION_LEN], 576 + int noext_cnt, 577 + unsigned char (*ext)[F2FS_EXTENSION_LEN], 578 + int ext_cnt) 602 579 { 603 - unsigned char (*ext)[F2FS_EXTENSION_LEN]; 604 - unsigned char (*noext)[F2FS_EXTENSION_LEN]; 605 - int ext_cnt, noext_cnt, index = 0, no_index = 0; 606 - 607 - ext = F2FS_OPTION(sbi).extensions; 608 - ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 609 - noext = F2FS_OPTION(sbi).noextensions; 610 - noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 580 + int index = 0, no_index = 0; 611 581 612 582 if (!noext_cnt) 613 583 return 0; 614 584 615 585 for (no_index = 0; no_index < noext_cnt; no_index++) { 586 + if (strlen(noext[no_index]) == 0) 587 + continue; 616 588 if (!strcasecmp("*", noext[no_index])) { 617 - f2fs_info(sbi, "Don't allow the nocompress extension specifies all files"); 589 + f2fs_info(NULL, "Don't allow the nocompress extension specifies all files"); 618 590 return -EINVAL; 619 591 } 620 592 for (index = 0; index < ext_cnt; index++) { 593 + if (strlen(ext[index]) == 0) 594 + continue; 621 595 if (!strcasecmp(ext[index], noext[no_index])) { 622 - f2fs_info(sbi, "Don't allow the same extension %s appear in both compress and nocompress extension", 596 + f2fs_info(NULL, "Don't allow the same extension %s appear in both compress and nocompress extension", 623 597 ext[index]); 624 598 return -EINVAL; 625 599 } ··· 629 603 } 630 604 631 605 #ifdef CONFIG_F2FS_FS_LZ4 632 - static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str) 606 + static int f2fs_set_lz4hc_level(struct f2fs_fs_context *ctx, const char *str) 633 607 { 634 608 #ifdef CONFIG_F2FS_FS_LZ4HC 635 609 unsigned int level; 636 610 637 611 if (strlen(str) == 3) { 638 - F2FS_OPTION(sbi).compress_level = 0; 612 + F2FS_CTX_INFO(ctx).compress_level = 0; 613 + ctx->spec_mask |= F2FS_SPEC_compress_level; 639 614 return 0; 640 615 } 641 616 642 617 str += 3; 643 618 644 619 if (str[0] != ':') { 645 - f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>"); 620 + f2fs_info(NULL, "wrong format, e.g. <alg_name>:<compr_level>"); 646 621 return -EINVAL; 647 622 } 648 623 if (kstrtouint(str + 1, 10, &level)) 649 624 return -EINVAL; 650 625 651 626 if (!f2fs_is_compress_level_valid(COMPRESS_LZ4, level)) { 652 - f2fs_info(sbi, "invalid lz4hc compress level: %d", level); 627 + f2fs_info(NULL, "invalid lz4hc compress level: %d", level); 653 628 return -EINVAL; 654 629 } 655 630 656 - F2FS_OPTION(sbi).compress_level = level; 631 + F2FS_CTX_INFO(ctx).compress_level = level; 632 + ctx->spec_mask |= F2FS_SPEC_compress_level; 657 633 return 0; 658 634 #else 659 635 if (strlen(str) == 3) { 660 - F2FS_OPTION(sbi).compress_level = 0; 636 + F2FS_CTX_INFO(ctx).compress_level = 0; 637 + ctx->spec_mask |= F2FS_SPEC_compress_level; 661 638 return 0; 662 639 } 663 - f2fs_info(sbi, "kernel doesn't support lz4hc compression"); 640 + f2fs_info(NULL, "kernel doesn't support lz4hc compression"); 664 641 return -EINVAL; 665 642 #endif 666 643 } 667 644 #endif 668 645 669 646 #ifdef CONFIG_F2FS_FS_ZSTD 670 - static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str) 647 + static int f2fs_set_zstd_level(struct f2fs_fs_context *ctx, const char *str) 671 648 { 672 649 int level; 673 650 int len = 4; 674 651 675 652 if (strlen(str) == len) { 676 - F2FS_OPTION(sbi).compress_level = F2FS_ZSTD_DEFAULT_CLEVEL; 653 + F2FS_CTX_INFO(ctx).compress_level = F2FS_ZSTD_DEFAULT_CLEVEL; 654 + ctx->spec_mask |= F2FS_SPEC_compress_level; 677 655 return 0; 678 656 } 679 657 680 658 str += len; 681 659 682 660 if (str[0] != ':') { 683 - f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>"); 661 + f2fs_info(NULL, "wrong format, e.g. <alg_name>:<compr_level>"); 684 662 return -EINVAL; 685 663 } 686 664 if (kstrtoint(str + 1, 10, &level)) ··· 692 662 693 663 /* f2fs does not support negative compress level now */ 694 664 if (level < 0) { 695 - f2fs_info(sbi, "do not support negative compress level: %d", level); 665 + f2fs_info(NULL, "do not support negative compress level: %d", level); 696 666 return -ERANGE; 697 667 } 698 668 699 669 if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) { 700 - f2fs_info(sbi, "invalid zstd compress level: %d", level); 670 + f2fs_info(NULL, "invalid zstd compress level: %d", level); 701 671 return -EINVAL; 702 672 } 703 673 704 - F2FS_OPTION(sbi).compress_level = level; 674 + F2FS_CTX_INFO(ctx).compress_level = level; 675 + ctx->spec_mask |= F2FS_SPEC_compress_level; 705 676 return 0; 706 677 } 707 678 #endif 708 679 #endif 709 680 710 - static int parse_options(struct f2fs_sb_info *sbi, char *options, bool is_remount) 681 + static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) 711 682 { 712 - substring_t args[MAX_OPT_ARGS]; 683 + struct f2fs_fs_context *ctx = fc->fs_private; 713 684 #ifdef CONFIG_F2FS_FS_COMPRESSION 714 685 unsigned char (*ext)[F2FS_EXTENSION_LEN]; 715 686 unsigned char (*noext)[F2FS_EXTENSION_LEN]; 716 687 int ext_cnt, noext_cnt; 688 + char *name; 717 689 #endif 718 - char *p, *name; 719 - int arg = 0; 720 - kuid_t uid; 721 - kgid_t gid; 722 - int ret; 690 + substring_t args[MAX_OPT_ARGS]; 691 + struct fs_parse_result result; 692 + int token, ret, arg; 723 693 724 - if (!options) 725 - return 0; 694 + token = fs_parse(fc, f2fs_param_specs, param, &result); 695 + if (token < 0) 696 + return token; 726 697 727 - while ((p = strsep(&options, ",")) != NULL) { 728 - int token; 698 + switch (token) { 699 + case Opt_gc_background: 700 + F2FS_CTX_INFO(ctx).bggc_mode = result.uint_32; 701 + ctx->spec_mask |= F2FS_SPEC_background_gc; 702 + break; 703 + case Opt_disable_roll_forward: 704 + ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_ROLL_FORWARD); 705 + break; 706 + case Opt_norecovery: 707 + /* requires ro mount, checked in f2fs_validate_options */ 708 + ctx_set_opt(ctx, F2FS_MOUNT_NORECOVERY); 709 + break; 710 + case Opt_discard: 711 + if (result.negated) 712 + ctx_clear_opt(ctx, F2FS_MOUNT_DISCARD); 713 + else 714 + ctx_set_opt(ctx, F2FS_MOUNT_DISCARD); 715 + break; 716 + case Opt_noheap: 717 + case Opt_heap: 718 + f2fs_warn(NULL, "heap/no_heap options were deprecated"); 719 + break; 720 + #ifdef CONFIG_F2FS_FS_XATTR 721 + case Opt_user_xattr: 722 + if (result.negated) 723 + ctx_clear_opt(ctx, F2FS_MOUNT_XATTR_USER); 724 + else 725 + ctx_set_opt(ctx, F2FS_MOUNT_XATTR_USER); 726 + break; 727 + case Opt_inline_xattr: 728 + if (result.negated) 729 + ctx_clear_opt(ctx, F2FS_MOUNT_INLINE_XATTR); 730 + else 731 + ctx_set_opt(ctx, F2FS_MOUNT_INLINE_XATTR); 732 + break; 733 + case Opt_inline_xattr_size: 734 + if (result.int_32 < MIN_INLINE_XATTR_SIZE || 735 + result.int_32 > MAX_INLINE_XATTR_SIZE) { 736 + f2fs_err(NULL, "inline xattr size is out of range: %u ~ %u", 737 + (u32)MIN_INLINE_XATTR_SIZE, (u32)MAX_INLINE_XATTR_SIZE); 738 + return -EINVAL; 739 + } 740 + ctx_set_opt(ctx, F2FS_MOUNT_INLINE_XATTR_SIZE); 741 + F2FS_CTX_INFO(ctx).inline_xattr_size = result.int_32; 742 + ctx->spec_mask |= F2FS_SPEC_inline_xattr_size; 743 + break; 744 + #else 745 + case Opt_user_xattr: 746 + case Opt_inline_xattr: 747 + case Opt_inline_xattr_size: 748 + f2fs_info(NULL, "%s options not supported", param->key); 749 + break; 750 + #endif 751 + #ifdef CONFIG_F2FS_FS_POSIX_ACL 752 + case Opt_acl: 753 + if (result.negated) 754 + ctx_clear_opt(ctx, F2FS_MOUNT_POSIX_ACL); 755 + else 756 + ctx_set_opt(ctx, F2FS_MOUNT_POSIX_ACL); 757 + break; 758 + #else 759 + case Opt_acl: 760 + f2fs_info(NULL, "%s options not supported", param->key); 761 + break; 762 + #endif 763 + case Opt_active_logs: 764 + if (result.int_32 != 2 && result.int_32 != 4 && 765 + result.int_32 != NR_CURSEG_PERSIST_TYPE) 766 + return -EINVAL; 767 + ctx->spec_mask |= F2FS_SPEC_active_logs; 768 + F2FS_CTX_INFO(ctx).active_logs = result.int_32; 769 + break; 770 + case Opt_disable_ext_identify: 771 + ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_EXT_IDENTIFY); 772 + break; 773 + case Opt_inline_data: 774 + if (result.negated) 775 + ctx_clear_opt(ctx, F2FS_MOUNT_INLINE_DATA); 776 + else 777 + ctx_set_opt(ctx, F2FS_MOUNT_INLINE_DATA); 778 + break; 779 + case Opt_inline_dentry: 780 + if (result.negated) 781 + ctx_clear_opt(ctx, F2FS_MOUNT_INLINE_DENTRY); 782 + else 783 + ctx_set_opt(ctx, F2FS_MOUNT_INLINE_DENTRY); 784 + break; 785 + case Opt_flush_merge: 786 + if (result.negated) 787 + ctx_clear_opt(ctx, F2FS_MOUNT_FLUSH_MERGE); 788 + else 789 + ctx_set_opt(ctx, F2FS_MOUNT_FLUSH_MERGE); 790 + break; 791 + case Opt_barrier: 792 + if (result.negated) 793 + ctx_set_opt(ctx, F2FS_MOUNT_NOBARRIER); 794 + else 795 + ctx_clear_opt(ctx, F2FS_MOUNT_NOBARRIER); 796 + break; 797 + case Opt_fastboot: 798 + ctx_set_opt(ctx, F2FS_MOUNT_FASTBOOT); 799 + break; 800 + case Opt_extent_cache: 801 + if (result.negated) 802 + ctx_clear_opt(ctx, F2FS_MOUNT_READ_EXTENT_CACHE); 803 + else 804 + ctx_set_opt(ctx, F2FS_MOUNT_READ_EXTENT_CACHE); 805 + break; 806 + case Opt_data_flush: 807 + ctx_set_opt(ctx, F2FS_MOUNT_DATA_FLUSH); 808 + break; 809 + case Opt_reserve_root: 810 + ctx_set_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); 811 + F2FS_CTX_INFO(ctx).root_reserved_blocks = result.uint_32; 812 + ctx->spec_mask |= F2FS_SPEC_reserve_root; 813 + break; 814 + case Opt_resuid: 815 + F2FS_CTX_INFO(ctx).s_resuid = result.uid; 816 + ctx->spec_mask |= F2FS_SPEC_resuid; 817 + break; 818 + case Opt_resgid: 819 + F2FS_CTX_INFO(ctx).s_resgid = result.gid; 820 + ctx->spec_mask |= F2FS_SPEC_resgid; 821 + break; 822 + case Opt_mode: 823 + F2FS_CTX_INFO(ctx).fs_mode = result.uint_32; 824 + ctx->spec_mask |= F2FS_SPEC_mode; 825 + break; 826 + #ifdef CONFIG_F2FS_FAULT_INJECTION 827 + case Opt_fault_injection: 828 + F2FS_CTX_INFO(ctx).fault_info.inject_rate = result.int_32; 829 + ctx->spec_mask |= F2FS_SPEC_fault_injection; 830 + ctx_set_opt(ctx, F2FS_MOUNT_FAULT_INJECTION); 831 + break; 729 832 730 - if (!*p) 731 - continue; 833 + case Opt_fault_type: 834 + if (result.uint_32 > BIT(FAULT_MAX)) 835 + return -EINVAL; 836 + F2FS_CTX_INFO(ctx).fault_info.inject_type = result.uint_32; 837 + ctx->spec_mask |= F2FS_SPEC_fault_type; 838 + ctx_set_opt(ctx, F2FS_MOUNT_FAULT_INJECTION); 839 + break; 840 + #else 841 + case Opt_fault_injection: 842 + case Opt_fault_type: 843 + f2fs_info(NULL, "%s options not supported", param->key); 844 + break; 845 + #endif 846 + case Opt_lazytime: 847 + if (result.negated) 848 + ctx_clear_opt(ctx, F2FS_MOUNT_LAZYTIME); 849 + else 850 + ctx_set_opt(ctx, F2FS_MOUNT_LAZYTIME); 851 + break; 852 + #ifdef CONFIG_QUOTA 853 + case Opt_quota: 854 + if (result.negated) { 855 + ctx_clear_opt(ctx, F2FS_MOUNT_QUOTA); 856 + ctx_clear_opt(ctx, F2FS_MOUNT_USRQUOTA); 857 + ctx_clear_opt(ctx, F2FS_MOUNT_GRPQUOTA); 858 + ctx_clear_opt(ctx, F2FS_MOUNT_PRJQUOTA); 859 + } else 860 + ctx_set_opt(ctx, F2FS_MOUNT_USRQUOTA); 861 + break; 862 + case Opt_usrquota: 863 + ctx_set_opt(ctx, F2FS_MOUNT_USRQUOTA); 864 + break; 865 + case Opt_grpquota: 866 + ctx_set_opt(ctx, F2FS_MOUNT_GRPQUOTA); 867 + break; 868 + case Opt_prjquota: 869 + ctx_set_opt(ctx, F2FS_MOUNT_PRJQUOTA); 870 + break; 871 + case Opt_usrjquota: 872 + if (!*param->string) 873 + ret = f2fs_unnote_qf_name(fc, USRQUOTA); 874 + else 875 + ret = f2fs_note_qf_name(fc, USRQUOTA, param); 876 + if (ret) 877 + return ret; 878 + break; 879 + case Opt_grpjquota: 880 + if (!*param->string) 881 + ret = f2fs_unnote_qf_name(fc, GRPQUOTA); 882 + else 883 + ret = f2fs_note_qf_name(fc, GRPQUOTA, param); 884 + if (ret) 885 + return ret; 886 + break; 887 + case Opt_prjjquota: 888 + if (!*param->string) 889 + ret = f2fs_unnote_qf_name(fc, PRJQUOTA); 890 + else 891 + ret = f2fs_note_qf_name(fc, PRJQUOTA, param); 892 + if (ret) 893 + return ret; 894 + break; 895 + case Opt_jqfmt: 896 + F2FS_CTX_INFO(ctx).s_jquota_fmt = result.int_32; 897 + ctx->spec_mask |= F2FS_SPEC_jqfmt; 898 + break; 899 + #else 900 + case Opt_quota: 901 + case Opt_usrquota: 902 + case Opt_grpquota: 903 + case Opt_prjquota: 904 + case Opt_usrjquota: 905 + case Opt_grpjquota: 906 + case Opt_prjjquota: 907 + f2fs_info(NULL, "quota operations not supported"); 908 + break; 909 + #endif 910 + case Opt_alloc: 911 + F2FS_CTX_INFO(ctx).alloc_mode = result.uint_32; 912 + ctx->spec_mask |= F2FS_SPEC_alloc_mode; 913 + break; 914 + case Opt_fsync: 915 + F2FS_CTX_INFO(ctx).fsync_mode = result.uint_32; 916 + ctx->spec_mask |= F2FS_SPEC_fsync_mode; 917 + break; 918 + case Opt_test_dummy_encryption: 919 + ret = f2fs_parse_test_dummy_encryption(param, ctx); 920 + if (ret) 921 + return ret; 922 + break; 923 + case Opt_inlinecrypt: 924 + #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT 925 + ctx_set_opt(ctx, F2FS_MOUNT_INLINECRYPT); 926 + #else 927 + f2fs_info(NULL, "inline encryption not supported"); 928 + #endif 929 + break; 930 + case Opt_checkpoint: 732 931 /* 733 932 * Initialize args struct so we know whether arg was 734 933 * found; some options take optional arguments. 735 934 */ 736 - args[0].to = args[0].from = NULL; 737 - token = match_token(p, f2fs_tokens, args); 935 + args[0].from = args[0].to = NULL; 936 + arg = 0; 738 937 938 + /* revert to match_table for checkpoint= options */ 939 + token = match_token(param->string, f2fs_checkpoint_tokens, args); 739 940 switch (token) { 740 - case Opt_gc_background: 741 - name = match_strdup(&args[0]); 742 - 743 - if (!name) 744 - return -ENOMEM; 745 - if (!strcmp(name, "on")) { 746 - F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; 747 - } else if (!strcmp(name, "off")) { 748 - if (f2fs_sb_has_blkzoned(sbi)) { 749 - f2fs_warn(sbi, "zoned devices need bggc"); 750 - kfree(name); 751 - return -EINVAL; 752 - } 753 - F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_OFF; 754 - } else if (!strcmp(name, "sync")) { 755 - F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_SYNC; 756 - } else { 757 - kfree(name); 758 - return -EINVAL; 759 - } 760 - kfree(name); 761 - break; 762 - case Opt_disable_roll_forward: 763 - set_opt(sbi, DISABLE_ROLL_FORWARD); 764 - break; 765 - case Opt_norecovery: 766 - /* requires ro mount, checked in f2fs_default_check */ 767 - set_opt(sbi, NORECOVERY); 768 - break; 769 - case Opt_discard: 770 - if (!f2fs_hw_support_discard(sbi)) { 771 - f2fs_warn(sbi, "device does not support discard"); 772 - break; 773 - } 774 - set_opt(sbi, DISCARD); 775 - break; 776 - case Opt_nodiscard: 777 - if (f2fs_hw_should_discard(sbi)) { 778 - f2fs_warn(sbi, "discard is required for zoned block devices"); 779 - return -EINVAL; 780 - } 781 - clear_opt(sbi, DISCARD); 782 - break; 783 - case Opt_noheap: 784 - case Opt_heap: 785 - f2fs_warn(sbi, "heap/no_heap options were deprecated"); 786 - break; 787 - #ifdef CONFIG_F2FS_FS_XATTR 788 - case Opt_user_xattr: 789 - set_opt(sbi, XATTR_USER); 790 - break; 791 - case Opt_nouser_xattr: 792 - clear_opt(sbi, XATTR_USER); 793 - break; 794 - case Opt_inline_xattr: 795 - set_opt(sbi, INLINE_XATTR); 796 - break; 797 - case Opt_noinline_xattr: 798 - clear_opt(sbi, INLINE_XATTR); 799 - break; 800 - case Opt_inline_xattr_size: 801 - if (args->from && match_int(args, &arg)) 802 - return -EINVAL; 803 - set_opt(sbi, INLINE_XATTR_SIZE); 804 - F2FS_OPTION(sbi).inline_xattr_size = arg; 805 - break; 806 - #else 807 - case Opt_user_xattr: 808 - case Opt_nouser_xattr: 809 - case Opt_inline_xattr: 810 - case Opt_noinline_xattr: 811 - case Opt_inline_xattr_size: 812 - f2fs_info(sbi, "xattr options not supported"); 813 - break; 814 - #endif 815 - #ifdef CONFIG_F2FS_FS_POSIX_ACL 816 - case Opt_acl: 817 - set_opt(sbi, POSIX_ACL); 818 - break; 819 - case Opt_noacl: 820 - clear_opt(sbi, POSIX_ACL); 821 - break; 822 - #else 823 - case Opt_acl: 824 - case Opt_noacl: 825 - f2fs_info(sbi, "acl options not supported"); 826 - break; 827 - #endif 828 - case Opt_active_logs: 829 - if (args->from && match_int(args, &arg)) 830 - return -EINVAL; 831 - if (arg != 2 && arg != 4 && 832 - arg != NR_CURSEG_PERSIST_TYPE) 833 - return -EINVAL; 834 - F2FS_OPTION(sbi).active_logs = arg; 835 - break; 836 - case Opt_disable_ext_identify: 837 - set_opt(sbi, DISABLE_EXT_IDENTIFY); 838 - break; 839 - case Opt_inline_data: 840 - set_opt(sbi, INLINE_DATA); 841 - break; 842 - case Opt_inline_dentry: 843 - set_opt(sbi, INLINE_DENTRY); 844 - break; 845 - case Opt_noinline_dentry: 846 - clear_opt(sbi, INLINE_DENTRY); 847 - break; 848 - case Opt_flush_merge: 849 - set_opt(sbi, FLUSH_MERGE); 850 - break; 851 - case Opt_noflush_merge: 852 - clear_opt(sbi, FLUSH_MERGE); 853 - break; 854 - case Opt_nobarrier: 855 - set_opt(sbi, NOBARRIER); 856 - break; 857 - case Opt_barrier: 858 - clear_opt(sbi, NOBARRIER); 859 - break; 860 - case Opt_fastboot: 861 - set_opt(sbi, FASTBOOT); 862 - break; 863 - case Opt_extent_cache: 864 - set_opt(sbi, READ_EXTENT_CACHE); 865 - break; 866 - case Opt_noextent_cache: 867 - if (f2fs_sb_has_device_alias(sbi)) { 868 - f2fs_err(sbi, "device aliasing requires extent cache"); 869 - return -EINVAL; 870 - } 871 - clear_opt(sbi, READ_EXTENT_CACHE); 872 - break; 873 - case Opt_noinline_data: 874 - clear_opt(sbi, INLINE_DATA); 875 - break; 876 - case Opt_data_flush: 877 - set_opt(sbi, DATA_FLUSH); 878 - break; 879 - case Opt_reserve_root: 880 - if (args->from && match_int(args, &arg)) 881 - return -EINVAL; 882 - if (test_opt(sbi, RESERVE_ROOT)) { 883 - f2fs_info(sbi, "Preserve previous reserve_root=%u", 884 - F2FS_OPTION(sbi).root_reserved_blocks); 885 - } else { 886 - F2FS_OPTION(sbi).root_reserved_blocks = arg; 887 - set_opt(sbi, RESERVE_ROOT); 888 - } 889 - break; 890 - case Opt_resuid: 891 - if (args->from && match_int(args, &arg)) 892 - return -EINVAL; 893 - uid = make_kuid(current_user_ns(), arg); 894 - if (!uid_valid(uid)) { 895 - f2fs_err(sbi, "Invalid uid value %d", arg); 896 - return -EINVAL; 897 - } 898 - F2FS_OPTION(sbi).s_resuid = uid; 899 - break; 900 - case Opt_resgid: 901 - if (args->from && match_int(args, &arg)) 902 - return -EINVAL; 903 - gid = make_kgid(current_user_ns(), arg); 904 - if (!gid_valid(gid)) { 905 - f2fs_err(sbi, "Invalid gid value %d", arg); 906 - return -EINVAL; 907 - } 908 - F2FS_OPTION(sbi).s_resgid = gid; 909 - break; 910 - case Opt_mode: 911 - name = match_strdup(&args[0]); 912 - 913 - if (!name) 914 - return -ENOMEM; 915 - if (!strcmp(name, "adaptive")) { 916 - F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; 917 - } else if (!strcmp(name, "lfs")) { 918 - F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; 919 - } else if (!strcmp(name, "fragment:segment")) { 920 - F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG; 921 - } else if (!strcmp(name, "fragment:block")) { 922 - F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK; 923 - } else { 924 - kfree(name); 925 - return -EINVAL; 926 - } 927 - kfree(name); 928 - break; 929 - #ifdef CONFIG_F2FS_FAULT_INJECTION 930 - case Opt_fault_injection: 931 - if (args->from && match_int(args, &arg)) 932 - return -EINVAL; 933 - if (f2fs_build_fault_attr(sbi, arg, 0, FAULT_RATE)) 934 - return -EINVAL; 935 - set_opt(sbi, FAULT_INJECTION); 936 - break; 937 - 938 - case Opt_fault_type: 939 - if (args->from && match_int(args, &arg)) 940 - return -EINVAL; 941 - if (f2fs_build_fault_attr(sbi, 0, arg, FAULT_TYPE)) 942 - return -EINVAL; 943 - set_opt(sbi, FAULT_INJECTION); 944 - break; 945 - #else 946 - case Opt_fault_injection: 947 - case Opt_fault_type: 948 - f2fs_info(sbi, "fault injection options not supported"); 949 - break; 950 - #endif 951 - case Opt_lazytime: 952 - set_opt(sbi, LAZYTIME); 953 - break; 954 - case Opt_nolazytime: 955 - clear_opt(sbi, LAZYTIME); 956 - break; 957 - #ifdef CONFIG_QUOTA 958 - case Opt_quota: 959 - case Opt_usrquota: 960 - set_opt(sbi, USRQUOTA); 961 - break; 962 - case Opt_grpquota: 963 - set_opt(sbi, GRPQUOTA); 964 - break; 965 - case Opt_prjquota: 966 - set_opt(sbi, PRJQUOTA); 967 - break; 968 - case Opt_usrjquota: 969 - ret = f2fs_set_qf_name(sbi, USRQUOTA, &args[0]); 970 - if (ret) 971 - return ret; 972 - break; 973 - case Opt_grpjquota: 974 - ret = f2fs_set_qf_name(sbi, GRPQUOTA, &args[0]); 975 - if (ret) 976 - return ret; 977 - break; 978 - case Opt_prjjquota: 979 - ret = f2fs_set_qf_name(sbi, PRJQUOTA, &args[0]); 980 - if (ret) 981 - return ret; 982 - break; 983 - case Opt_offusrjquota: 984 - ret = f2fs_clear_qf_name(sbi, USRQUOTA); 985 - if (ret) 986 - return ret; 987 - break; 988 - case Opt_offgrpjquota: 989 - ret = f2fs_clear_qf_name(sbi, GRPQUOTA); 990 - if (ret) 991 - return ret; 992 - break; 993 - case Opt_offprjjquota: 994 - ret = f2fs_clear_qf_name(sbi, PRJQUOTA); 995 - if (ret) 996 - return ret; 997 - break; 998 - case Opt_jqfmt_vfsold: 999 - F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD; 1000 - break; 1001 - case Opt_jqfmt_vfsv0: 1002 - F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0; 1003 - break; 1004 - case Opt_jqfmt_vfsv1: 1005 - F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1; 1006 - break; 1007 - case Opt_noquota: 1008 - clear_opt(sbi, QUOTA); 1009 - clear_opt(sbi, USRQUOTA); 1010 - clear_opt(sbi, GRPQUOTA); 1011 - clear_opt(sbi, PRJQUOTA); 1012 - break; 1013 - #else 1014 - case Opt_quota: 1015 - case Opt_usrquota: 1016 - case Opt_grpquota: 1017 - case Opt_prjquota: 1018 - case Opt_usrjquota: 1019 - case Opt_grpjquota: 1020 - case Opt_prjjquota: 1021 - case Opt_offusrjquota: 1022 - case Opt_offgrpjquota: 1023 - case Opt_offprjjquota: 1024 - case Opt_jqfmt_vfsold: 1025 - case Opt_jqfmt_vfsv0: 1026 - case Opt_jqfmt_vfsv1: 1027 - case Opt_noquota: 1028 - f2fs_info(sbi, "quota operations not supported"); 1029 - break; 1030 - #endif 1031 - case Opt_alloc: 1032 - name = match_strdup(&args[0]); 1033 - if (!name) 1034 - return -ENOMEM; 1035 - 1036 - if (!strcmp(name, "default")) { 1037 - F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; 1038 - } else if (!strcmp(name, "reuse")) { 1039 - F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; 1040 - } else { 1041 - kfree(name); 1042 - return -EINVAL; 1043 - } 1044 - kfree(name); 1045 - break; 1046 - case Opt_fsync: 1047 - name = match_strdup(&args[0]); 1048 - if (!name) 1049 - return -ENOMEM; 1050 - if (!strcmp(name, "posix")) { 1051 - F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; 1052 - } else if (!strcmp(name, "strict")) { 1053 - F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT; 1054 - } else if (!strcmp(name, "nobarrier")) { 1055 - F2FS_OPTION(sbi).fsync_mode = 1056 - FSYNC_MODE_NOBARRIER; 1057 - } else { 1058 - kfree(name); 1059 - return -EINVAL; 1060 - } 1061 - kfree(name); 1062 - break; 1063 - case Opt_test_dummy_encryption: 1064 - ret = f2fs_set_test_dummy_encryption(sbi, p, &args[0], 1065 - is_remount); 1066 - if (ret) 1067 - return ret; 1068 - break; 1069 - case Opt_inlinecrypt: 1070 - #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT 1071 - set_opt(sbi, INLINECRYPT); 1072 - #else 1073 - f2fs_info(sbi, "inline encryption not supported"); 1074 - #endif 1075 - break; 1076 941 case Opt_checkpoint_disable_cap_perc: 1077 942 if (args->from && match_int(args, &arg)) 1078 943 return -EINVAL; 1079 944 if (arg < 0 || arg > 100) 1080 945 return -EINVAL; 1081 - F2FS_OPTION(sbi).unusable_cap_perc = arg; 1082 - set_opt(sbi, DISABLE_CHECKPOINT); 946 + F2FS_CTX_INFO(ctx).unusable_cap_perc = arg; 947 + ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap_perc; 948 + ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); 1083 949 break; 1084 950 case Opt_checkpoint_disable_cap: 1085 951 if (args->from && match_int(args, &arg)) 1086 952 return -EINVAL; 1087 - F2FS_OPTION(sbi).unusable_cap = arg; 1088 - set_opt(sbi, DISABLE_CHECKPOINT); 953 + F2FS_CTX_INFO(ctx).unusable_cap = arg; 954 + ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap; 955 + ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); 1089 956 break; 1090 957 case Opt_checkpoint_disable: 1091 - set_opt(sbi, DISABLE_CHECKPOINT); 958 + ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); 1092 959 break; 1093 960 case Opt_checkpoint_enable: 1094 - clear_opt(sbi, DISABLE_CHECKPOINT); 1095 - break; 1096 - case Opt_checkpoint_merge: 1097 - set_opt(sbi, MERGE_CHECKPOINT); 1098 - break; 1099 - case Opt_nocheckpoint_merge: 1100 - clear_opt(sbi, MERGE_CHECKPOINT); 1101 - break; 1102 - #ifdef CONFIG_F2FS_FS_COMPRESSION 1103 - case Opt_compress_algorithm: 1104 - if (!f2fs_sb_has_compression(sbi)) { 1105 - f2fs_info(sbi, "Image doesn't support compression"); 1106 - break; 1107 - } 1108 - name = match_strdup(&args[0]); 1109 - if (!name) 1110 - return -ENOMEM; 1111 - if (!strcmp(name, "lzo")) { 1112 - #ifdef CONFIG_F2FS_FS_LZO 1113 - F2FS_OPTION(sbi).compress_level = 0; 1114 - F2FS_OPTION(sbi).compress_algorithm = 1115 - COMPRESS_LZO; 1116 - #else 1117 - f2fs_info(sbi, "kernel doesn't support lzo compression"); 1118 - #endif 1119 - } else if (!strncmp(name, "lz4", 3)) { 1120 - #ifdef CONFIG_F2FS_FS_LZ4 1121 - ret = f2fs_set_lz4hc_level(sbi, name); 1122 - if (ret) { 1123 - kfree(name); 1124 - return -EINVAL; 1125 - } 1126 - F2FS_OPTION(sbi).compress_algorithm = 1127 - COMPRESS_LZ4; 1128 - #else 1129 - f2fs_info(sbi, "kernel doesn't support lz4 compression"); 1130 - #endif 1131 - } else if (!strncmp(name, "zstd", 4)) { 1132 - #ifdef CONFIG_F2FS_FS_ZSTD 1133 - ret = f2fs_set_zstd_level(sbi, name); 1134 - if (ret) { 1135 - kfree(name); 1136 - return -EINVAL; 1137 - } 1138 - F2FS_OPTION(sbi).compress_algorithm = 1139 - COMPRESS_ZSTD; 1140 - #else 1141 - f2fs_info(sbi, "kernel doesn't support zstd compression"); 1142 - #endif 1143 - } else if (!strcmp(name, "lzo-rle")) { 1144 - #ifdef CONFIG_F2FS_FS_LZORLE 1145 - F2FS_OPTION(sbi).compress_level = 0; 1146 - F2FS_OPTION(sbi).compress_algorithm = 1147 - COMPRESS_LZORLE; 1148 - #else 1149 - f2fs_info(sbi, "kernel doesn't support lzorle compression"); 1150 - #endif 1151 - } else { 1152 - kfree(name); 1153 - return -EINVAL; 1154 - } 1155 - kfree(name); 1156 - break; 1157 - case Opt_compress_log_size: 1158 - if (!f2fs_sb_has_compression(sbi)) { 1159 - f2fs_info(sbi, "Image doesn't support compression"); 1160 - break; 1161 - } 1162 - if (args->from && match_int(args, &arg)) 1163 - return -EINVAL; 1164 - if (arg < MIN_COMPRESS_LOG_SIZE || 1165 - arg > MAX_COMPRESS_LOG_SIZE) { 1166 - f2fs_err(sbi, 1167 - "Compress cluster log size is out of range"); 1168 - return -EINVAL; 1169 - } 1170 - F2FS_OPTION(sbi).compress_log_size = arg; 1171 - break; 1172 - case Opt_compress_extension: 1173 - if (!f2fs_sb_has_compression(sbi)) { 1174 - f2fs_info(sbi, "Image doesn't support compression"); 1175 - break; 1176 - } 1177 - name = match_strdup(&args[0]); 1178 - if (!name) 1179 - return -ENOMEM; 1180 - 1181 - ext = F2FS_OPTION(sbi).extensions; 1182 - ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 1183 - 1184 - if (strlen(name) >= F2FS_EXTENSION_LEN || 1185 - ext_cnt >= COMPRESS_EXT_NUM) { 1186 - f2fs_err(sbi, 1187 - "invalid extension length/number"); 1188 - kfree(name); 1189 - return -EINVAL; 1190 - } 1191 - 1192 - if (is_compress_extension_exist(sbi, name, true)) { 1193 - kfree(name); 1194 - break; 1195 - } 1196 - 1197 - ret = strscpy(ext[ext_cnt], name); 1198 - if (ret < 0) { 1199 - kfree(name); 1200 - return ret; 1201 - } 1202 - F2FS_OPTION(sbi).compress_ext_cnt++; 1203 - kfree(name); 1204 - break; 1205 - case Opt_nocompress_extension: 1206 - if (!f2fs_sb_has_compression(sbi)) { 1207 - f2fs_info(sbi, "Image doesn't support compression"); 1208 - break; 1209 - } 1210 - name = match_strdup(&args[0]); 1211 - if (!name) 1212 - return -ENOMEM; 1213 - 1214 - noext = F2FS_OPTION(sbi).noextensions; 1215 - noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 1216 - 1217 - if (strlen(name) >= F2FS_EXTENSION_LEN || 1218 - noext_cnt >= COMPRESS_EXT_NUM) { 1219 - f2fs_err(sbi, 1220 - "invalid extension length/number"); 1221 - kfree(name); 1222 - return -EINVAL; 1223 - } 1224 - 1225 - if (is_compress_extension_exist(sbi, name, false)) { 1226 - kfree(name); 1227 - break; 1228 - } 1229 - 1230 - ret = strscpy(noext[noext_cnt], name); 1231 - if (ret < 0) { 1232 - kfree(name); 1233 - return ret; 1234 - } 1235 - F2FS_OPTION(sbi).nocompress_ext_cnt++; 1236 - kfree(name); 1237 - break; 1238 - case Opt_compress_chksum: 1239 - if (!f2fs_sb_has_compression(sbi)) { 1240 - f2fs_info(sbi, "Image doesn't support compression"); 1241 - break; 1242 - } 1243 - F2FS_OPTION(sbi).compress_chksum = true; 1244 - break; 1245 - case Opt_compress_mode: 1246 - if (!f2fs_sb_has_compression(sbi)) { 1247 - f2fs_info(sbi, "Image doesn't support compression"); 1248 - break; 1249 - } 1250 - name = match_strdup(&args[0]); 1251 - if (!name) 1252 - return -ENOMEM; 1253 - if (!strcmp(name, "fs")) { 1254 - F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS; 1255 - } else if (!strcmp(name, "user")) { 1256 - F2FS_OPTION(sbi).compress_mode = COMPR_MODE_USER; 1257 - } else { 1258 - kfree(name); 1259 - return -EINVAL; 1260 - } 1261 - kfree(name); 1262 - break; 1263 - case Opt_compress_cache: 1264 - if (!f2fs_sb_has_compression(sbi)) { 1265 - f2fs_info(sbi, "Image doesn't support compression"); 1266 - break; 1267 - } 1268 - set_opt(sbi, COMPRESS_CACHE); 1269 - break; 1270 - #else 1271 - case Opt_compress_algorithm: 1272 - case Opt_compress_log_size: 1273 - case Opt_compress_extension: 1274 - case Opt_nocompress_extension: 1275 - case Opt_compress_chksum: 1276 - case Opt_compress_mode: 1277 - case Opt_compress_cache: 1278 - f2fs_info(sbi, "compression options not supported"); 1279 - break; 1280 - #endif 1281 - case Opt_atgc: 1282 - set_opt(sbi, ATGC); 1283 - break; 1284 - case Opt_gc_merge: 1285 - set_opt(sbi, GC_MERGE); 1286 - break; 1287 - case Opt_nogc_merge: 1288 - clear_opt(sbi, GC_MERGE); 1289 - break; 1290 - case Opt_discard_unit: 1291 - name = match_strdup(&args[0]); 1292 - if (!name) 1293 - return -ENOMEM; 1294 - if (!strcmp(name, "block")) { 1295 - F2FS_OPTION(sbi).discard_unit = 1296 - DISCARD_UNIT_BLOCK; 1297 - } else if (!strcmp(name, "segment")) { 1298 - F2FS_OPTION(sbi).discard_unit = 1299 - DISCARD_UNIT_SEGMENT; 1300 - } else if (!strcmp(name, "section")) { 1301 - F2FS_OPTION(sbi).discard_unit = 1302 - DISCARD_UNIT_SECTION; 1303 - } else { 1304 - kfree(name); 1305 - return -EINVAL; 1306 - } 1307 - kfree(name); 1308 - break; 1309 - case Opt_memory_mode: 1310 - name = match_strdup(&args[0]); 1311 - if (!name) 1312 - return -ENOMEM; 1313 - if (!strcmp(name, "normal")) { 1314 - F2FS_OPTION(sbi).memory_mode = 1315 - MEMORY_MODE_NORMAL; 1316 - } else if (!strcmp(name, "low")) { 1317 - F2FS_OPTION(sbi).memory_mode = 1318 - MEMORY_MODE_LOW; 1319 - } else { 1320 - kfree(name); 1321 - return -EINVAL; 1322 - } 1323 - kfree(name); 1324 - break; 1325 - case Opt_age_extent_cache: 1326 - set_opt(sbi, AGE_EXTENT_CACHE); 1327 - break; 1328 - case Opt_errors: 1329 - name = match_strdup(&args[0]); 1330 - if (!name) 1331 - return -ENOMEM; 1332 - if (!strcmp(name, "remount-ro")) { 1333 - F2FS_OPTION(sbi).errors = 1334 - MOUNT_ERRORS_READONLY; 1335 - } else if (!strcmp(name, "continue")) { 1336 - F2FS_OPTION(sbi).errors = 1337 - MOUNT_ERRORS_CONTINUE; 1338 - } else if (!strcmp(name, "panic")) { 1339 - F2FS_OPTION(sbi).errors = 1340 - MOUNT_ERRORS_PANIC; 1341 - } else { 1342 - kfree(name); 1343 - return -EINVAL; 1344 - } 1345 - kfree(name); 1346 - break; 1347 - case Opt_nat_bits: 1348 - set_opt(sbi, NAT_BITS); 961 + ctx_clear_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); 1349 962 break; 1350 963 default: 1351 - f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value", 1352 - p); 1353 964 return -EINVAL; 1354 965 } 966 + break; 967 + case Opt_checkpoint_merge: 968 + if (result.negated) 969 + ctx_clear_opt(ctx, F2FS_MOUNT_MERGE_CHECKPOINT); 970 + else 971 + ctx_set_opt(ctx, F2FS_MOUNT_MERGE_CHECKPOINT); 972 + break; 973 + #ifdef CONFIG_F2FS_FS_COMPRESSION 974 + case Opt_compress_algorithm: 975 + name = param->string; 976 + if (!strcmp(name, "lzo")) { 977 + #ifdef CONFIG_F2FS_FS_LZO 978 + F2FS_CTX_INFO(ctx).compress_level = 0; 979 + F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_LZO; 980 + ctx->spec_mask |= F2FS_SPEC_compress_level; 981 + ctx->spec_mask |= F2FS_SPEC_compress_algorithm; 982 + #else 983 + f2fs_info(NULL, "kernel doesn't support lzo compression"); 984 + #endif 985 + } else if (!strncmp(name, "lz4", 3)) { 986 + #ifdef CONFIG_F2FS_FS_LZ4 987 + ret = f2fs_set_lz4hc_level(ctx, name); 988 + if (ret) 989 + return -EINVAL; 990 + F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_LZ4; 991 + ctx->spec_mask |= F2FS_SPEC_compress_algorithm; 992 + #else 993 + f2fs_info(NULL, "kernel doesn't support lz4 compression"); 994 + #endif 995 + } else if (!strncmp(name, "zstd", 4)) { 996 + #ifdef CONFIG_F2FS_FS_ZSTD 997 + ret = f2fs_set_zstd_level(ctx, name); 998 + if (ret) 999 + return -EINVAL; 1000 + F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_ZSTD; 1001 + ctx->spec_mask |= F2FS_SPEC_compress_algorithm; 1002 + #else 1003 + f2fs_info(NULL, "kernel doesn't support zstd compression"); 1004 + #endif 1005 + } else if (!strcmp(name, "lzo-rle")) { 1006 + #ifdef CONFIG_F2FS_FS_LZORLE 1007 + F2FS_CTX_INFO(ctx).compress_level = 0; 1008 + F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_LZORLE; 1009 + ctx->spec_mask |= F2FS_SPEC_compress_level; 1010 + ctx->spec_mask |= F2FS_SPEC_compress_algorithm; 1011 + #else 1012 + f2fs_info(NULL, "kernel doesn't support lzorle compression"); 1013 + #endif 1014 + } else 1015 + return -EINVAL; 1016 + break; 1017 + case Opt_compress_log_size: 1018 + if (result.uint_32 < MIN_COMPRESS_LOG_SIZE || 1019 + result.uint_32 > MAX_COMPRESS_LOG_SIZE) { 1020 + f2fs_err(NULL, 1021 + "Compress cluster log size is out of range"); 1022 + return -EINVAL; 1023 + } 1024 + F2FS_CTX_INFO(ctx).compress_log_size = result.uint_32; 1025 + ctx->spec_mask |= F2FS_SPEC_compress_log_size; 1026 + break; 1027 + case Opt_compress_extension: 1028 + name = param->string; 1029 + ext = F2FS_CTX_INFO(ctx).extensions; 1030 + ext_cnt = F2FS_CTX_INFO(ctx).compress_ext_cnt; 1031 + 1032 + if (strlen(name) >= F2FS_EXTENSION_LEN || 1033 + ext_cnt >= COMPRESS_EXT_NUM) { 1034 + f2fs_err(NULL, "invalid extension length/number"); 1035 + return -EINVAL; 1036 + } 1037 + 1038 + if (is_compress_extension_exist(&ctx->info, name, true)) 1039 + break; 1040 + 1041 + ret = strscpy(ext[ext_cnt], name, F2FS_EXTENSION_LEN); 1042 + if (ret < 0) 1043 + return ret; 1044 + F2FS_CTX_INFO(ctx).compress_ext_cnt++; 1045 + ctx->spec_mask |= F2FS_SPEC_compress_extension; 1046 + break; 1047 + case Opt_nocompress_extension: 1048 + name = param->string; 1049 + noext = F2FS_CTX_INFO(ctx).noextensions; 1050 + noext_cnt = F2FS_CTX_INFO(ctx).nocompress_ext_cnt; 1051 + 1052 + if (strlen(name) >= F2FS_EXTENSION_LEN || 1053 + noext_cnt >= COMPRESS_EXT_NUM) { 1054 + f2fs_err(NULL, "invalid extension length/number"); 1055 + return -EINVAL; 1056 + } 1057 + 1058 + if (is_compress_extension_exist(&ctx->info, name, false)) 1059 + break; 1060 + 1061 + ret = strscpy(noext[noext_cnt], name, F2FS_EXTENSION_LEN); 1062 + if (ret < 0) 1063 + return ret; 1064 + F2FS_CTX_INFO(ctx).nocompress_ext_cnt++; 1065 + ctx->spec_mask |= F2FS_SPEC_nocompress_extension; 1066 + break; 1067 + case Opt_compress_chksum: 1068 + F2FS_CTX_INFO(ctx).compress_chksum = true; 1069 + ctx->spec_mask |= F2FS_SPEC_compress_chksum; 1070 + break; 1071 + case Opt_compress_mode: 1072 + F2FS_CTX_INFO(ctx).compress_mode = result.uint_32; 1073 + ctx->spec_mask |= F2FS_SPEC_compress_mode; 1074 + break; 1075 + case Opt_compress_cache: 1076 + ctx_set_opt(ctx, F2FS_MOUNT_COMPRESS_CACHE); 1077 + break; 1078 + #else 1079 + case Opt_compress_algorithm: 1080 + case Opt_compress_log_size: 1081 + case Opt_compress_extension: 1082 + case Opt_nocompress_extension: 1083 + case Opt_compress_chksum: 1084 + case Opt_compress_mode: 1085 + case Opt_compress_cache: 1086 + f2fs_info(NULL, "compression options not supported"); 1087 + break; 1088 + #endif 1089 + case Opt_atgc: 1090 + ctx_set_opt(ctx, F2FS_MOUNT_ATGC); 1091 + break; 1092 + case Opt_gc_merge: 1093 + if (result.negated) 1094 + ctx_clear_opt(ctx, F2FS_MOUNT_GC_MERGE); 1095 + else 1096 + ctx_set_opt(ctx, F2FS_MOUNT_GC_MERGE); 1097 + break; 1098 + case Opt_discard_unit: 1099 + F2FS_CTX_INFO(ctx).discard_unit = result.uint_32; 1100 + ctx->spec_mask |= F2FS_SPEC_discard_unit; 1101 + break; 1102 + case Opt_memory_mode: 1103 + F2FS_CTX_INFO(ctx).memory_mode = result.uint_32; 1104 + ctx->spec_mask |= F2FS_SPEC_memory_mode; 1105 + break; 1106 + case Opt_age_extent_cache: 1107 + ctx_set_opt(ctx, F2FS_MOUNT_AGE_EXTENT_CACHE); 1108 + break; 1109 + case Opt_errors: 1110 + F2FS_CTX_INFO(ctx).errors = result.uint_32; 1111 + ctx->spec_mask |= F2FS_SPEC_errors; 1112 + break; 1113 + case Opt_nat_bits: 1114 + ctx_set_opt(ctx, F2FS_MOUNT_NAT_BITS); 1115 + break; 1355 1116 } 1356 1117 return 0; 1357 1118 } 1358 1119 1359 - static int f2fs_default_check(struct f2fs_sb_info *sbi) 1120 + /* 1121 + * Check quota settings consistency. 1122 + */ 1123 + static int f2fs_check_quota_consistency(struct fs_context *fc, 1124 + struct super_block *sb) 1360 1125 { 1361 - #ifdef CONFIG_QUOTA 1362 - if (f2fs_check_quota_options(sbi)) 1126 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1127 + #ifdef CONFIG_QUOTA 1128 + struct f2fs_fs_context *ctx = fc->fs_private; 1129 + bool quota_feature = f2fs_sb_has_quota_ino(sbi); 1130 + bool quota_turnon = sb_any_quota_loaded(sb); 1131 + char *old_qname, *new_qname; 1132 + bool usr_qf_name, grp_qf_name, prj_qf_name, usrquota, grpquota, prjquota; 1133 + int i; 1134 + 1135 + /* 1136 + * We do the test below only for project quotas. 'usrquota' and 1137 + * 'grpquota' mount options are allowed even without quota feature 1138 + * to support legacy quotas in quota files. 1139 + */ 1140 + if (ctx_test_opt(ctx, F2FS_MOUNT_PRJQUOTA) && 1141 + !f2fs_sb_has_project_quota(sbi)) { 1142 + f2fs_err(sbi, "Project quota feature not enabled. Cannot enable project quota enforcement."); 1363 1143 return -EINVAL; 1144 + } 1145 + 1146 + if (ctx->qname_mask) { 1147 + for (i = 0; i < MAXQUOTAS; i++) { 1148 + if (!(ctx->qname_mask & (1 << i))) 1149 + continue; 1150 + 1151 + old_qname = F2FS_OPTION(sbi).s_qf_names[i]; 1152 + new_qname = F2FS_CTX_INFO(ctx).s_qf_names[i]; 1153 + if (quota_turnon && 1154 + !!old_qname != !!new_qname) 1155 + goto err_jquota_change; 1156 + 1157 + if (old_qname) { 1158 + if (strcmp(old_qname, new_qname) == 0) { 1159 + ctx->qname_mask &= ~(1 << i); 1160 + continue; 1161 + } 1162 + goto err_jquota_specified; 1163 + } 1164 + 1165 + if (quota_feature) { 1166 + f2fs_info(sbi, "QUOTA feature is enabled, so ignore qf_name"); 1167 + ctx->qname_mask &= ~(1 << i); 1168 + kfree(F2FS_CTX_INFO(ctx).s_qf_names[i]); 1169 + F2FS_CTX_INFO(ctx).s_qf_names[i] = NULL; 1170 + } 1171 + } 1172 + } 1173 + 1174 + /* Make sure we don't mix old and new quota format */ 1175 + usr_qf_name = F2FS_OPTION(sbi).s_qf_names[USRQUOTA] || 1176 + F2FS_CTX_INFO(ctx).s_qf_names[USRQUOTA]; 1177 + grp_qf_name = F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] || 1178 + F2FS_CTX_INFO(ctx).s_qf_names[GRPQUOTA]; 1179 + prj_qf_name = F2FS_OPTION(sbi).s_qf_names[PRJQUOTA] || 1180 + F2FS_CTX_INFO(ctx).s_qf_names[PRJQUOTA]; 1181 + usrquota = test_opt(sbi, USRQUOTA) || 1182 + ctx_test_opt(ctx, F2FS_MOUNT_USRQUOTA); 1183 + grpquota = test_opt(sbi, GRPQUOTA) || 1184 + ctx_test_opt(ctx, F2FS_MOUNT_GRPQUOTA); 1185 + prjquota = test_opt(sbi, PRJQUOTA) || 1186 + ctx_test_opt(ctx, F2FS_MOUNT_PRJQUOTA); 1187 + 1188 + if (usr_qf_name) { 1189 + ctx_clear_opt(ctx, F2FS_MOUNT_USRQUOTA); 1190 + usrquota = false; 1191 + } 1192 + if (grp_qf_name) { 1193 + ctx_clear_opt(ctx, F2FS_MOUNT_GRPQUOTA); 1194 + grpquota = false; 1195 + } 1196 + if (prj_qf_name) { 1197 + ctx_clear_opt(ctx, F2FS_MOUNT_PRJQUOTA); 1198 + prjquota = false; 1199 + } 1200 + if (usr_qf_name || grp_qf_name || prj_qf_name) { 1201 + if (grpquota || usrquota || prjquota) { 1202 + f2fs_err(sbi, "old and new quota format mixing"); 1203 + return -EINVAL; 1204 + } 1205 + if (!(ctx->spec_mask & F2FS_SPEC_jqfmt || 1206 + F2FS_OPTION(sbi).s_jquota_fmt)) { 1207 + f2fs_err(sbi, "journaled quota format not specified"); 1208 + return -EINVAL; 1209 + } 1210 + } 1211 + return 0; 1212 + 1213 + err_jquota_change: 1214 + f2fs_err(sbi, "Cannot change journaled quota options when quota turned on"); 1215 + return -EINVAL; 1216 + err_jquota_specified: 1217 + f2fs_err(sbi, "%s quota file already specified", 1218 + QTYPE2NAME(i)); 1219 + return -EINVAL; 1220 + 1364 1221 #else 1365 - if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sbi->sb)) { 1222 + if (f2fs_readonly(sbi->sb)) 1223 + return 0; 1224 + if (f2fs_sb_has_quota_ino(sbi)) { 1366 1225 f2fs_info(sbi, "Filesystem with quota feature cannot be mounted RDWR without CONFIG_QUOTA"); 1367 1226 return -EINVAL; 1368 1227 } 1369 - if (f2fs_sb_has_project_quota(sbi) && !f2fs_readonly(sbi->sb)) { 1228 + if (f2fs_sb_has_project_quota(sbi)) { 1370 1229 f2fs_err(sbi, "Filesystem with project quota feature cannot be mounted RDWR without CONFIG_QUOTA"); 1371 1230 return -EINVAL; 1372 1231 } 1232 + 1233 + return 0; 1373 1234 #endif 1235 + } 1236 + 1237 + static int f2fs_check_test_dummy_encryption(struct fs_context *fc, 1238 + struct super_block *sb) 1239 + { 1240 + struct f2fs_fs_context *ctx = fc->fs_private; 1241 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1242 + 1243 + if (!fscrypt_is_dummy_policy_set(&F2FS_CTX_INFO(ctx).dummy_enc_policy)) 1244 + return 0; 1245 + 1246 + if (!f2fs_sb_has_encrypt(sbi)) { 1247 + f2fs_err(sbi, "Encrypt feature is off"); 1248 + return -EINVAL; 1249 + } 1250 + 1251 + /* 1252 + * This mount option is just for testing, and it's not worthwhile to 1253 + * implement the extra complexity (e.g. RCU protection) that would be 1254 + * needed to allow it to be set or changed during remount. We do allow 1255 + * it to be specified during remount, but only if there is no change. 1256 + */ 1257 + if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) { 1258 + if (fscrypt_dummy_policies_equal(&F2FS_OPTION(sbi).dummy_enc_policy, 1259 + &F2FS_CTX_INFO(ctx).dummy_enc_policy)) 1260 + return 0; 1261 + f2fs_warn(sbi, "Can't set or change test_dummy_encryption on remount"); 1262 + return -EINVAL; 1263 + } 1264 + return 0; 1265 + } 1266 + 1267 + static inline bool test_compression_spec(unsigned int mask) 1268 + { 1269 + return mask & (F2FS_SPEC_compress_algorithm 1270 + | F2FS_SPEC_compress_log_size 1271 + | F2FS_SPEC_compress_extension 1272 + | F2FS_SPEC_nocompress_extension 1273 + | F2FS_SPEC_compress_chksum 1274 + | F2FS_SPEC_compress_mode); 1275 + } 1276 + 1277 + static inline void clear_compression_spec(struct f2fs_fs_context *ctx) 1278 + { 1279 + ctx->spec_mask &= ~(F2FS_SPEC_compress_algorithm 1280 + | F2FS_SPEC_compress_log_size 1281 + | F2FS_SPEC_compress_extension 1282 + | F2FS_SPEC_nocompress_extension 1283 + | F2FS_SPEC_compress_chksum 1284 + | F2FS_SPEC_compress_mode); 1285 + } 1286 + 1287 + static int f2fs_check_compression(struct fs_context *fc, 1288 + struct super_block *sb) 1289 + { 1290 + #ifdef CONFIG_F2FS_FS_COMPRESSION 1291 + struct f2fs_fs_context *ctx = fc->fs_private; 1292 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1293 + int i, cnt; 1294 + 1295 + if (!f2fs_sb_has_compression(sbi)) { 1296 + if (test_compression_spec(ctx->spec_mask) || 1297 + ctx_test_opt(ctx, F2FS_MOUNT_COMPRESS_CACHE)) 1298 + f2fs_info(sbi, "Image doesn't support compression"); 1299 + clear_compression_spec(ctx); 1300 + ctx->opt_mask &= ~F2FS_MOUNT_COMPRESS_CACHE; 1301 + return 0; 1302 + } 1303 + if (ctx->spec_mask & F2FS_SPEC_compress_extension) { 1304 + cnt = F2FS_CTX_INFO(ctx).compress_ext_cnt; 1305 + for (i = 0; i < F2FS_CTX_INFO(ctx).compress_ext_cnt; i++) { 1306 + if (is_compress_extension_exist(&F2FS_OPTION(sbi), 1307 + F2FS_CTX_INFO(ctx).extensions[i], true)) { 1308 + F2FS_CTX_INFO(ctx).extensions[i][0] = '\0'; 1309 + cnt--; 1310 + } 1311 + } 1312 + if (F2FS_OPTION(sbi).compress_ext_cnt + cnt > COMPRESS_EXT_NUM) { 1313 + f2fs_err(sbi, "invalid extension length/number"); 1314 + return -EINVAL; 1315 + } 1316 + } 1317 + if (ctx->spec_mask & F2FS_SPEC_nocompress_extension) { 1318 + cnt = F2FS_CTX_INFO(ctx).nocompress_ext_cnt; 1319 + for (i = 0; i < F2FS_CTX_INFO(ctx).nocompress_ext_cnt; i++) { 1320 + if (is_compress_extension_exist(&F2FS_OPTION(sbi), 1321 + F2FS_CTX_INFO(ctx).noextensions[i], false)) { 1322 + F2FS_CTX_INFO(ctx).noextensions[i][0] = '\0'; 1323 + cnt--; 1324 + } 1325 + } 1326 + if (F2FS_OPTION(sbi).nocompress_ext_cnt + cnt > COMPRESS_EXT_NUM) { 1327 + f2fs_err(sbi, "invalid noextension length/number"); 1328 + return -EINVAL; 1329 + } 1330 + } 1331 + 1332 + if (f2fs_test_compress_extension(F2FS_CTX_INFO(ctx).noextensions, 1333 + F2FS_CTX_INFO(ctx).nocompress_ext_cnt, 1334 + F2FS_CTX_INFO(ctx).extensions, 1335 + F2FS_CTX_INFO(ctx).compress_ext_cnt)) { 1336 + f2fs_err(sbi, "new noextensions conflicts with new extensions"); 1337 + return -EINVAL; 1338 + } 1339 + if (f2fs_test_compress_extension(F2FS_CTX_INFO(ctx).noextensions, 1340 + F2FS_CTX_INFO(ctx).nocompress_ext_cnt, 1341 + F2FS_OPTION(sbi).extensions, 1342 + F2FS_OPTION(sbi).compress_ext_cnt)) { 1343 + f2fs_err(sbi, "new noextensions conflicts with old extensions"); 1344 + return -EINVAL; 1345 + } 1346 + if (f2fs_test_compress_extension(F2FS_OPTION(sbi).noextensions, 1347 + F2FS_OPTION(sbi).nocompress_ext_cnt, 1348 + F2FS_CTX_INFO(ctx).extensions, 1349 + F2FS_CTX_INFO(ctx).compress_ext_cnt)) { 1350 + f2fs_err(sbi, "new extensions conflicts with old noextensions"); 1351 + return -EINVAL; 1352 + } 1353 + #endif 1354 + return 0; 1355 + } 1356 + 1357 + static int f2fs_check_opt_consistency(struct fs_context *fc, 1358 + struct super_block *sb) 1359 + { 1360 + struct f2fs_fs_context *ctx = fc->fs_private; 1361 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1362 + int err; 1363 + 1364 + if (ctx_test_opt(ctx, F2FS_MOUNT_NORECOVERY) && !f2fs_readonly(sb)) 1365 + return -EINVAL; 1366 + 1367 + if (f2fs_hw_should_discard(sbi) && 1368 + (ctx->opt_mask & F2FS_MOUNT_DISCARD) && 1369 + !ctx_test_opt(ctx, F2FS_MOUNT_DISCARD)) { 1370 + f2fs_warn(sbi, "discard is required for zoned block devices"); 1371 + return -EINVAL; 1372 + } 1373 + 1374 + if (!f2fs_hw_support_discard(sbi) && 1375 + (ctx->opt_mask & F2FS_MOUNT_DISCARD) && 1376 + ctx_test_opt(ctx, F2FS_MOUNT_DISCARD)) { 1377 + f2fs_warn(sbi, "device does not support discard"); 1378 + ctx_clear_opt(ctx, F2FS_MOUNT_DISCARD); 1379 + ctx->opt_mask &= ~F2FS_MOUNT_DISCARD; 1380 + } 1381 + 1382 + if (f2fs_sb_has_device_alias(sbi) && 1383 + (ctx->opt_mask & F2FS_MOUNT_READ_EXTENT_CACHE) && 1384 + !ctx_test_opt(ctx, F2FS_MOUNT_READ_EXTENT_CACHE)) { 1385 + f2fs_err(sbi, "device aliasing requires extent cache"); 1386 + return -EINVAL; 1387 + } 1388 + 1389 + if (test_opt(sbi, RESERVE_ROOT) && 1390 + (ctx->opt_mask & F2FS_MOUNT_RESERVE_ROOT) && 1391 + ctx_test_opt(ctx, F2FS_MOUNT_RESERVE_ROOT)) { 1392 + f2fs_info(sbi, "Preserve previous reserve_root=%u", 1393 + F2FS_OPTION(sbi).root_reserved_blocks); 1394 + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); 1395 + ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_ROOT; 1396 + } 1397 + 1398 + err = f2fs_check_test_dummy_encryption(fc, sb); 1399 + if (err) 1400 + return err; 1401 + 1402 + err = f2fs_check_compression(fc, sb); 1403 + if (err) 1404 + return err; 1405 + 1406 + err = f2fs_check_quota_consistency(fc, sb); 1407 + if (err) 1408 + return err; 1374 1409 1375 1410 if (!IS_ENABLED(CONFIG_UNICODE) && f2fs_sb_has_casefold(sbi)) { 1376 1411 f2fs_err(sbi, ··· 1449 1354 * devices, but mandatory for host-managed zoned block devices. 1450 1355 */ 1451 1356 if (f2fs_sb_has_blkzoned(sbi)) { 1357 + if (F2FS_CTX_INFO(ctx).bggc_mode == BGGC_MODE_OFF) { 1358 + f2fs_warn(sbi, "zoned devices need bggc"); 1359 + return -EINVAL; 1360 + } 1452 1361 #ifdef CONFIG_BLK_DEV_ZONED 1453 - if (F2FS_OPTION(sbi).discard_unit != 1454 - DISCARD_UNIT_SECTION) { 1362 + if ((ctx->spec_mask & F2FS_SPEC_discard_unit) && 1363 + F2FS_CTX_INFO(ctx).discard_unit != DISCARD_UNIT_SECTION) { 1455 1364 f2fs_info(sbi, "Zoned block device doesn't need small discard, set discard_unit=section by default"); 1456 - F2FS_OPTION(sbi).discard_unit = 1457 - DISCARD_UNIT_SECTION; 1365 + F2FS_CTX_INFO(ctx).discard_unit = DISCARD_UNIT_SECTION; 1458 1366 } 1459 1367 1460 - if (F2FS_OPTION(sbi).fs_mode != FS_MODE_LFS) { 1368 + if ((ctx->spec_mask & F2FS_SPEC_mode) && 1369 + F2FS_CTX_INFO(ctx).fs_mode != FS_MODE_LFS) { 1461 1370 f2fs_info(sbi, "Only lfs mode is allowed with zoned block device feature"); 1462 1371 return -EINVAL; 1463 1372 } ··· 1471 1372 #endif 1472 1373 } 1473 1374 1474 - #ifdef CONFIG_F2FS_FS_COMPRESSION 1475 - if (f2fs_test_compress_extension(sbi)) { 1476 - f2fs_err(sbi, "invalid compress or nocompress extension"); 1477 - return -EINVAL; 1478 - } 1479 - #endif 1480 - 1481 - if (test_opt(sbi, INLINE_XATTR_SIZE)) { 1482 - int min_size, max_size; 1483 - 1375 + if (ctx_test_opt(ctx, F2FS_MOUNT_INLINE_XATTR_SIZE)) { 1484 1376 if (!f2fs_sb_has_extra_attr(sbi) || 1485 1377 !f2fs_sb_has_flexible_inline_xattr(sbi)) { 1486 1378 f2fs_err(sbi, "extra_attr or flexible_inline_xattr feature is off"); 1487 1379 return -EINVAL; 1488 1380 } 1489 - if (!test_opt(sbi, INLINE_XATTR)) { 1381 + if (!ctx_test_opt(ctx, F2FS_MOUNT_INLINE_XATTR) && !test_opt(sbi, INLINE_XATTR)) { 1490 1382 f2fs_err(sbi, "inline_xattr_size option should be set with inline_xattr option"); 1491 - return -EINVAL; 1492 - } 1493 - 1494 - min_size = MIN_INLINE_XATTR_SIZE; 1495 - max_size = MAX_INLINE_XATTR_SIZE; 1496 - 1497 - if (F2FS_OPTION(sbi).inline_xattr_size < min_size || 1498 - F2FS_OPTION(sbi).inline_xattr_size > max_size) { 1499 - f2fs_err(sbi, "inline xattr size is out of range: %d ~ %d", 1500 - min_size, max_size); 1501 1383 return -EINVAL; 1502 1384 } 1503 1385 } 1504 1386 1505 - if (test_opt(sbi, ATGC) && f2fs_lfs_mode(sbi)) { 1387 + if (ctx_test_opt(ctx, F2FS_MOUNT_ATGC) && 1388 + F2FS_CTX_INFO(ctx).fs_mode == FS_MODE_LFS) { 1506 1389 f2fs_err(sbi, "LFS is not compatible with ATGC"); 1507 1390 return -EINVAL; 1508 1391 } 1509 1392 1510 - if (f2fs_is_readonly(sbi) && test_opt(sbi, FLUSH_MERGE)) { 1393 + if (f2fs_is_readonly(sbi) && ctx_test_opt(ctx, F2FS_MOUNT_FLUSH_MERGE)) { 1511 1394 f2fs_err(sbi, "FLUSH_MERGE not compatible with readonly mode"); 1512 1395 return -EINVAL; 1513 1396 } ··· 1498 1417 f2fs_err(sbi, "Allow to mount readonly mode only"); 1499 1418 return -EROFS; 1500 1419 } 1420 + return 0; 1421 + } 1501 1422 1502 - if (test_opt(sbi, NORECOVERY) && !f2fs_readonly(sbi->sb)) { 1503 - f2fs_err(sbi, "norecovery requires readonly mount"); 1423 + static void f2fs_apply_quota_options(struct fs_context *fc, 1424 + struct super_block *sb) 1425 + { 1426 + #ifdef CONFIG_QUOTA 1427 + struct f2fs_fs_context *ctx = fc->fs_private; 1428 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1429 + bool quota_feature = f2fs_sb_has_quota_ino(sbi); 1430 + char *qname; 1431 + int i; 1432 + 1433 + if (quota_feature) 1434 + return; 1435 + 1436 + for (i = 0; i < MAXQUOTAS; i++) { 1437 + if (!(ctx->qname_mask & (1 << i))) 1438 + continue; 1439 + 1440 + qname = F2FS_CTX_INFO(ctx).s_qf_names[i]; 1441 + if (qname) { 1442 + qname = kstrdup(F2FS_CTX_INFO(ctx).s_qf_names[i], 1443 + GFP_KERNEL | __GFP_NOFAIL); 1444 + set_opt(sbi, QUOTA); 1445 + } 1446 + F2FS_OPTION(sbi).s_qf_names[i] = qname; 1447 + } 1448 + 1449 + if (ctx->spec_mask & F2FS_SPEC_jqfmt) 1450 + F2FS_OPTION(sbi).s_jquota_fmt = F2FS_CTX_INFO(ctx).s_jquota_fmt; 1451 + 1452 + if (quota_feature && F2FS_OPTION(sbi).s_jquota_fmt) { 1453 + f2fs_info(sbi, "QUOTA feature is enabled, so ignore jquota_fmt"); 1454 + F2FS_OPTION(sbi).s_jquota_fmt = 0; 1455 + } 1456 + #endif 1457 + } 1458 + 1459 + static void f2fs_apply_test_dummy_encryption(struct fs_context *fc, 1460 + struct super_block *sb) 1461 + { 1462 + struct f2fs_fs_context *ctx = fc->fs_private; 1463 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1464 + 1465 + if (!fscrypt_is_dummy_policy_set(&F2FS_CTX_INFO(ctx).dummy_enc_policy) || 1466 + /* if already set, it was already verified to be the same */ 1467 + fscrypt_is_dummy_policy_set(&F2FS_OPTION(sbi).dummy_enc_policy)) 1468 + return; 1469 + swap(F2FS_OPTION(sbi).dummy_enc_policy, F2FS_CTX_INFO(ctx).dummy_enc_policy); 1470 + f2fs_warn(sbi, "Test dummy encryption mode enabled"); 1471 + } 1472 + 1473 + static void f2fs_apply_compression(struct fs_context *fc, 1474 + struct super_block *sb) 1475 + { 1476 + #ifdef CONFIG_F2FS_FS_COMPRESSION 1477 + struct f2fs_fs_context *ctx = fc->fs_private; 1478 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1479 + unsigned char (*ctx_ext)[F2FS_EXTENSION_LEN]; 1480 + unsigned char (*sbi_ext)[F2FS_EXTENSION_LEN]; 1481 + int ctx_cnt, sbi_cnt, i; 1482 + 1483 + if (ctx->spec_mask & F2FS_SPEC_compress_level) 1484 + F2FS_OPTION(sbi).compress_level = 1485 + F2FS_CTX_INFO(ctx).compress_level; 1486 + if (ctx->spec_mask & F2FS_SPEC_compress_algorithm) 1487 + F2FS_OPTION(sbi).compress_algorithm = 1488 + F2FS_CTX_INFO(ctx).compress_algorithm; 1489 + if (ctx->spec_mask & F2FS_SPEC_compress_log_size) 1490 + F2FS_OPTION(sbi).compress_log_size = 1491 + F2FS_CTX_INFO(ctx).compress_log_size; 1492 + if (ctx->spec_mask & F2FS_SPEC_compress_chksum) 1493 + F2FS_OPTION(sbi).compress_chksum = 1494 + F2FS_CTX_INFO(ctx).compress_chksum; 1495 + if (ctx->spec_mask & F2FS_SPEC_compress_mode) 1496 + F2FS_OPTION(sbi).compress_mode = 1497 + F2FS_CTX_INFO(ctx).compress_mode; 1498 + if (ctx->spec_mask & F2FS_SPEC_compress_extension) { 1499 + ctx_ext = F2FS_CTX_INFO(ctx).extensions; 1500 + ctx_cnt = F2FS_CTX_INFO(ctx).compress_ext_cnt; 1501 + sbi_ext = F2FS_OPTION(sbi).extensions; 1502 + sbi_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 1503 + for (i = 0; i < ctx_cnt; i++) { 1504 + if (strlen(ctx_ext[i]) == 0) 1505 + continue; 1506 + strscpy(sbi_ext[sbi_cnt], ctx_ext[i]); 1507 + sbi_cnt++; 1508 + } 1509 + F2FS_OPTION(sbi).compress_ext_cnt = sbi_cnt; 1510 + } 1511 + if (ctx->spec_mask & F2FS_SPEC_nocompress_extension) { 1512 + ctx_ext = F2FS_CTX_INFO(ctx).noextensions; 1513 + ctx_cnt = F2FS_CTX_INFO(ctx).nocompress_ext_cnt; 1514 + sbi_ext = F2FS_OPTION(sbi).noextensions; 1515 + sbi_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 1516 + for (i = 0; i < ctx_cnt; i++) { 1517 + if (strlen(ctx_ext[i]) == 0) 1518 + continue; 1519 + strscpy(sbi_ext[sbi_cnt], ctx_ext[i]); 1520 + sbi_cnt++; 1521 + } 1522 + F2FS_OPTION(sbi).nocompress_ext_cnt = sbi_cnt; 1523 + } 1524 + #endif 1525 + } 1526 + 1527 + static void f2fs_apply_options(struct fs_context *fc, struct super_block *sb) 1528 + { 1529 + struct f2fs_fs_context *ctx = fc->fs_private; 1530 + struct f2fs_sb_info *sbi = F2FS_SB(sb); 1531 + 1532 + F2FS_OPTION(sbi).opt &= ~ctx->opt_mask; 1533 + F2FS_OPTION(sbi).opt |= F2FS_CTX_INFO(ctx).opt; 1534 + 1535 + if (ctx->spec_mask & F2FS_SPEC_background_gc) 1536 + F2FS_OPTION(sbi).bggc_mode = F2FS_CTX_INFO(ctx).bggc_mode; 1537 + if (ctx->spec_mask & F2FS_SPEC_inline_xattr_size) 1538 + F2FS_OPTION(sbi).inline_xattr_size = 1539 + F2FS_CTX_INFO(ctx).inline_xattr_size; 1540 + if (ctx->spec_mask & F2FS_SPEC_active_logs) 1541 + F2FS_OPTION(sbi).active_logs = F2FS_CTX_INFO(ctx).active_logs; 1542 + if (ctx->spec_mask & F2FS_SPEC_reserve_root) 1543 + F2FS_OPTION(sbi).root_reserved_blocks = 1544 + F2FS_CTX_INFO(ctx).root_reserved_blocks; 1545 + if (ctx->spec_mask & F2FS_SPEC_resgid) 1546 + F2FS_OPTION(sbi).s_resgid = F2FS_CTX_INFO(ctx).s_resgid; 1547 + if (ctx->spec_mask & F2FS_SPEC_resuid) 1548 + F2FS_OPTION(sbi).s_resuid = F2FS_CTX_INFO(ctx).s_resuid; 1549 + if (ctx->spec_mask & F2FS_SPEC_mode) 1550 + F2FS_OPTION(sbi).fs_mode = F2FS_CTX_INFO(ctx).fs_mode; 1551 + #ifdef CONFIG_F2FS_FAULT_INJECTION 1552 + if (ctx->spec_mask & F2FS_SPEC_fault_injection) 1553 + (void)f2fs_build_fault_attr(sbi, 1554 + F2FS_CTX_INFO(ctx).fault_info.inject_rate, 0, FAULT_RATE); 1555 + if (ctx->spec_mask & F2FS_SPEC_fault_type) 1556 + (void)f2fs_build_fault_attr(sbi, 0, 1557 + F2FS_CTX_INFO(ctx).fault_info.inject_type, FAULT_TYPE); 1558 + #endif 1559 + if (ctx->spec_mask & F2FS_SPEC_alloc_mode) 1560 + F2FS_OPTION(sbi).alloc_mode = F2FS_CTX_INFO(ctx).alloc_mode; 1561 + if (ctx->spec_mask & F2FS_SPEC_fsync_mode) 1562 + F2FS_OPTION(sbi).fsync_mode = F2FS_CTX_INFO(ctx).fsync_mode; 1563 + if (ctx->spec_mask & F2FS_SPEC_checkpoint_disable_cap) 1564 + F2FS_OPTION(sbi).unusable_cap = F2FS_CTX_INFO(ctx).unusable_cap; 1565 + if (ctx->spec_mask & F2FS_SPEC_checkpoint_disable_cap_perc) 1566 + F2FS_OPTION(sbi).unusable_cap_perc = 1567 + F2FS_CTX_INFO(ctx).unusable_cap_perc; 1568 + if (ctx->spec_mask & F2FS_SPEC_discard_unit) 1569 + F2FS_OPTION(sbi).discard_unit = F2FS_CTX_INFO(ctx).discard_unit; 1570 + if (ctx->spec_mask & F2FS_SPEC_memory_mode) 1571 + F2FS_OPTION(sbi).memory_mode = F2FS_CTX_INFO(ctx).memory_mode; 1572 + if (ctx->spec_mask & F2FS_SPEC_errors) 1573 + F2FS_OPTION(sbi).errors = F2FS_CTX_INFO(ctx).errors; 1574 + 1575 + f2fs_apply_compression(fc, sb); 1576 + f2fs_apply_test_dummy_encryption(fc, sb); 1577 + f2fs_apply_quota_options(fc, sb); 1578 + } 1579 + 1580 + static int f2fs_sanity_check_options(struct f2fs_sb_info *sbi, bool remount) 1581 + { 1582 + if (f2fs_sb_has_device_alias(sbi) && 1583 + !test_opt(sbi, READ_EXTENT_CACHE)) { 1584 + f2fs_err(sbi, "device aliasing requires extent cache"); 1504 1585 return -EINVAL; 1505 1586 } 1506 1587 1588 + if (!remount) 1589 + return 0; 1590 + 1591 + #ifdef CONFIG_BLK_DEV_ZONED 1592 + if (f2fs_sb_has_blkzoned(sbi) && 1593 + sbi->max_open_zones < F2FS_OPTION(sbi).active_logs) { 1594 + f2fs_err(sbi, 1595 + "zoned: max open zones %u is too small, need at least %u open zones", 1596 + sbi->max_open_zones, F2FS_OPTION(sbi).active_logs); 1597 + return -EINVAL; 1598 + } 1599 + #endif 1600 + if (f2fs_lfs_mode(sbi) && !IS_F2FS_IPU_DISABLE(sbi)) { 1601 + f2fs_warn(sbi, "LFS is not compatible with IPU"); 1602 + return -EINVAL; 1603 + } 1507 1604 return 0; 1508 1605 } 1509 1606 ··· 1701 1442 /* Initialize f2fs-specific inode info */ 1702 1443 atomic_set(&fi->dirty_pages, 0); 1703 1444 atomic_set(&fi->i_compr_blocks, 0); 1445 + atomic_set(&fi->open_count, 0); 1704 1446 init_f2fs_rwsem(&fi->i_sem); 1705 1447 spin_lock_init(&fi->i_size_lock); 1706 1448 INIT_LIST_HEAD(&fi->dirty_list); ··· 1978 1718 destroy_percpu_info(sbi); 1979 1719 f2fs_destroy_iostat(sbi); 1980 1720 for (i = 0; i < NR_PAGE_TYPE; i++) 1981 - kvfree(sbi->write_io[i]); 1721 + kfree(sbi->write_io[i]); 1982 1722 #if IS_ENABLED(CONFIG_UNICODE) 1983 1723 utf8_unload(sb->s_encoding); 1984 1724 #endif ··· 2589 2329 f2fs_flush_ckpt_thread(sbi); 2590 2330 } 2591 2331 2592 - static int f2fs_remount(struct super_block *sb, int *flags, char *data) 2332 + static int __f2fs_remount(struct fs_context *fc, struct super_block *sb) 2593 2333 { 2594 2334 struct f2fs_sb_info *sbi = F2FS_SB(sb); 2595 2335 struct f2fs_mount_info org_mount_opt; 2596 2336 unsigned long old_sb_flags; 2337 + unsigned int flags = fc->sb_flags; 2597 2338 int err; 2598 2339 bool need_restart_gc = false, need_stop_gc = false; 2599 2340 bool need_restart_flush = false, need_stop_flush = false; ··· 2640 2379 #endif 2641 2380 2642 2381 /* recover superblocks we couldn't write due to previous RO mount */ 2643 - if (!(*flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) { 2382 + if (!(flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) { 2644 2383 err = f2fs_commit_super(sbi, false); 2645 2384 f2fs_info(sbi, "Try to recover all the superblocks, ret: %d", 2646 2385 err); ··· 2650 2389 2651 2390 default_options(sbi, true); 2652 2391 2653 - /* parse mount options */ 2654 - err = parse_options(sbi, data, true); 2392 + err = f2fs_check_opt_consistency(fc, sb); 2655 2393 if (err) 2656 2394 goto restore_opts; 2657 2395 2658 - #ifdef CONFIG_BLK_DEV_ZONED 2659 - if (f2fs_sb_has_blkzoned(sbi) && 2660 - sbi->max_open_zones < F2FS_OPTION(sbi).active_logs) { 2661 - f2fs_err(sbi, 2662 - "zoned: max open zones %u is too small, need at least %u open zones", 2663 - sbi->max_open_zones, F2FS_OPTION(sbi).active_logs); 2664 - err = -EINVAL; 2665 - goto restore_opts; 2666 - } 2667 - #endif 2396 + f2fs_apply_options(fc, sb); 2668 2397 2669 - err = f2fs_default_check(sbi); 2398 + err = f2fs_sanity_check_options(sbi, true); 2670 2399 if (err) 2671 2400 goto restore_opts; 2672 2401 ··· 2667 2416 * Previous and new state of filesystem is RO, 2668 2417 * so skip checking GC and FLUSH_MERGE conditions. 2669 2418 */ 2670 - if (f2fs_readonly(sb) && (*flags & SB_RDONLY)) 2419 + if (f2fs_readonly(sb) && (flags & SB_RDONLY)) 2671 2420 goto skip; 2672 2421 2673 - if (f2fs_dev_is_readonly(sbi) && !(*flags & SB_RDONLY)) { 2422 + if (f2fs_dev_is_readonly(sbi) && !(flags & SB_RDONLY)) { 2674 2423 err = -EROFS; 2675 2424 goto restore_opts; 2676 2425 } 2677 2426 2678 2427 #ifdef CONFIG_QUOTA 2679 - if (!f2fs_readonly(sb) && (*flags & SB_RDONLY)) { 2428 + if (!f2fs_readonly(sb) && (flags & SB_RDONLY)) { 2680 2429 err = dquot_suspend(sb, -1); 2681 2430 if (err < 0) 2682 2431 goto restore_opts; 2683 - } else if (f2fs_readonly(sb) && !(*flags & SB_RDONLY)) { 2432 + } else if (f2fs_readonly(sb) && !(flags & SB_RDONLY)) { 2684 2433 /* dquot_resume needs RW */ 2685 2434 sb->s_flags &= ~SB_RDONLY; 2686 2435 if (sb_any_quota_suspended(sb)) { ··· 2692 2441 } 2693 2442 } 2694 2443 #endif 2695 - if (f2fs_lfs_mode(sbi) && !IS_F2FS_IPU_DISABLE(sbi)) { 2696 - err = -EINVAL; 2697 - f2fs_warn(sbi, "LFS is not compatible with IPU"); 2698 - goto restore_opts; 2699 - } 2700 - 2701 2444 /* disallow enable atgc dynamically */ 2702 2445 if (no_atgc == !!test_opt(sbi, ATGC)) { 2703 2446 err = -EINVAL; ··· 2730 2485 goto restore_opts; 2731 2486 } 2732 2487 2733 - if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) { 2488 + if ((flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) { 2734 2489 err = -EINVAL; 2735 2490 f2fs_warn(sbi, "disabling checkpoint not compatible with read-only"); 2736 2491 goto restore_opts; ··· 2741 2496 * or if background_gc = off is passed in mount 2742 2497 * option. Also sync the filesystem. 2743 2498 */ 2744 - if ((*flags & SB_RDONLY) || 2499 + if ((flags & SB_RDONLY) || 2745 2500 (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF && 2746 2501 !test_opt(sbi, GC_MERGE))) { 2747 2502 if (sbi->gc_thread) { ··· 2755 2510 need_stop_gc = true; 2756 2511 } 2757 2512 2758 - if (*flags & SB_RDONLY) { 2513 + if (flags & SB_RDONLY) { 2759 2514 sync_inodes_sb(sb); 2760 2515 2761 2516 set_sbi_flag(sbi, SBI_IS_DIRTY); ··· 2768 2523 * We stop issue flush thread if FS is mounted as RO 2769 2524 * or if flush_merge is not passed in mount option. 2770 2525 */ 2771 - if ((*flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) { 2526 + if ((flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) { 2772 2527 clear_opt(sbi, FLUSH_MERGE); 2773 2528 f2fs_destroy_flush_cmd_control(sbi, false); 2774 2529 need_restart_flush = true; ··· 2810 2565 * triggered while remount and we need to take care of it before 2811 2566 * returning from remount. 2812 2567 */ 2813 - if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) || 2568 + if ((flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) || 2814 2569 !test_opt(sbi, MERGE_CHECKPOINT)) { 2815 2570 f2fs_stop_ckpt_thread(sbi); 2816 2571 } else { 2817 - /* Flush if the prevous checkpoint, if exists. */ 2572 + /* Flush if the previous checkpoint, if exists. */ 2818 2573 f2fs_flush_ckpt_thread(sbi); 2819 2574 2820 2575 err = f2fs_start_ckpt_thread(sbi); ··· 2837 2592 (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); 2838 2593 2839 2594 limit_reserve_root(sbi); 2840 - *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME); 2595 + fc->sb_flags = (flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME); 2841 2596 2842 2597 sbi->umount_lock_holder = NULL; 2843 2598 return 0; ··· 3508 3263 .freeze_fs = f2fs_freeze, 3509 3264 .unfreeze_fs = f2fs_unfreeze, 3510 3265 .statfs = f2fs_statfs, 3511 - .remount_fs = f2fs_remount, 3512 3266 .shutdown = f2fs_shutdown, 3513 3267 }; 3514 3268 ··· 3695 3451 f2fs_bug_on(sbi, 1); 3696 3452 3697 3453 ret = submit_bio_wait(bio); 3454 + bio_put(bio); 3698 3455 folio_end_writeback(folio); 3699 3456 3700 3457 return ret; ··· 4767 4522 sbi->readdir_ra = true; 4768 4523 } 4769 4524 4770 - static int f2fs_fill_super(struct super_block *sb, void *data, int silent) 4525 + static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc) 4771 4526 { 4527 + struct f2fs_fs_context *ctx = fc->fs_private; 4772 4528 struct f2fs_sb_info *sbi; 4773 4529 struct f2fs_super_block *raw_super; 4774 4530 struct inode *root; 4775 4531 int err; 4776 4532 bool skip_recovery = false, need_fsck = false; 4777 - char *options = NULL; 4778 4533 int recovery, i, valid_super_block; 4779 4534 struct curseg_info *seg_i; 4780 4535 int retry_cnt = 1; ··· 4837 4592 sizeof(raw_super->uuid)); 4838 4593 4839 4594 default_options(sbi, false); 4840 - /* parse mount options */ 4841 - options = kstrdup((const char *)data, GFP_KERNEL); 4842 - if (data && !options) { 4843 - err = -ENOMEM; 4844 - goto free_sb_buf; 4845 - } 4846 4595 4847 - err = parse_options(sbi, options, false); 4596 + err = f2fs_check_opt_consistency(fc, sb); 4848 4597 if (err) 4849 - goto free_options; 4598 + goto free_sb_buf; 4850 4599 4851 - err = f2fs_default_check(sbi); 4600 + f2fs_apply_options(fc, sb); 4601 + 4602 + err = f2fs_sanity_check_options(sbi, false); 4852 4603 if (err) 4853 4604 goto free_options; 4854 4605 ··· 5011 4770 /* get segno of first zoned block device */ 5012 4771 sbi->first_seq_zone_segno = get_first_seq_zone_segno(sbi); 5013 4772 4773 + sbi->reserved_pin_section = f2fs_sb_has_blkzoned(sbi) ? 4774 + ZONED_PIN_SEC_REQUIRED_COUNT : 4775 + GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)); 4776 + 5014 4777 /* Read accumulated write IO statistics if exists */ 5015 4778 seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); 5016 4779 if (__exist_node_summaries(sbi)) ··· 5175 4930 if (err) 5176 4931 goto sync_free_meta; 5177 4932 } 5178 - kvfree(options); 5179 4933 5180 4934 /* recover broken superblock */ 5181 4935 if (recovery) { ··· 5257 5013 f2fs_destroy_iostat(sbi); 5258 5014 free_bio_info: 5259 5015 for (i = 0; i < NR_PAGE_TYPE; i++) 5260 - kvfree(sbi->write_io[i]); 5016 + kfree(sbi->write_io[i]); 5261 5017 5262 5018 #if IS_ENABLED(CONFIG_UNICODE) 5263 5019 utf8_unload(sb->s_encoding); ··· 5268 5024 for (i = 0; i < MAXQUOTAS; i++) 5269 5025 kfree(F2FS_OPTION(sbi).s_qf_names[i]); 5270 5026 #endif 5271 - fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy); 5272 - kvfree(options); 5027 + /* no need to free dummy_enc_policy, we just keep it in ctx when failed */ 5028 + swap(F2FS_CTX_INFO(ctx).dummy_enc_policy, F2FS_OPTION(sbi).dummy_enc_policy); 5273 5029 free_sb_buf: 5274 5030 kfree(raw_super); 5275 5031 free_sbi: ··· 5285 5041 return err; 5286 5042 } 5287 5043 5288 - static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, 5289 - const char *dev_name, void *data) 5044 + static int f2fs_get_tree(struct fs_context *fc) 5290 5045 { 5291 - return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); 5046 + return get_tree_bdev(fc, f2fs_fill_super); 5292 5047 } 5048 + 5049 + static int f2fs_reconfigure(struct fs_context *fc) 5050 + { 5051 + struct super_block *sb = fc->root->d_sb; 5052 + 5053 + return __f2fs_remount(fc, sb); 5054 + } 5055 + 5056 + static void f2fs_fc_free(struct fs_context *fc) 5057 + { 5058 + struct f2fs_fs_context *ctx = fc->fs_private; 5059 + 5060 + if (!ctx) 5061 + return; 5062 + 5063 + #ifdef CONFIG_QUOTA 5064 + f2fs_unnote_qf_name_all(fc); 5065 + #endif 5066 + fscrypt_free_dummy_policy(&F2FS_CTX_INFO(ctx).dummy_enc_policy); 5067 + kfree(ctx); 5068 + } 5069 + 5070 + static const struct fs_context_operations f2fs_context_ops = { 5071 + .parse_param = f2fs_parse_param, 5072 + .get_tree = f2fs_get_tree, 5073 + .reconfigure = f2fs_reconfigure, 5074 + .free = f2fs_fc_free, 5075 + }; 5293 5076 5294 5077 static void kill_f2fs_super(struct super_block *sb) 5295 5078 { ··· 5359 5088 } 5360 5089 } 5361 5090 5091 + static int f2fs_init_fs_context(struct fs_context *fc) 5092 + { 5093 + struct f2fs_fs_context *ctx; 5094 + 5095 + ctx = kzalloc(sizeof(struct f2fs_fs_context), GFP_KERNEL); 5096 + if (!ctx) 5097 + return -ENOMEM; 5098 + 5099 + fc->fs_private = ctx; 5100 + fc->ops = &f2fs_context_ops; 5101 + 5102 + return 0; 5103 + } 5104 + 5362 5105 static struct file_system_type f2fs_fs_type = { 5363 5106 .owner = THIS_MODULE, 5364 5107 .name = "f2fs", 5365 - .mount = f2fs_mount, 5108 + .init_fs_context = f2fs_init_fs_context, 5366 5109 .kill_sb = kill_f2fs_super, 5367 5110 .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, 5368 5111 };
+48
fs/f2fs/sysfs.c
··· 628 628 return count; 629 629 } 630 630 631 + if (!strcmp(a->attr.name, "gc_no_zoned_gc_percent")) { 632 + if (t > 100) 633 + return -EINVAL; 634 + *ui = (unsigned int)t; 635 + return count; 636 + } 637 + 638 + if (!strcmp(a->attr.name, "gc_boost_zoned_gc_percent")) { 639 + if (t > 100) 640 + return -EINVAL; 641 + *ui = (unsigned int)t; 642 + return count; 643 + } 644 + 645 + if (!strcmp(a->attr.name, "gc_valid_thresh_ratio")) { 646 + if (t > 100) 647 + return -EINVAL; 648 + *ui = (unsigned int)t; 649 + return count; 650 + } 651 + 631 652 #ifdef CONFIG_F2FS_IOSTAT 632 653 if (!strcmp(a->attr.name, "iostat_enable")) { 633 654 sbi->iostat_enable = !!t; ··· 842 821 if (t > MAX_DIR_HASH_DEPTH) 843 822 return -EINVAL; 844 823 sbi->dir_level = t; 824 + return count; 825 + } 826 + 827 + if (!strcmp(a->attr.name, "reserved_pin_section")) { 828 + if (t > GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi))) 829 + return -EINVAL; 830 + *ui = (unsigned int)t; 831 + return count; 832 + } 833 + 834 + if (!strcmp(a->attr.name, "gc_boost_gc_multiple")) { 835 + if (t < 1 || t > SEGS_PER_SEC(sbi)) 836 + return -EINVAL; 837 + sbi->gc_thread->boost_gc_multiple = (unsigned int)t; 838 + return count; 839 + } 840 + 841 + if (!strcmp(a->attr.name, "gc_boost_gc_greedy")) { 842 + if (t > GC_GREEDY) 843 + return -EINVAL; 844 + sbi->gc_thread->boost_gc_greedy = (unsigned int)t; 845 845 return count; 846 846 } 847 847 ··· 1092 1050 GC_THREAD_RW_ATTR(gc_no_zoned_gc_percent, no_zoned_gc_percent); 1093 1051 GC_THREAD_RW_ATTR(gc_boost_zoned_gc_percent, boost_zoned_gc_percent); 1094 1052 GC_THREAD_RW_ATTR(gc_valid_thresh_ratio, valid_thresh_ratio); 1053 + GC_THREAD_RW_ATTR(gc_boost_gc_multiple, boost_gc_multiple); 1054 + GC_THREAD_RW_ATTR(gc_boost_gc_greedy, boost_gc_greedy); 1095 1055 1096 1056 /* SM_INFO ATTR */ 1097 1057 SM_INFO_RW_ATTR(reclaim_segments, rec_prefree_segments); ··· 1174 1130 F2FS_SBI_GENERAL_RW_ATTR(blkzone_alloc_policy); 1175 1131 #endif 1176 1132 F2FS_SBI_GENERAL_RW_ATTR(carve_out); 1133 + F2FS_SBI_GENERAL_RW_ATTR(reserved_pin_section); 1177 1134 1178 1135 /* STAT_INFO ATTR */ 1179 1136 #ifdef CONFIG_F2FS_STAT_FS ··· 1265 1220 ATTR_LIST(gc_no_zoned_gc_percent), 1266 1221 ATTR_LIST(gc_boost_zoned_gc_percent), 1267 1222 ATTR_LIST(gc_valid_thresh_ratio), 1223 + ATTR_LIST(gc_boost_gc_multiple), 1224 + ATTR_LIST(gc_boost_gc_greedy), 1268 1225 ATTR_LIST(gc_idle), 1269 1226 ATTR_LIST(gc_urgent), 1270 1227 ATTR_LIST(reclaim_segments), ··· 1370 1323 ATTR_LIST(last_age_weight), 1371 1324 ATTR_LIST(max_read_extent_count), 1372 1325 ATTR_LIST(carve_out), 1326 + ATTR_LIST(reserved_pin_section), 1373 1327 NULL, 1374 1328 }; 1375 1329 ATTRIBUTE_GROUPS(f2fs);
+1 -1
fs/fat/fatent.c
··· 356 356 357 357 if (!fat_valid_entry(sbi, entry)) { 358 358 fatent_brelse(fatent); 359 - fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); 359 + fat_fs_error_ratelimit(sb, "invalid access to FAT (entry 0x%08x)", entry); 360 360 return -EIO; 361 361 } 362 362
+3 -3
fs/fat/misc.c
··· 158 158 mark_inode_dirty(inode); 159 159 } 160 160 if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { 161 - fat_fs_error(sb, "clusters badly computed (%d != %llu)", 162 - new_fclus, 163 - (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); 161 + fat_fs_error_ratelimit( 162 + sb, "clusters badly computed (%d != %llu)", new_fclus, 163 + (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); 164 164 fat_cache_inval_inode(inode); 165 165 } 166 166 inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
+1
fs/ocfs2/aops.c
··· 1071 1071 if (IS_ERR(wc->w_folios[i])) { 1072 1072 ret = PTR_ERR(wc->w_folios[i]); 1073 1073 mlog_errno(ret); 1074 + wc->w_folios[i] = NULL; 1074 1075 goto out; 1075 1076 } 1076 1077 }
+8
fs/ocfs2/dir.c
··· 798 798 } 799 799 } 800 800 801 + if (le16_to_cpu(el->l_next_free_rec) == 0) { 802 + ret = ocfs2_error(inode->i_sb, 803 + "Inode %lu has empty extent list at depth %u\n", 804 + inode->i_ino, 805 + le16_to_cpu(el->l_tree_depth)); 806 + goto out; 807 + } 808 + 801 809 found = 0; 802 810 for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) { 803 811 rec = &el->l_recs[i];
+1 -1
fs/ocfs2/dlm/dlmrecovery.c
··· 2632 2632 dlm_reco_master_ready(dlm), 2633 2633 msecs_to_jiffies(1000)); 2634 2634 if (!dlm_reco_master_ready(dlm)) { 2635 - mlog(0, "%s: reco master taking awhile\n", 2635 + mlog(0, "%s: reco master taking a while\n", 2636 2636 dlm->name); 2637 2637 goto again; 2638 2638 }
+66 -4
fs/ocfs2/inode.c
··· 50 50 unsigned int fi_sysfile_type; 51 51 }; 52 52 53 - static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES]; 54 - 55 53 static int ocfs2_read_locked_inode(struct inode *inode, 56 54 struct ocfs2_find_inode_args *args); 57 55 static int ocfs2_init_locked_inode(struct inode *inode, void *opaque); ··· 248 250 static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) 249 251 { 250 252 struct ocfs2_find_inode_args *args = opaque; 253 + #ifdef CONFIG_LOCKDEP 254 + static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES]; 251 255 static struct lock_class_key ocfs2_quota_ip_alloc_sem_key, 252 256 ocfs2_file_ip_alloc_sem_key; 257 + #endif 253 258 254 259 inode->i_ino = args->fi_ino; 255 260 OCFS2_I(inode)->ip_blkno = args->fi_blkno; 256 - if (args->fi_sysfile_type != 0) 261 + #ifdef CONFIG_LOCKDEP 262 + switch (args->fi_sysfile_type) { 263 + case BAD_BLOCK_SYSTEM_INODE: 264 + break; 265 + case GLOBAL_INODE_ALLOC_SYSTEM_INODE: 257 266 lockdep_set_class(&inode->i_rwsem, 258 - &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); 267 + &ocfs2_sysfile_lock_key[GLOBAL_INODE_ALLOC_SYSTEM_INODE]); 268 + break; 269 + case SLOT_MAP_SYSTEM_INODE: 270 + lockdep_set_class(&inode->i_rwsem, 271 + &ocfs2_sysfile_lock_key[SLOT_MAP_SYSTEM_INODE]); 272 + break; 273 + case HEARTBEAT_SYSTEM_INODE: 274 + lockdep_set_class(&inode->i_rwsem, 275 + &ocfs2_sysfile_lock_key[HEARTBEAT_SYSTEM_INODE]); 276 + break; 277 + case GLOBAL_BITMAP_SYSTEM_INODE: 278 + lockdep_set_class(&inode->i_rwsem, 279 + &ocfs2_sysfile_lock_key[GLOBAL_BITMAP_SYSTEM_INODE]); 280 + break; 281 + case USER_QUOTA_SYSTEM_INODE: 282 + lockdep_set_class(&inode->i_rwsem, 283 + &ocfs2_sysfile_lock_key[USER_QUOTA_SYSTEM_INODE]); 284 + break; 285 + case GROUP_QUOTA_SYSTEM_INODE: 286 + lockdep_set_class(&inode->i_rwsem, 287 + &ocfs2_sysfile_lock_key[GROUP_QUOTA_SYSTEM_INODE]); 288 + break; 289 + case ORPHAN_DIR_SYSTEM_INODE: 290 + lockdep_set_class(&inode->i_rwsem, 291 + &ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]); 292 + break; 293 + case EXTENT_ALLOC_SYSTEM_INODE: 294 + lockdep_set_class(&inode->i_rwsem, 295 + &ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]); 296 + break; 297 + case INODE_ALLOC_SYSTEM_INODE: 298 + lockdep_set_class(&inode->i_rwsem, 299 + &ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]); 300 + break; 301 + case JOURNAL_SYSTEM_INODE: 302 + lockdep_set_class(&inode->i_rwsem, 303 + &ocfs2_sysfile_lock_key[JOURNAL_SYSTEM_INODE]); 304 + break; 305 + case LOCAL_ALLOC_SYSTEM_INODE: 306 + lockdep_set_class(&inode->i_rwsem, 307 + &ocfs2_sysfile_lock_key[LOCAL_ALLOC_SYSTEM_INODE]); 308 + break; 309 + case TRUNCATE_LOG_SYSTEM_INODE: 310 + lockdep_set_class(&inode->i_rwsem, 311 + &ocfs2_sysfile_lock_key[TRUNCATE_LOG_SYSTEM_INODE]); 312 + break; 313 + case LOCAL_USER_QUOTA_SYSTEM_INODE: 314 + lockdep_set_class(&inode->i_rwsem, 315 + &ocfs2_sysfile_lock_key[LOCAL_USER_QUOTA_SYSTEM_INODE]); 316 + break; 317 + case LOCAL_GROUP_QUOTA_SYSTEM_INODE: 318 + lockdep_set_class(&inode->i_rwsem, 319 + &ocfs2_sysfile_lock_key[LOCAL_GROUP_QUOTA_SYSTEM_INODE]); 320 + break; 321 + default: 322 + WARN_ONCE(1, "Unknown sysfile type %d\n", args->fi_sysfile_type); 323 + } 259 324 if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE || 260 325 args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE || 261 326 args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE || ··· 328 267 else 329 268 lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, 330 269 &ocfs2_file_ip_alloc_sem_key); 270 + #endif 331 271 332 272 return 0; 333 273 }
+9 -10
fs/ocfs2/move_extents.c
··· 617 617 */ 618 618 credits += OCFS2_INODE_UPDATE_CREDITS + 1; 619 619 620 + inode_lock(tl_inode); 621 + 620 622 /* 621 623 * ocfs2_move_extent() didn't reserve any clusters in lock_allocators() 622 624 * logic, while we still need to lock the global_bitmap. ··· 628 626 if (!gb_inode) { 629 627 mlog(ML_ERROR, "unable to get global_bitmap inode\n"); 630 628 ret = -EIO; 631 - goto out; 629 + goto out_unlock_tl_inode; 632 630 } 633 631 634 632 inode_lock(gb_inode); ··· 636 634 ret = ocfs2_inode_lock(gb_inode, &gb_bh, 1); 637 635 if (ret) { 638 636 mlog_errno(ret); 639 - goto out_unlock_gb_mutex; 637 + goto out_unlock_gb_inode; 640 638 } 641 - 642 - inode_lock(tl_inode); 643 639 644 640 handle = ocfs2_start_trans(osb, credits); 645 641 if (IS_ERR(handle)) { 646 642 ret = PTR_ERR(handle); 647 643 mlog_errno(ret); 648 - goto out_unlock_tl_inode; 644 + goto out_unlock; 649 645 } 650 646 651 647 new_phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *new_phys_cpos); ··· 703 703 out_commit: 704 704 ocfs2_commit_trans(osb, handle); 705 705 brelse(gd_bh); 706 - 707 - out_unlock_tl_inode: 708 - inode_unlock(tl_inode); 709 - 706 + out_unlock: 710 707 ocfs2_inode_unlock(gb_inode, 1); 711 - out_unlock_gb_mutex: 708 + out_unlock_gb_inode: 712 709 inode_unlock(gb_inode); 713 710 brelse(gb_bh); 714 711 iput(gb_inode); 712 + out_unlock_tl_inode: 713 + inode_unlock(tl_inode); 715 714 716 715 out: 717 716 if (context->meta_ac) {
+7 -4
fs/ocfs2/namei.c
··· 142 142 143 143 bail_add: 144 144 ret = d_splice_alias(inode, dentry); 145 + if (IS_ERR(ret)) 146 + goto bail_unlock; 145 147 146 148 if (inode) { 147 149 /* ··· 156 154 * NOTE: This dentry already has ->d_op set from 157 155 * ocfs2_get_parent() and ocfs2_get_dentry() 158 156 */ 159 - if (!IS_ERR_OR_NULL(ret)) 157 + if (ret) 160 158 dentry = ret; 161 159 162 160 status = ocfs2_dentry_attach_lock(dentry, inode, 163 161 OCFS2_I(dir)->ip_blkno); 164 162 if (status) { 165 163 mlog_errno(status); 164 + if (ret) 165 + dput(ret); 166 166 ret = ERR_PTR(status); 167 - goto bail_unlock; 168 167 } 169 168 } else 170 169 ocfs2_dentry_attach_gen(dentry); ··· 1455 1452 newfe = (struct ocfs2_dinode *) newfe_bh->b_data; 1456 1453 1457 1454 trace_ocfs2_rename_over_existing( 1458 - (unsigned long long)newfe_blkno, newfe_bh, newfe_bh ? 1459 - (unsigned long long)newfe_bh->b_blocknr : 0ULL); 1455 + (unsigned long long)newfe_blkno, newfe_bh, 1456 + (unsigned long long)newfe_bh->b_blocknr); 1460 1457 1461 1458 if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) { 1462 1459 status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
+4 -11
fs/ocfs2/stack_user.c
··· 360 360 struct ocfs2_control_message_setn *msg) 361 361 { 362 362 long nodenum; 363 - char *ptr = NULL; 364 363 struct ocfs2_control_private *p = file->private_data; 365 364 366 365 if (ocfs2_control_get_handshake_state(file) != ··· 374 375 return -EINVAL; 375 376 msg->space = msg->newline = '\0'; 376 377 377 - nodenum = simple_strtol(msg->nodestr, &ptr, 16); 378 - if (!ptr || *ptr) 378 + if (kstrtol(msg->nodestr, 16, &nodenum)) 379 379 return -EINVAL; 380 380 381 381 if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) || ··· 389 391 struct ocfs2_control_message_setv *msg) 390 392 { 391 393 long major, minor; 392 - char *ptr = NULL; 393 394 struct ocfs2_control_private *p = file->private_data; 394 395 struct ocfs2_protocol_version *max = 395 396 &ocfs2_user_plugin.sp_max_proto; ··· 406 409 return -EINVAL; 407 410 msg->space1 = msg->space2 = msg->newline = '\0'; 408 411 409 - major = simple_strtol(msg->major, &ptr, 16); 410 - if (!ptr || *ptr) 412 + if (kstrtol(msg->major, 16, &major)) 411 413 return -EINVAL; 412 - minor = simple_strtol(msg->minor, &ptr, 16); 413 - if (!ptr || *ptr) 414 + if (kstrtol(msg->minor, 16, &minor)) 414 415 return -EINVAL; 415 416 416 417 /* ··· 436 441 struct ocfs2_control_message_down *msg) 437 442 { 438 443 long nodenum; 439 - char *p = NULL; 440 444 441 445 if (ocfs2_control_get_handshake_state(file) != 442 446 OCFS2_CONTROL_HANDSHAKE_VALID) ··· 450 456 return -EINVAL; 451 457 msg->space1 = msg->space2 = msg->newline = '\0'; 452 458 453 - nodenum = simple_strtol(msg->nodestr, &p, 16); 454 - if (!p || *p) 459 + if (kstrtol(msg->nodestr, 16, &nodenum)) 455 460 return -EINVAL; 456 461 457 462 if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
+12 -17
fs/proc/vmcore.c
··· 1490 1490 return -EINVAL; 1491 1491 1492 1492 dump = vzalloc(sizeof(*dump)); 1493 - if (!dump) { 1494 - ret = -ENOMEM; 1495 - goto out_err; 1496 - } 1493 + if (!dump) 1494 + return -ENOMEM; 1497 1495 1498 1496 /* Keep size of the buffer page aligned so that it can be mmaped */ 1499 1497 data_size = roundup(sizeof(struct vmcoredd_header) + data->size, ··· 1517 1519 dump->size = data_size; 1518 1520 1519 1521 /* Add the dump to driver sysfs list and update the elfcore hdr */ 1520 - mutex_lock(&vmcore_mutex); 1521 - if (vmcore_opened) 1522 - pr_warn_once("Unexpected adding of device dump\n"); 1523 - if (vmcore_open) { 1524 - ret = -EBUSY; 1525 - goto unlock; 1522 + scoped_guard(mutex, &vmcore_mutex) { 1523 + if (vmcore_opened) 1524 + pr_warn_once("Unexpected adding of device dump\n"); 1525 + if (vmcore_open) { 1526 + ret = -EBUSY; 1527 + goto out_err; 1528 + } 1529 + 1530 + list_add_tail(&dump->list, &vmcoredd_list); 1531 + vmcoredd_update_size(data_size); 1526 1532 } 1527 - 1528 - list_add_tail(&dump->list, &vmcoredd_list); 1529 - vmcoredd_update_size(data_size); 1530 - mutex_unlock(&vmcore_mutex); 1531 1533 return 0; 1532 - 1533 - unlock: 1534 - mutex_unlock(&vmcore_mutex); 1535 1534 1536 1535 out_err: 1537 1536 vfree(buf);
+23 -24
fs/squashfs/block.c
··· 80 80 struct address_space *cache_mapping, u64 index, int length, 81 81 u64 read_start, u64 read_end, int page_count) 82 82 { 83 - struct page *head_to_cache = NULL, *tail_to_cache = NULL; 83 + struct folio *head_to_cache = NULL, *tail_to_cache = NULL; 84 84 struct block_device *bdev = fullbio->bi_bdev; 85 85 int start_idx = 0, end_idx = 0; 86 - struct bvec_iter_all iter_all; 86 + struct folio_iter fi; 87 87 struct bio *bio = NULL; 88 - struct bio_vec *bv; 89 88 int idx = 0; 90 89 int err = 0; 91 90 #ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL 92 - struct page **cache_pages = kmalloc_array(page_count, 93 - sizeof(void *), GFP_KERNEL | __GFP_ZERO); 91 + struct folio **cache_folios = kmalloc_array(page_count, 92 + sizeof(*cache_folios), GFP_KERNEL | __GFP_ZERO); 94 93 #endif 95 94 96 - bio_for_each_segment_all(bv, fullbio, iter_all) { 97 - struct page *page = bv->bv_page; 95 + bio_for_each_folio_all(fi, fullbio) { 96 + struct folio *folio = fi.folio; 98 97 99 - if (page->mapping == cache_mapping) { 98 + if (folio->mapping == cache_mapping) { 100 99 idx++; 101 100 continue; 102 101 } ··· 110 111 * adjacent blocks. 111 112 */ 112 113 if (idx == 0 && index != read_start) 113 - head_to_cache = page; 114 + head_to_cache = folio; 114 115 else if (idx == page_count - 1 && index + length != read_end) 115 - tail_to_cache = page; 116 + tail_to_cache = folio; 116 117 #ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL 117 118 /* Cache all pages in the BIO for repeated reads */ 118 - else if (cache_pages) 119 - cache_pages[idx] = page; 119 + else if (cache_folios) 120 + cache_folios[idx] = folio; 120 121 #endif 121 122 122 123 if (!bio || idx != end_idx) { ··· 149 150 return err; 150 151 151 152 if (head_to_cache) { 152 - int ret = add_to_page_cache_lru(head_to_cache, cache_mapping, 153 + int ret = filemap_add_folio(cache_mapping, head_to_cache, 153 154 read_start >> PAGE_SHIFT, 154 155 GFP_NOIO); 155 156 156 157 if (!ret) { 157 - SetPageUptodate(head_to_cache); 158 - unlock_page(head_to_cache); 158 + folio_mark_uptodate(head_to_cache); 159 + folio_unlock(head_to_cache); 159 160 } 160 161 161 162 } 162 163 163 164 if (tail_to_cache) { 164 - int ret = add_to_page_cache_lru(tail_to_cache, cache_mapping, 165 + int ret = filemap_add_folio(cache_mapping, tail_to_cache, 165 166 (read_end >> PAGE_SHIFT) - 1, 166 167 GFP_NOIO); 167 168 168 169 if (!ret) { 169 - SetPageUptodate(tail_to_cache); 170 - unlock_page(tail_to_cache); 170 + folio_mark_uptodate(tail_to_cache); 171 + folio_unlock(tail_to_cache); 171 172 } 172 173 } 173 174 174 175 #ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL 175 - if (!cache_pages) 176 + if (!cache_folios) 176 177 goto out; 177 178 178 179 for (idx = 0; idx < page_count; idx++) { 179 - if (!cache_pages[idx]) 180 + if (!cache_folios[idx]) 180 181 continue; 181 - int ret = add_to_page_cache_lru(cache_pages[idx], cache_mapping, 182 + int ret = filemap_add_folio(cache_mapping, cache_folios[idx], 182 183 (read_start >> PAGE_SHIFT) + idx, 183 184 GFP_NOIO); 184 185 185 186 if (!ret) { 186 - SetPageUptodate(cache_pages[idx]); 187 - unlock_page(cache_pages[idx]); 187 + folio_mark_uptodate(cache_folios[idx]); 188 + folio_unlock(cache_folios[idx]); 188 189 } 189 190 } 190 - kfree(cache_pages); 191 + kfree(cache_folios); 191 192 out: 192 193 #endif 193 194 return 0;
+3 -4
fs/squashfs/file.c
··· 493 493 return res; 494 494 } 495 495 496 - static int squashfs_readahead_fragment(struct page **page, 496 + static int squashfs_readahead_fragment(struct inode *inode, struct page **page, 497 497 unsigned int pages, unsigned int expected, loff_t start) 498 498 { 499 - struct inode *inode = page[0]->mapping->host; 500 499 struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb, 501 500 squashfs_i(inode)->fragment_block, 502 501 squashfs_i(inode)->fragment_size); ··· 604 605 605 606 if (start >> msblk->block_log == file_end && 606 607 squashfs_i(inode)->fragment_block != SQUASHFS_INVALID_BLK) { 607 - res = squashfs_readahead_fragment(pages, nr_pages, 608 - expected, start); 608 + res = squashfs_readahead_fragment(inode, pages, 609 + nr_pages, expected, start); 609 610 if (res) 610 611 goto skip_pages; 611 612 continue;
+2 -2
include/crypto/algapi.h
··· 43 43 * alias. 44 44 */ 45 45 #define MODULE_ALIAS_CRYPTO(name) \ 46 - __MODULE_INFO(alias, alias_userspace, name); \ 47 - __MODULE_INFO(alias, alias_crypto, "crypto-" name) 46 + MODULE_INFO(alias, name); \ 47 + MODULE_INFO(alias, "crypto-" name) 48 48 49 49 struct crypto_aead; 50 50 struct crypto_instance;
+2
include/linux/compiler-gcc.h
··· 127 127 #define __diag_GCC_8(s) 128 128 #endif 129 129 130 + #define __diag_GCC_all(s) __diag(s) 131 + 130 132 #define __diag_ignore_all(option, comment) \ 131 133 __diag(__diag_GCC_ignore option) 132 134
+14 -1
include/linux/crash_reserve.h
··· 13 13 */ 14 14 extern struct resource crashk_res; 15 15 extern struct resource crashk_low_res; 16 + extern struct range crashk_cma_ranges[]; 17 + #if defined(CONFIG_CMA) && defined(CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION) 18 + #define CRASHKERNEL_CMA 19 + #define CRASHKERNEL_CMA_RANGES_MAX 4 20 + extern int crashk_cma_cnt; 21 + #else 22 + #define crashk_cma_cnt 0 23 + #define CRASHKERNEL_CMA_RANGES_MAX 0 24 + #endif 25 + 16 26 17 27 int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, 18 28 unsigned long long *crash_size, unsigned long long *crash_base, 19 - unsigned long long *low_size, bool *high); 29 + unsigned long long *low_size, unsigned long long *cma_size, 30 + bool *high); 31 + 32 + void __init reserve_crashkernel_cma(unsigned long long cma_size); 20 33 21 34 #ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION 22 35 #ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
+23 -31
include/linux/execmem.h
··· 60 60 * will trap 61 61 * @ptr: pointer to memory to fill 62 62 * @size: size of the range to fill 63 - * @writable: is the memory poited by @ptr is writable or ROX 64 63 * 65 64 * A hook for architecures to fill execmem ranges with invalid instructions. 66 65 * Architectures that use EXECMEM_ROX_CACHE must implement this. 67 66 */ 68 - void execmem_fill_trapping_insns(void *ptr, size_t size, bool writable); 69 - 70 - /** 71 - * execmem_make_temp_rw - temporarily remap region with read-write 72 - * permissions 73 - * @ptr: address of the region to remap 74 - * @size: size of the region to remap 75 - * 76 - * Remaps a part of the cached large page in the ROX cache in the range 77 - * [@ptr, @ptr + @size) as writable and not executable. The caller must 78 - * have exclusive ownership of this range and ensure nothing will try to 79 - * execute code in this range. 80 - * 81 - * Return: 0 on success or negative error code on failure. 82 - */ 83 - int execmem_make_temp_rw(void *ptr, size_t size); 67 + void execmem_fill_trapping_insns(void *ptr, size_t size); 84 68 85 69 /** 86 70 * execmem_restore_rox - restore read-only-execute permissions ··· 79 95 */ 80 96 int execmem_restore_rox(void *ptr, size_t size); 81 97 #else 82 - static inline int execmem_make_temp_rw(void *ptr, size_t size) { return 0; } 83 98 static inline int execmem_restore_rox(void *ptr, size_t size) { return 0; } 84 99 #endif 85 100 ··· 149 166 void *execmem_alloc(enum execmem_type type, size_t size); 150 167 151 168 /** 169 + * execmem_alloc_rw - allocate writable executable memory 170 + * @type: type of the allocation 171 + * @size: how many bytes of memory are required 172 + * 173 + * Allocates memory that will contain executable code, either generated or 174 + * loaded from kernel modules. 175 + * 176 + * Allocates memory that will contain data coupled with executable code, 177 + * like data sections in kernel modules. 178 + * 179 + * Forces writable permissions on the allocated memory and the caller is 180 + * responsible to manage the permissions afterwards. 181 + * 182 + * For architectures that use ROX cache the permissions will be set to R+W. 183 + * For architectures that don't use ROX cache the default permissions for @type 184 + * will be used as they must be writable. 185 + * 186 + * Return: a pointer to the allocated memory or %NULL 187 + */ 188 + void *execmem_alloc_rw(enum execmem_type type, size_t size); 189 + 190 + /** 152 191 * execmem_free - free executable memory 153 192 * @ptr: pointer to the memory that should be freed 154 193 */ ··· 189 184 */ 190 185 struct vm_struct *execmem_vmap(size_t size); 191 186 #endif 192 - 193 - /** 194 - * execmem_update_copy - copy an update to executable memory 195 - * @dst: destination address to update 196 - * @src: source address containing the data 197 - * @size: how many bytes of memory shold be copied 198 - * 199 - * Copy @size bytes from @src to @dst using text poking if the memory at 200 - * @dst is read-only. 201 - * 202 - * Return: a pointer to @dst or NULL on error 203 - */ 204 - void *execmem_update_copy(void *dst, const void *src, size_t size); 205 187 206 188 /** 207 189 * execmem_is_rox - check if execmem is read-only
+1 -1
include/linux/f2fs_fs.h
··· 268 268 /* Node IDs in an Indirect Block */ 269 269 #define NIDS_PER_BLOCK ((F2FS_BLKSIZE - sizeof(struct node_footer)) / sizeof(__le32)) 270 270 271 - #define ADDRS_PER_PAGE(page, inode) (addrs_per_page(inode, IS_INODE(page))) 271 + #define ADDRS_PER_PAGE(folio, inode) (addrs_per_page(inode, IS_INODE(folio))) 272 272 273 273 #define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) 274 274 #define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2)
+6 -4
include/linux/fscrypt.h
··· 332 332 return (struct page *)page_private(bounce_page); 333 333 } 334 334 335 - static inline bool fscrypt_is_bounce_folio(struct folio *folio) 335 + static inline bool fscrypt_is_bounce_folio(const struct folio *folio) 336 336 { 337 337 return folio->mapping == NULL; 338 338 } 339 339 340 - static inline struct folio *fscrypt_pagecache_folio(struct folio *bounce_folio) 340 + static inline 341 + struct folio *fscrypt_pagecache_folio(const struct folio *bounce_folio) 341 342 { 342 343 return bounce_folio->private; 343 344 } ··· 518 517 return ERR_PTR(-EINVAL); 519 518 } 520 519 521 - static inline bool fscrypt_is_bounce_folio(struct folio *folio) 520 + static inline bool fscrypt_is_bounce_folio(const struct folio *folio) 522 521 { 523 522 return false; 524 523 } 525 524 526 - static inline struct folio *fscrypt_pagecache_folio(struct folio *bounce_folio) 525 + static inline 526 + struct folio *fscrypt_pagecache_folio(const struct folio *bounce_folio) 527 527 { 528 528 WARN_ON_ONCE(1); 529 529 return ERR_PTR(-EINVAL);
+3
include/linux/gcd.h
··· 3 3 #define _GCD_H 4 4 5 5 #include <linux/compiler.h> 6 + #include <linux/jump_label.h> 7 + 8 + DECLARE_STATIC_KEY_TRUE(efficient_ffs_key); 6 9 7 10 unsigned long gcd(unsigned long a, unsigned long b) __attribute_const__; 8 11
+9 -9
include/linux/hung_task.h
··· 21 21 * type. 22 22 * 23 23 * Type encoding: 24 - * 00 - Blocked on mutex (BLOCKER_TYPE_MUTEX) 25 - * 01 - Blocked on semaphore (BLOCKER_TYPE_SEM) 26 - * 10 - Blocked on rt-mutex (BLOCKER_TYPE_RTMUTEX) 27 - * 11 - Blocked on rw-semaphore (BLOCKER_TYPE_RWSEM) 24 + * 00 - Blocked on mutex (BLOCKER_TYPE_MUTEX) 25 + * 01 - Blocked on semaphore (BLOCKER_TYPE_SEM) 26 + * 10 - Blocked on rw-semaphore as READER (BLOCKER_TYPE_RWSEM_READER) 27 + * 11 - Blocked on rw-semaphore as WRITER (BLOCKER_TYPE_RWSEM_WRITER) 28 28 */ 29 - #define BLOCKER_TYPE_MUTEX 0x00UL 30 - #define BLOCKER_TYPE_SEM 0x01UL 31 - #define BLOCKER_TYPE_RTMUTEX 0x02UL 32 - #define BLOCKER_TYPE_RWSEM 0x03UL 29 + #define BLOCKER_TYPE_MUTEX 0x00UL 30 + #define BLOCKER_TYPE_SEM 0x01UL 31 + #define BLOCKER_TYPE_RWSEM_READER 0x02UL 32 + #define BLOCKER_TYPE_RWSEM_WRITER 0x03UL 33 33 34 - #define BLOCKER_TYPE_MASK 0x03UL 34 + #define BLOCKER_TYPE_MASK 0x03UL 35 35 36 36 #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER 37 37 static inline void hung_task_set_blocker(void *lock, unsigned long type)
+2 -2
include/linux/i3c/device.h
··· 245 245 * 246 246 * Return: 0 if both registrations succeeds, a negative error code otherwise. 247 247 */ 248 - static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv, 248 + static __always_inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv, 249 249 struct i2c_driver *i2cdrv) 250 250 { 251 251 int ret; ··· 270 270 * Note that when CONFIG_I3C is not enabled, this function only unregisters the 271 271 * @i2cdrv. 272 272 */ 273 - static inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv, 273 + static __always_inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv, 274 274 struct i2c_driver *i2cdrv) 275 275 { 276 276 if (IS_ENABLED(CONFIG_I3C))
+9 -4
include/linux/i3c/master.h
··· 249 249 */ 250 250 #define I3C_BUS_MAX_DEVS 11 251 251 252 - #define I3C_BUS_MAX_I3C_SCL_RATE 12900000 253 - #define I3C_BUS_TYP_I3C_SCL_RATE 12500000 254 - #define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000 255 - #define I3C_BUS_I2C_FM_SCL_RATE 400000 252 + /* Taken from the I3C Spec V1.1.1, chapter 6.2. "Timing specification" */ 253 + #define I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE 1000000 254 + #define I3C_BUS_I2C_FM_SCL_MAX_RATE 400000 255 + #define I3C_BUS_I3C_SCL_MAX_RATE 12900000 256 + #define I3C_BUS_I3C_SCL_TYP_RATE 12500000 257 + #define I3C_BUS_TAVAL_MIN_NS 1000 258 + #define I3C_BUS_TBUF_MIXED_FM_MIN_NS 1300 259 + #define I3C_BUS_THIGH_MIXED_MAX_NS 41 260 + #define I3C_BUS_TIDLE_MIN_NS 200000 256 261 #define I3C_BUS_TLOW_OD_MIN_NS 200 257 262 258 263 /**
+25
include/linux/input/touch-overlay.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (c) 2023 Javier Carrasco <javier.carrasco@wolfvision.net> 4 + */ 5 + 6 + #ifndef _TOUCH_OVERLAY 7 + #define _TOUCH_OVERLAY 8 + 9 + #include <linux/types.h> 10 + 11 + struct input_dev; 12 + 13 + int touch_overlay_map(struct list_head *list, struct input_dev *input); 14 + 15 + void touch_overlay_get_touchscreen_abs(struct list_head *list, u16 *x, u16 *y); 16 + 17 + bool touch_overlay_mapped_touchscreen(struct list_head *list); 18 + 19 + bool touch_overlay_process_contact(struct list_head *list, 20 + struct input_dev *input, 21 + struct input_mt_pos *pos, int slot); 22 + 23 + void touch_overlay_sync_frame(struct list_head *list, struct input_dev *input); 24 + 25 + #endif
-3
include/linux/io-mapping.h
··· 225 225 kfree(iomap); 226 226 } 227 227 228 - int io_mapping_map_user(struct io_mapping *iomap, struct vm_area_struct *vma, 229 - unsigned long addr, unsigned long pfn, unsigned long size); 230 - 231 228 #endif /* _LINUX_IO_MAPPING_H */
+4 -4
include/linux/jhash.h
··· 24 24 * Jozsef 25 25 */ 26 26 #include <linux/bitops.h> 27 - #include <linux/unaligned/packed_struct.h> 27 + #include <linux/unaligned.h> 28 28 29 29 /* Best hash sizes are of power of two */ 30 30 #define jhash_size(n) ((u32)1<<(n)) ··· 77 77 78 78 /* All but the last block: affect some 32 bits of (a,b,c) */ 79 79 while (length > 12) { 80 - a += __get_unaligned_cpu32(k); 81 - b += __get_unaligned_cpu32(k + 4); 82 - c += __get_unaligned_cpu32(k + 8); 80 + a += get_unaligned((u32 *)k); 81 + b += get_unaligned((u32 *)(k + 4)); 82 + c += get_unaligned((u32 *)(k + 8)); 83 83 __jhash_mix(a, b, c); 84 84 length -= 12; 85 85 k += 12;
+10
include/linux/kexec.h
··· 79 79 80 80 typedef unsigned long kimage_entry_t; 81 81 82 + /* 83 + * This is a copy of the UAPI struct kexec_segment and must be identical 84 + * to it because it gets copied straight from user space into kernel 85 + * memory. Do not modify this structure unless you change the way segments 86 + * get ingested from user space. 87 + */ 82 88 struct kexec_segment { 83 89 /* 84 90 * This pointer can point to user memory if kexec_load() system ··· 178 172 * @buf_align: Minimum alignment needed. 179 173 * @buf_min: The buffer can't be placed below this address. 180 174 * @buf_max: The buffer can't be placed above this address. 175 + * @cma: CMA page if the buffer is backed by CMA. 181 176 * @top_down: Allocate from top of memory. 182 177 * @random: Place the buffer at a random position. 183 178 */ ··· 191 184 unsigned long buf_align; 192 185 unsigned long buf_min; 193 186 unsigned long buf_max; 187 + struct page *cma; 194 188 bool top_down; 195 189 #ifdef CONFIG_CRASH_DUMP 196 190 bool random; ··· 348 340 349 341 unsigned long nr_segments; 350 342 struct kexec_segment segment[KEXEC_SEGMENT_MAX]; 343 + struct page *segment_cma[KEXEC_SEGMENT_MAX]; 351 344 352 345 struct list_head control_pages; 353 346 struct list_head dest_pages; ··· 370 361 */ 371 362 unsigned int hotplug_support:1; 372 363 #endif 364 + unsigned int no_cma:1; 373 365 374 366 #ifdef ARCH_HAS_KIMAGE_ARCH 375 367 struct kimage_arch arch;
+1
include/linux/libata.h
··· 545 545 546 546 extern struct device_attribute dev_attr_unload_heads; 547 547 #ifdef CONFIG_SATA_HOST 548 + extern struct device_attribute dev_attr_link_power_management_supported; 548 549 extern struct device_attribute dev_attr_link_power_management_policy; 549 550 extern struct device_attribute dev_attr_ncq_prio_supported; 550 551 extern struct device_attribute dev_attr_ncq_prio_enable;
+4 -2
include/linux/mm.h
··· 414 414 #endif 415 415 416 416 #ifdef CONFIG_64BIT 417 - /* VM is sealed, in vm_flags */ 418 - #define VM_SEALED _BITUL(63) 417 + #define VM_SEALED_BIT 42 418 + #define VM_SEALED BIT(VM_SEALED_BIT) 419 + #else 420 + #define VM_SEALED VM_NONE 419 421 #endif 420 422 421 423 /* Bits set in the VMA until the stack is in its final location */
+30
include/linux/mmap_lock.h
··· 12 12 #include <linux/tracepoint-defs.h> 13 13 #include <linux/types.h> 14 14 #include <linux/cleanup.h> 15 + #include <linux/sched/mm.h> 15 16 16 17 #define MMAP_LOCK_INITIALIZER(name) \ 17 18 .mmap_lock = __RWSEM_INITIALIZER((name).mmap_lock), ··· 155 154 * reused and attached to a different mm before we lock it. 156 155 * Returns the vma on success, NULL on failure to lock and EAGAIN if vma got 157 156 * detached. 157 + * 158 + * WARNING! The vma passed to this function cannot be used if the function 159 + * fails to lock it because in certain cases RCU lock is dropped and then 160 + * reacquired. Once RCU lock is dropped the vma can be concurently freed. 158 161 */ 159 162 static inline struct vm_area_struct *vma_start_read(struct mm_struct *mm, 160 163 struct vm_area_struct *vma) ··· 188 183 } 189 184 190 185 rwsem_acquire_read(&vma->vmlock_dep_map, 0, 1, _RET_IP_); 186 + 187 + /* 188 + * If vma got attached to another mm from under us, that mm is not 189 + * stable and can be freed in the narrow window after vma->vm_refcnt 190 + * is dropped and before rcuwait_wake_up(mm) is called. Grab it before 191 + * releasing vma->vm_refcnt. 192 + */ 193 + if (unlikely(vma->vm_mm != mm)) { 194 + /* Use a copy of vm_mm in case vma is freed after we drop vm_refcnt */ 195 + struct mm_struct *other_mm = vma->vm_mm; 196 + 197 + /* 198 + * __mmdrop() is a heavy operation and we don't need RCU 199 + * protection here. Release RCU lock during these operations. 200 + * We reinstate the RCU read lock as the caller expects it to 201 + * be held when this function returns even on error. 202 + */ 203 + rcu_read_unlock(); 204 + mmgrab(other_mm); 205 + vma_refcount_put(vma); 206 + mmdrop(other_mm); 207 + rcu_read_lock(); 208 + return NULL; 209 + } 210 + 191 211 /* 192 212 * Overflow of vm_lock_seq/mm_lock_seq might produce false locked result. 193 213 * False unlocked result is impossible because we modify and check
+11 -21
include/linux/module.h
··· 33 33 #include <linux/percpu.h> 34 34 #include <asm/module.h> 35 35 36 - #define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN 36 + #define MODULE_NAME_LEN __MODULE_NAME_LEN 37 37 38 38 struct modversion_info { 39 39 unsigned long crc; ··· 164 164 #endif /*CONFIG_MODULES*/ 165 165 166 166 struct module_kobject *lookup_or_create_module_kobject(const char *name); 167 - 168 - /* Generic info of form tag = "info" */ 169 - #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) 170 167 171 168 /* For userspace: you can also call me... */ 172 169 #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) ··· 299 302 #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, ns) 300 303 301 304 struct notifier_block; 302 - 303 - #ifdef CONFIG_MODULES 304 - 305 - /* Get/put a kernel symbol (calls must be symmetric) */ 306 - void *__symbol_get(const char *symbol); 307 - void *__symbol_get_gpl(const char *symbol); 308 - #define symbol_get(x) ({ \ 309 - static const char __notrim[] \ 310 - __used __section(".no_trim_symbol") = __stringify(x); \ 311 - (typeof(&x))(__symbol_get(__stringify(x))); }) 312 - 313 - /* modules using other modules: kdb wants to see this. */ 314 - struct module_use { 315 - struct list_head source_list; 316 - struct list_head target_list; 317 - struct module *source, *target; 318 - }; 319 305 320 306 enum module_state { 321 307 MODULE_STATE_LIVE, /* Normal state. */ ··· 583 603 #ifndef MODULE_ARCH_INIT 584 604 #define MODULE_ARCH_INIT {} 585 605 #endif 606 + 607 + #ifdef CONFIG_MODULES 608 + 609 + /* Get/put a kernel symbol (calls must be symmetric) */ 610 + void *__symbol_get(const char *symbol); 611 + void *__symbol_get_gpl(const char *symbol); 612 + #define symbol_get(x) ({ \ 613 + static const char __notrim[] \ 614 + __used __section(".no_trim_symbol") = __stringify(x); \ 615 + (typeof(&x))(__symbol_get(__stringify(x))); }) 586 616 587 617 #ifndef HAVE_ARCH_KALLSYMS_SYMBOL_VALUE 588 618 static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym)
+14 -10
include/linux/moduleparam.h
··· 6 6 #include <linux/stringify.h> 7 7 #include <linux/kernel.h> 8 8 9 + /* 10 + * The maximum module name length, including the NUL byte. 11 + * Chosen so that structs with an unsigned long line up, specifically 12 + * modversion_info. 13 + */ 14 + #define __MODULE_NAME_LEN (64 - sizeof(unsigned long)) 15 + 9 16 /* You can override this manually, but generally this should match the 10 17 module name. */ 11 18 #ifdef MODULE ··· 24 17 #define __MODULE_INFO_PREFIX KBUILD_MODNAME "." 25 18 #endif 26 19 27 - /* Chosen so that structs with an unsigned long line up. */ 28 - #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) 29 - 30 - #define __MODULE_INFO(tag, name, info) \ 31 - static const char __UNIQUE_ID(name)[] \ 20 + /* Generic info of form tag = "info" */ 21 + #define MODULE_INFO(tag, info) \ 22 + static const char __UNIQUE_ID(modinfo)[] \ 32 23 __used __section(".modinfo") __aligned(1) \ 33 24 = __MODULE_INFO_PREFIX __stringify(tag) "=" info 34 25 35 26 #define __MODULE_PARM_TYPE(name, _type) \ 36 - __MODULE_INFO(parmtype, name##type, #name ":" _type) 27 + MODULE_INFO(parmtype, #name ":" _type) 37 28 38 29 /* One for each parameter, describing how to use it. Some files do 39 30 multiple of these per line, so can't just use MODULE_INFO. */ 40 31 #define MODULE_PARM_DESC(_parm, desc) \ 41 - __MODULE_INFO(parm, _parm, #_parm ":" desc) 32 + MODULE_INFO(parm, #_parm ":" desc) 42 33 43 34 struct kernel_param; 44 35 ··· 287 282 #define __moduleparam_const const 288 283 #endif 289 284 290 - /* This is the fundamental function for registering boot/module 291 - parameters. */ 285 + /* This is the fundamental function for registering boot/module parameters. */ 292 286 #define __module_param_call(prefix, name, ops, arg, perm, level, flags) \ 293 - /* Default value instead of permissions? */ \ 287 + static_assert(sizeof(""prefix) - 1 <= __MODULE_NAME_LEN); \ 294 288 static const char __param_str_##name[] = prefix #name; \ 295 289 static struct kernel_param __moduleparam_const __param_##name \ 296 290 __used __section("__param") \
-2
include/linux/page-flags.h
··· 837 837 838 838 #define folio_start_writeback(folio) \ 839 839 __folio_start_writeback(folio, false) 840 - #define folio_start_writeback_keepwrite(folio) \ 841 - __folio_start_writeback(folio, true) 842 840 843 841 static __always_inline bool folio_test_head(const struct folio *folio) 844 842 {
+45
include/linux/pgtable.h
··· 736 736 } 737 737 #endif 738 738 739 + /** 740 + * get_and_clear_ptes - Clear present PTEs that map consecutive pages of 741 + * the same folio, collecting dirty/accessed bits. 742 + * @mm: Address space the pages are mapped into. 743 + * @addr: Address the first page is mapped at. 744 + * @ptep: Page table pointer for the first entry. 745 + * @nr: Number of entries to clear. 746 + * 747 + * Use this instead of get_and_clear_full_ptes() if it is known that we don't 748 + * need to clear the full mm, which is mostly the case. 749 + * 750 + * Note that PTE bits in the PTE range besides the PFN can differ. For example, 751 + * some PTEs might be write-protected. 752 + * 753 + * Context: The caller holds the page table lock. The PTEs map consecutive 754 + * pages that belong to the same folio. The PTEs are all in the same PMD. 755 + */ 756 + static inline pte_t get_and_clear_ptes(struct mm_struct *mm, unsigned long addr, 757 + pte_t *ptep, unsigned int nr) 758 + { 759 + return get_and_clear_full_ptes(mm, addr, ptep, nr, 0); 760 + } 761 + 739 762 #ifndef clear_full_ptes 740 763 /** 741 764 * clear_full_ptes - Clear present PTEs that map consecutive pages of the same ··· 790 767 } 791 768 } 792 769 #endif 770 + 771 + /** 772 + * clear_ptes - Clear present PTEs that map consecutive pages of the same folio. 773 + * @mm: Address space the pages are mapped into. 774 + * @addr: Address the first page is mapped at. 775 + * @ptep: Page table pointer for the first entry. 776 + * @nr: Number of entries to clear. 777 + * 778 + * Use this instead of clear_full_ptes() if it is known that we don't need to 779 + * clear the full mm, which is mostly the case. 780 + * 781 + * Note that PTE bits in the PTE range besides the PFN can differ. For example, 782 + * some PTEs might be write-protected. 783 + * 784 + * Context: The caller holds the page table lock. The PTEs map consecutive 785 + * pages that belong to the same folio. The PTEs are all in the same PMD. 786 + */ 787 + static inline void clear_ptes(struct mm_struct *mm, unsigned long addr, 788 + pte_t *ptep, unsigned int nr) 789 + { 790 + clear_full_ptes(mm, addr, ptep, nr, 0); 791 + } 793 792 794 793 /* 795 794 * If two threads concurrently fault at the same page, the thread that
+11 -1
include/linux/raid/pq.h
··· 11 11 #ifdef __KERNEL__ 12 12 13 13 #include <linux/blkdev.h> 14 + #include <linux/mm.h> 14 15 15 - extern const char raid6_empty_zero_page[PAGE_SIZE]; 16 + /* This should be const but the raid6 code is too convoluted for that. */ 17 + static inline void *raid6_get_zero_page(void) 18 + { 19 + return page_address(ZERO_PAGE(0)); 20 + } 16 21 17 22 #else /* ! __KERNEL__ */ 18 23 /* Used for testing in user space */ ··· 194 189 struct timeval tv; 195 190 gettimeofday(&tv, NULL); 196 191 return tv.tv_sec*1000 + tv.tv_usec/1000; 192 + } 193 + 194 + static inline void *raid6_get_zero_page(void) 195 + { 196 + return raid6_empty_zero_page; 197 197 } 198 198 199 199 #endif /* ! __KERNEL__ */
+19 -5
include/linux/relay.h
··· 29 29 #define RELAYFS_CHANNEL_VERSION 7 30 30 31 31 /* 32 + * Relay buffer statistics 33 + */ 34 + enum { 35 + RELAY_STATS_BUF_FULL = (1 << 0), 36 + RELAY_STATS_WRT_BIG = (1 << 1), 37 + 38 + RELAY_STATS_LAST = RELAY_STATS_WRT_BIG, 39 + }; 40 + 41 + struct rchan_buf_stats 42 + { 43 + unsigned int full_count; /* counter for buffer full */ 44 + unsigned int big_count; /* counter for too big to write */ 45 + }; 46 + 47 + /* 32 48 * Per-cpu relay channel buffer 33 49 */ 34 50 struct rchan_buf ··· 59 43 struct irq_work wakeup_work; /* reader wakeup */ 60 44 struct dentry *dentry; /* channel file dentry */ 61 45 struct kref kref; /* channel buffer refcount */ 46 + struct rchan_buf_stats stats; /* buffer stats */ 62 47 struct page **page_array; /* array of current buffer pages */ 63 48 unsigned int page_count; /* number of current buffer pages */ 64 49 unsigned int finalized; /* buffer has been finalized */ 65 50 size_t *padding; /* padding counts per sub-buffer */ 66 - size_t prev_padding; /* temporary variable */ 67 51 size_t bytes_consumed; /* bytes consumed in cur read subbuf */ 68 52 size_t early_bytes; /* bytes consumed before VFS inited */ 69 53 unsigned int cpu; /* this buf's cpu */ ··· 81 65 const struct rchan_callbacks *cb; /* client callbacks */ 82 66 struct kref kref; /* channel refcount */ 83 67 void *private_data; /* for user-defined data */ 84 - size_t last_toobig; /* tried to log event > subbuf size */ 85 68 struct rchan_buf * __percpu *buf; /* per-cpu channel buffers */ 86 69 int is_global; /* One global buffer ? */ 87 70 struct list_head list; /* for channel list */ ··· 99 84 * @buf: the channel buffer containing the new sub-buffer 100 85 * @subbuf: the start of the new sub-buffer 101 86 * @prev_subbuf: the start of the previous sub-buffer 102 - * @prev_padding: unused space at the end of previous sub-buffer 103 87 * 104 88 * The client should return 1 to continue logging, 0 to stop 105 89 * logging. ··· 114 100 */ 115 101 int (*subbuf_start) (struct rchan_buf *buf, 116 102 void *subbuf, 117 - void *prev_subbuf, 118 - size_t prev_padding); 103 + void *prev_subbuf); 119 104 120 105 /* 121 106 * create_buf_file - create file to represent a relay channel buffer ··· 174 161 void *private_data); 175 162 extern void relay_close(struct rchan *chan); 176 163 extern void relay_flush(struct rchan *chan); 164 + size_t relay_stats(struct rchan *chan, int flags); 177 165 extern void relay_subbufs_consumed(struct rchan *chan, 178 166 unsigned int cpu, 179 167 size_t consumed);
+3
include/linux/ring_buffer.h
··· 144 144 void ring_buffer_nest_start(struct trace_buffer *buffer); 145 145 void ring_buffer_nest_end(struct trace_buffer *buffer); 146 146 147 + DEFINE_GUARD(ring_buffer_nest, struct trace_buffer *, 148 + ring_buffer_nest_start(_T), ring_buffer_nest_end(_T)) 149 + 147 150 struct ring_buffer_event * 148 151 ring_buffer_peek(struct trace_buffer *buffer, int cpu, u64 *ts, 149 152 unsigned long *lost_events);
+22
include/linux/rmap.h
··· 449 449 default: 450 450 VM_WARN_ON_ONCE(true); 451 451 } 452 + 453 + /* 454 + * Anon folios must have an associated live anon_vma as long as they're 455 + * mapped into userspace. 456 + * Note that the atomic_read() mainly does two things: 457 + * 458 + * 1. In KASAN builds with CONFIG_SLUB_RCU_DEBUG, it causes KASAN to 459 + * check that the associated anon_vma has not yet been freed (subject 460 + * to KASAN's usual limitations). This check will pass if the 461 + * anon_vma's refcount has already dropped to 0 but an RCU grace 462 + * period hasn't passed since then. 463 + * 2. If the anon_vma has not yet been freed, it checks that the 464 + * anon_vma still has a nonzero refcount (as opposed to being in the 465 + * middle of an RCU delay for getting freed). 466 + */ 467 + if (folio_test_anon(folio) && !folio_test_ksm(folio)) { 468 + unsigned long mapping = (unsigned long)folio->mapping; 469 + struct anon_vma *anon_vma; 470 + 471 + anon_vma = (void *)(mapping - FOLIO_MAPPING_ANON); 472 + VM_WARN_ON_FOLIO(atomic_read(&anon_vma->refcount) == 0, folio); 473 + } 452 474 } 453 475 454 476 /*
+1 -1
include/linux/rtc/ds1685.h
··· 8 8 * include larger, battery-backed NV-SRAM, burst-mode access, and an RTC 9 9 * write counter. 10 10 * 11 - * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>. 11 + * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>. 12 12 * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>. 13 13 * 14 14 * References:
+12
include/linux/rwsem.h
··· 132 132 return !list_empty(&sem->wait_list); 133 133 } 134 134 135 + #if defined(CONFIG_DEBUG_RWSEMS) || defined(CONFIG_DETECT_HUNG_TASK_BLOCKER) 136 + /* 137 + * Return just the real task structure pointer of the owner 138 + */ 139 + extern struct task_struct *rwsem_owner(struct rw_semaphore *sem); 140 + 141 + /* 142 + * Return true if the rwsem is owned by a reader. 143 + */ 144 + extern bool is_rwsem_reader_owned(struct rw_semaphore *sem); 145 + #endif 146 + 135 147 #else /* !CONFIG_PREEMPT_RT */ 136 148 137 149 #include <linux/rwbase_rt.h>
+1 -1
include/linux/sprintf.h
··· 23 23 24 24 /* These are for specific cases, do not use without real need */ 25 25 extern bool no_hash_pointers; 26 - int no_hash_pointers_enable(char *str); 26 + void hash_pointers_finalize(bool slub_debug); 27 27 28 28 /* Used for Rust formatting ('%pA') */ 29 29 char *rust_fmt_argument(char *buf, char *end, const void *ptr);
+28
include/linux/sys_info.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_SYS_INFO_H 3 + #define _LINUX_SYS_INFO_H 4 + 5 + #include <linux/sysctl.h> 6 + 7 + /* 8 + * SYS_INFO_PANIC_CONSOLE_REPLAY is for panic case only, as it needs special 9 + * handling which only fits panic case. 10 + */ 11 + #define SYS_INFO_TASKS 0x00000001 12 + #define SYS_INFO_MEM 0x00000002 13 + #define SYS_INFO_TIMERS 0x00000004 14 + #define SYS_INFO_LOCKS 0x00000008 15 + #define SYS_INFO_FTRACE 0x00000010 16 + #define SYS_INFO_PANIC_CONSOLE_REPLAY 0x00000020 17 + #define SYS_INFO_ALL_CPU_BT 0x00000040 18 + #define SYS_INFO_BLOCKED_TASKS 0x00000080 19 + 20 + void sys_info(unsigned long si_mask); 21 + unsigned long sys_info_parse_param(char *str); 22 + 23 + #ifdef CONFIG_SYSCTL 24 + int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write, 25 + void *buffer, size_t *lenp, 26 + loff_t *ppos); 27 + #endif 28 + #endif /* _LINUX_SYS_INFO_H */
+4
include/linux/vfio.h
··· 105 105 * @match: Optional device name match callback (return: 0 for no-match, >0 for 106 106 * match, -errno for abort (ex. match with insufficient or incorrect 107 107 * additional args) 108 + * @match_token_uuid: Optional device token match/validation. Return 0 109 + * if the uuid is valid for the device, -errno otherwise. uuid is NULL 110 + * if none was provided. 108 111 * @dma_unmap: Called when userspace unmaps IOVA from the container 109 112 * this device is attached to. 110 113 * @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl ··· 135 132 int (*mmap)(struct vfio_device *vdev, struct vm_area_struct *vma); 136 133 void (*request)(struct vfio_device *vdev, unsigned int count); 137 134 int (*match)(struct vfio_device *vdev, char *buf); 135 + int (*match_token_uuid)(struct vfio_device *vdev, const uuid_t *uuid); 138 136 void (*dma_unmap)(struct vfio_device *vdev, u64 iova, u64 length); 139 137 int (*device_feature)(struct vfio_device *device, u32 flags, 140 138 void __user *arg, size_t argsz);
+2
include/linux/vfio_pci_core.h
··· 122 122 int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma); 123 123 void vfio_pci_core_request(struct vfio_device *core_vdev, unsigned int count); 124 124 int vfio_pci_core_match(struct vfio_device *core_vdev, char *buf); 125 + int vfio_pci_core_match_token_uuid(struct vfio_device *core_vdev, 126 + const uuid_t *uuid); 125 127 int vfio_pci_core_enable(struct vfio_pci_core_device *vdev); 126 128 void vfio_pci_core_disable(struct vfio_pci_core_device *vdev); 127 129 void vfio_pci_core_finish_enable(struct vfio_pci_core_device *vdev);
-26
include/linux/xxhash.h
··· 178 178 void xxh32_reset(struct xxh32_state *state, uint32_t seed); 179 179 180 180 /** 181 - * xxh32_update() - hash the data given and update the xxh32 state 182 - * 183 - * @state: The xxh32 state to update. 184 - * @input: The data to hash. 185 - * @length: The length of the data to hash. 186 - * 187 - * After calling xxh32_reset() call xxh32_update() as many times as necessary. 188 - * 189 - * Return: Zero on success, otherwise an error code. 190 - */ 191 - int xxh32_update(struct xxh32_state *state, const void *input, size_t length); 192 - 193 - /** 194 - * xxh32_digest() - produce the current xxh32 hash 195 - * 196 - * @state: Produce the current xxh32 hash of this state. 197 - * 198 - * A hash value can be produced at any time. It is still possible to continue 199 - * inserting input into the hash state after a call to xxh32_digest(), and 200 - * generate new hashes later on, by calling xxh32_digest() again. 201 - * 202 - * Return: The xxh32 hash stored in the state. 203 - */ 204 - uint32_t xxh32_digest(const struct xxh32_state *state); 205 - 206 - /** 207 181 * xxh64_reset() - reset the xxh64 state to start a new hashing operation 208 182 * 209 183 * @state: The xxh64 state to reset.
+2 -2
include/net/tcp.h
··· 2655 2655 void (*write_space)(struct sock *sk)); 2656 2656 2657 2657 #define MODULE_ALIAS_TCP_ULP(name) \ 2658 - __MODULE_INFO(alias, alias_userspace, name); \ 2659 - __MODULE_INFO(alias, alias_tcp_ulp, "tcp-ulp-" name) 2658 + MODULE_INFO(alias, name); \ 2659 + MODULE_INFO(alias, "tcp-ulp-" name) 2660 2660 2661 2661 #ifdef CONFIG_NET_SOCK_MSG 2662 2662 struct sk_msg;
+13 -78
include/scsi/sas_ata.h
··· 15 15 16 16 #ifdef CONFIG_SCSI_SAS_ATA 17 17 18 - static inline int dev_is_sata(struct domain_device *dev) 18 + static inline bool dev_is_sata(struct domain_device *dev) 19 19 { 20 - return dev->dev_type == SAS_SATA_DEV || dev->dev_type == SAS_SATA_PM || 21 - dev->dev_type == SAS_SATA_PM_PORT || dev->dev_type == SAS_SATA_PENDING; 20 + switch (dev->dev_type) { 21 + case SAS_SATA_DEV: 22 + case SAS_SATA_PENDING: 23 + case SAS_SATA_PM: 24 + case SAS_SATA_PM_PORT: 25 + return true; 26 + default: 27 + return false; 28 + } 22 29 } 23 30 24 - int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy); 25 - int sas_ata_init(struct domain_device *dev); 26 - void sas_ata_task_abort(struct sas_task *task); 27 - void sas_ata_strategy_handler(struct Scsi_Host *shost); 28 - void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q); 29 31 void sas_ata_schedule_reset(struct domain_device *dev); 30 - void sas_ata_wait_eh(struct domain_device *dev); 31 - void sas_probe_sata(struct asd_sas_port *port); 32 - void sas_suspend_sata(struct asd_sas_port *port); 33 - void sas_resume_sata(struct asd_sas_port *port); 34 - void sas_ata_end_eh(struct ata_port *ap); 35 32 void sas_ata_device_link_abort(struct domain_device *dev, bool force_reset); 36 - int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, 37 - int force_phy_id); 33 + int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id); 38 34 int smp_ata_check_ready_type(struct ata_link *link); 39 - int sas_discover_sata(struct domain_device *dev); 40 - int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, 41 - struct domain_device *child, int phy_id); 42 35 43 36 extern const struct attribute_group sas_ata_sdev_attr_group; 44 37 45 38 #else 46 39 47 - static inline void sas_ata_disabled_notice(void) 40 + static inline bool dev_is_sata(struct domain_device *dev) 48 41 { 49 - pr_notice_once("ATA device seen but CONFIG_SCSI_SAS_ATA=N\n"); 50 - } 51 - 52 - static inline int dev_is_sata(struct domain_device *dev) 53 - { 54 - return 0; 55 - } 56 - static inline int sas_ata_init(struct domain_device *dev) 57 - { 58 - return 0; 59 - } 60 - static inline void sas_ata_task_abort(struct sas_task *task) 61 - { 62 - } 63 - 64 - static inline void sas_ata_strategy_handler(struct Scsi_Host *shost) 65 - { 66 - } 67 - 68 - static inline void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q) 69 - { 42 + return false; 70 43 } 71 44 72 45 static inline void sas_ata_schedule_reset(struct domain_device *dev) 73 - { 74 - } 75 - 76 - static inline void sas_ata_wait_eh(struct domain_device *dev) 77 - { 78 - } 79 - 80 - static inline void sas_probe_sata(struct asd_sas_port *port) 81 - { 82 - } 83 - 84 - static inline void sas_suspend_sata(struct asd_sas_port *port) 85 - { 86 - } 87 - 88 - static inline void sas_resume_sata(struct asd_sas_port *port) 89 - { 90 - } 91 - 92 - static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) 93 - { 94 - return 0; 95 - } 96 - 97 - static inline void sas_ata_end_eh(struct ata_port *ap) 98 46 { 99 47 } 100 48 ··· 60 112 static inline int smp_ata_check_ready_type(struct ata_link *link) 61 113 { 62 114 return 0; 63 - } 64 - 65 - static inline int sas_discover_sata(struct domain_device *dev) 66 - { 67 - sas_ata_disabled_notice(); 68 - return -ENXIO; 69 - } 70 - 71 - static inline int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, 72 - struct domain_device *child, int phy_id) 73 - { 74 - sas_ata_disabled_notice(); 75 - return -ENODEV; 76 115 } 77 116 78 117 #define sas_ata_sdev_attr_group ((struct attribute_group) {})
+8
include/uapi/linux/input-event-codes.h
··· 601 601 #define BTN_DPAD_LEFT 0x222 602 602 #define BTN_DPAD_RIGHT 0x223 603 603 604 + #define BTN_GRIPL 0x224 605 + #define BTN_GRIPR 0x225 606 + #define BTN_GRIPL2 0x226 607 + #define BTN_GRIPR2 0x227 608 + 604 609 #define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ 605 610 #define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */ 606 611 #define KEY_REFRESH_RATE_TOGGLE 0x232 /* Display refresh rate toggle */ ··· 769 764 #define KEY_KBD_LCD_MENU3 0x2ba 770 765 #define KEY_KBD_LCD_MENU4 0x2bb 771 766 #define KEY_KBD_LCD_MENU5 0x2bc 767 + 768 + /* Performance Boost key (Alienware)/G-Mode key (Dell) */ 769 + #define KEY_PERFORMANCE 0x2bd 772 770 773 771 #define BTN_TRIGGER_HAPPY 0x2c0 774 772 #define BTN_TRIGGER_HAPPY1 0x2c0
+1
include/uapi/linux/kexec.h
··· 27 27 #define KEXEC_FILE_ON_CRASH 0x00000002 28 28 #define KEXEC_FILE_NO_INITRAMFS 0x00000004 29 29 #define KEXEC_FILE_DEBUG 0x00000008 30 + #define KEXEC_FILE_NO_CMA 0x00000010 30 31 31 32 /* These values match the ELF architecture values. 32 33 * Unless there is a good reason that should continue to be the case.
+11 -1
include/uapi/linux/vfio.h
··· 905 905 * VFIO_DEVICE_BIND_IOMMUFD - _IOR(VFIO_TYPE, VFIO_BASE + 18, 906 906 * struct vfio_device_bind_iommufd) 907 907 * @argsz: User filled size of this data. 908 - * @flags: Must be 0. 908 + * @flags: Must be 0 or a bit flags of VFIO_DEVICE_BIND_* 909 909 * @iommufd: iommufd to bind. 910 910 * @out_devid: The device id generated by this bind. devid is a handle for 911 911 * this device/iommufd bond and can be used in IOMMUFD commands. 912 + * @token_uuid_ptr: Valid if VFIO_DEVICE_BIND_FLAG_TOKEN. Points to a 16 byte 913 + * UUID in the same format as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN. 912 914 * 913 915 * Bind a vfio_device to the specified iommufd. 914 916 * ··· 919 917 * 920 918 * Unbind is automatically conducted when device fd is closed. 921 919 * 920 + * A token is sometimes required to open the device, unless this is known to be 921 + * needed VFIO_DEVICE_BIND_FLAG_TOKEN should not be set and token_uuid_ptr is 922 + * ignored. The only case today is a PF/VF relationship where the VF bind must 923 + * be provided the same token as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN provided to 924 + * the PF. 925 + * 922 926 * Return: 0 on success, -errno on failure. 923 927 */ 924 928 struct vfio_device_bind_iommufd { 925 929 __u32 argsz; 926 930 __u32 flags; 931 + #define VFIO_DEVICE_BIND_FLAG_TOKEN (1 << 0) 927 932 __s32 iommufd; 928 933 __u32 out_devid; 934 + __aligned_u64 token_uuid_ptr; 929 935 }; 930 936 931 937 #define VFIO_DEVICE_BIND_IOMMUFD _IO(VFIO_TYPE, VFIO_BASE + 18)
+1 -1
include/xen/xenbus.h
··· 178 178 * sprintf-style type string, and pointer. Returns 0 or errno.*/ 179 179 int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); 180 180 181 - /* notifer routines for when the xenstore comes up */ 181 + /* notifier routines for when the xenstore comes up */ 182 182 extern int xenstored_ready; 183 183 int register_xenstore_notifier(struct notifier_block *nb); 184 184 void unregister_xenstore_notifier(struct notifier_block *nb);
+4
init/Kconfig
··· 172 172 173 173 config BROKEN 174 174 bool 175 + help 176 + This option allows you to choose whether you want to try to 177 + compile (and fix) old drivers that haven't been updated to 178 + new infrastructure. 175 179 176 180 config BROKEN_ON_SMP 177 181 bool
+5 -1
init/main.c
··· 1587 1587 * check if there is an early userspace init. If yes, let it do all 1588 1588 * the work 1589 1589 */ 1590 - if (init_eaccess(ramdisk_execute_command) != 0) { 1590 + int ramdisk_command_access; 1591 + ramdisk_command_access = init_eaccess(ramdisk_execute_command); 1592 + if (ramdisk_command_access != 0) { 1593 + pr_warn("check access for rdinit=%s failed: %i, ignoring\n", 1594 + ramdisk_execute_command, ramdisk_command_access); 1591 1595 ramdisk_execute_command = NULL; 1592 1596 prepare_namespace(); 1593 1597 }
+2
kernel/.gitignore
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 /config_data 3 3 /kheaders.md5 4 + /kheaders-objlist 5 + /kheaders-srclist
+42 -5
kernel/Makefile
··· 159 159 $(obj)/config_data: $(KCONFIG_CONFIG) FORCE 160 160 $(call filechk,cat) 161 161 162 + # kheaders_data.tar.xz 162 163 $(obj)/kheaders.o: $(obj)/kheaders_data.tar.xz 163 164 164 - quiet_cmd_genikh = CHK $(obj)/kheaders_data.tar.xz 165 - cmd_genikh = $(CONFIG_SHELL) $(srctree)/kernel/gen_kheaders.sh $@ 166 - $(obj)/kheaders_data.tar.xz: FORCE 167 - $(call cmd,genikh) 165 + quiet_cmd_kheaders_data = GEN $@ 166 + cmd_kheaders_data = "$<" "$@" "$(obj)/kheaders-srclist" "$(obj)/kheaders-objlist" "$(KBUILD_BUILD_TIMESTAMP)" 167 + cmd_kheaders_data_dep = cat $(depfile) >> $(dot-target).cmd; rm -f $(depfile) 168 168 169 - clean-files := kheaders_data.tar.xz kheaders.md5 169 + define rule_kheaders_data 170 + $(call cmd_and_savecmd,kheaders_data) 171 + $(call cmd,kheaders_data_dep) 172 + endef 173 + 174 + targets += kheaders_data.tar.xz 175 + $(obj)/kheaders_data.tar.xz: $(src)/gen_kheaders.sh $(obj)/kheaders-srclist $(obj)/kheaders-objlist $(obj)/kheaders.md5 FORCE 176 + $(call if_changed_rule,kheaders_data) 177 + 178 + # generated headers in objtree 179 + # 180 + # include/generated/utsversion.h is ignored because it is generated 181 + # after gen_kheaders.sh is executed. (utsversion.h is unneeded for kheaders) 182 + filechk_kheaders_objlist = \ 183 + for d in include "arch/$(SRCARCH)/include"; do \ 184 + find "$${d}/generated" ! -path "include/generated/utsversion.h" -a -name "*.h" -print; \ 185 + done 186 + 187 + $(obj)/kheaders-objlist: FORCE 188 + $(call filechk,kheaders_objlist) 189 + 190 + # non-generated headers in srctree 191 + filechk_kheaders_srclist = \ 192 + for d in include "arch/$(SRCARCH)/include"; do \ 193 + find "$(srctree)/$${d}" -path "$(srctree)/$${d}/generated" -prune -o -name "*.h" -print; \ 194 + done 195 + 196 + $(obj)/kheaders-srclist: FORCE 197 + $(call filechk,kheaders_srclist) 198 + 199 + # Some files are symlinks. If symlinks are changed, kheaders_data.tar.xz should 200 + # be rebuilt. 201 + filechk_kheaders_md5sum = xargs -r -a $< stat -c %N | md5sum 202 + 203 + $(obj)/kheaders.md5: $(obj)/kheaders-srclist FORCE 204 + $(call filechk,kheaders_md5sum) 205 + 206 + clean-files := kheaders.md5 kheaders-srclist kheaders-objlist
+15
kernel/crash_core.c
··· 21 21 #include <linux/reboot.h> 22 22 #include <linux/btf.h> 23 23 #include <linux/objtool.h> 24 + #include <linux/delay.h> 24 25 25 26 #include <asm/page.h> 26 27 #include <asm/sections.h> ··· 33 32 34 33 /* Per cpu memory for storing cpu states in case of system crash. */ 35 34 note_buf_t __percpu *crash_notes; 35 + 36 + /* time to wait for possible DMA to finish before starting the kdump kernel 37 + * when a CMA reservation is used 38 + */ 39 + #define CMA_DMA_TIMEOUT_SEC 10 36 40 37 41 #ifdef CONFIG_CRASH_DUMP 38 42 ··· 103 97 } 104 98 EXPORT_SYMBOL_GPL(kexec_crash_loaded); 105 99 100 + static void crash_cma_clear_pending_dma(void) 101 + { 102 + if (!crashk_cma_cnt) 103 + return; 104 + 105 + mdelay(CMA_DMA_TIMEOUT_SEC * 1000); 106 + } 107 + 106 108 /* 107 109 * No panic_cpu check version of crash_kexec(). This function is called 108 110 * only when panic_cpu holds the current CPU number; this is the only CPU ··· 133 119 crash_setup_regs(&fixed_regs, regs); 134 120 crash_save_vmcoreinfo(); 135 121 machine_crash_shutdown(&fixed_regs); 122 + crash_cma_clear_pending_dma(); 136 123 machine_kexec(kexec_crash_image); 137 124 } 138 125 kexec_unlock();
+66 -2
kernel/crash_reserve.c
··· 14 14 #include <linux/cpuhotplug.h> 15 15 #include <linux/memblock.h> 16 16 #include <linux/kmemleak.h> 17 + #include <linux/cma.h> 18 + #include <linux/crash_reserve.h> 17 19 18 20 #include <asm/page.h> 19 21 #include <asm/sections.h> ··· 174 172 175 173 #define SUFFIX_HIGH 0 176 174 #define SUFFIX_LOW 1 177 - #define SUFFIX_NULL 2 175 + #define SUFFIX_CMA 2 176 + #define SUFFIX_NULL 3 178 177 static __initdata char *suffix_tbl[] = { 179 178 [SUFFIX_HIGH] = ",high", 180 179 [SUFFIX_LOW] = ",low", 180 + [SUFFIX_CMA] = ",cma", 181 181 [SUFFIX_NULL] = NULL, 182 182 }; 183 183 184 184 /* 185 185 * That function parses "suffix" crashkernel command lines like 186 186 * 187 - * crashkernel=size,[high|low] 187 + * crashkernel=size,[high|low|cma] 188 188 * 189 189 * It returns 0 on success and -EINVAL on failure. 190 190 */ ··· 302 298 unsigned long long *crash_size, 303 299 unsigned long long *crash_base, 304 300 unsigned long long *low_size, 301 + unsigned long long *cma_size, 305 302 bool *high) 306 303 { 307 304 int ret; 305 + unsigned long long __always_unused cma_base; 308 306 309 307 /* crashkernel=X[@offset] */ 310 308 ret = __parse_crashkernel(cmdline, system_ram, crash_size, ··· 337 331 338 332 *high = true; 339 333 } 334 + 335 + /* 336 + * optional CMA reservation 337 + * cma_base is ignored 338 + */ 339 + if (cma_size) 340 + __parse_crashkernel(cmdline, 0, cma_size, 341 + &cma_base, suffix_tbl[SUFFIX_CMA]); 340 342 #endif 341 343 if (!*crash_size) 342 344 ret = -EINVAL; ··· 470 456 insert_resource(&iomem_resource, &crashk_res); 471 457 #endif 472 458 } 459 + 460 + struct range crashk_cma_ranges[CRASHKERNEL_CMA_RANGES_MAX]; 461 + #ifdef CRASHKERNEL_CMA 462 + int crashk_cma_cnt; 463 + void __init reserve_crashkernel_cma(unsigned long long cma_size) 464 + { 465 + unsigned long long request_size = roundup(cma_size, PAGE_SIZE); 466 + unsigned long long reserved_size = 0; 467 + 468 + if (!cma_size) 469 + return; 470 + 471 + while (cma_size > reserved_size && 472 + crashk_cma_cnt < CRASHKERNEL_CMA_RANGES_MAX) { 473 + 474 + struct cma *res; 475 + 476 + if (cma_declare_contiguous(0, request_size, 0, 0, 0, false, 477 + "crashkernel", &res)) { 478 + /* reservation failed, try half-sized blocks */ 479 + if (request_size <= PAGE_SIZE) 480 + break; 481 + 482 + request_size = roundup(request_size / 2, PAGE_SIZE); 483 + continue; 484 + } 485 + 486 + crashk_cma_ranges[crashk_cma_cnt].start = cma_get_base(res); 487 + crashk_cma_ranges[crashk_cma_cnt].end = 488 + crashk_cma_ranges[crashk_cma_cnt].start + 489 + cma_get_size(res) - 1; 490 + ++crashk_cma_cnt; 491 + reserved_size += request_size; 492 + } 493 + 494 + if (cma_size > reserved_size) 495 + pr_warn("crashkernel CMA reservation failed: %lld MB requested, %lld MB reserved in %d ranges\n", 496 + cma_size >> 20, reserved_size >> 20, crashk_cma_cnt); 497 + else 498 + pr_info("crashkernel CMA reserved: %lld MB in %d ranges\n", 499 + reserved_size >> 20, crashk_cma_cnt); 500 + } 501 + 502 + #else /* CRASHKERNEL_CMA */ 503 + void __init reserve_crashkernel_cma(unsigned long long cma_size) 504 + { 505 + if (cma_size) 506 + pr_warn("crashkernel CMA reservation not supported\n"); 507 + } 508 + #endif 473 509 474 510 #ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY 475 511 static __init int insert_crashkernel_resources(void)
+28 -8
kernel/events/core.c
··· 6842 6842 return vmf->pgoff == 0 ? 0 : VM_FAULT_SIGBUS; 6843 6843 } 6844 6844 6845 + static int perf_mmap_may_split(struct vm_area_struct *vma, unsigned long addr) 6846 + { 6847 + /* 6848 + * Forbid splitting perf mappings to prevent refcount leaks due to 6849 + * the resulting non-matching offsets and sizes. See open()/close(). 6850 + */ 6851 + return -EINVAL; 6852 + } 6853 + 6845 6854 static const struct vm_operations_struct perf_mmap_vmops = { 6846 6855 .open = perf_mmap_open, 6847 6856 .close = perf_mmap_close, /* non mergeable */ 6848 6857 .pfn_mkwrite = perf_mmap_pfn_mkwrite, 6858 + .may_split = perf_mmap_may_split, 6849 6859 }; 6850 6860 6851 6861 static int map_range(struct perf_buffer *rb, struct vm_area_struct *vma) ··· 7061 7051 ret = 0; 7062 7052 goto unlock; 7063 7053 } 7064 - 7065 - atomic_set(&rb->aux_mmap_count, 1); 7066 7054 } 7067 7055 7068 7056 user_lock_limit = sysctl_perf_event_mlock >> (PAGE_SHIFT - 10); ··· 7123 7115 perf_event_update_time(event); 7124 7116 perf_event_init_userpage(event); 7125 7117 perf_event_update_userpage(event); 7118 + ret = 0; 7126 7119 } else { 7127 7120 ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, 7128 7121 event->attr.aux_watermark, flags); 7129 - if (!ret) 7122 + if (!ret) { 7123 + atomic_set(&rb->aux_mmap_count, 1); 7130 7124 rb->aux_mmap_locked = extra; 7125 + } 7131 7126 } 7132 - 7133 - ret = 0; 7134 7127 7135 7128 unlock: 7136 7129 if (!ret) { ··· 7140 7131 7141 7132 atomic_inc(&event->mmap_count); 7142 7133 } else if (rb) { 7134 + /* AUX allocation failed */ 7143 7135 atomic_dec(&rb->mmap_count); 7144 7136 } 7145 7137 aux_unlock: 7146 7138 if (aux_mutex) 7147 7139 mutex_unlock(aux_mutex); 7148 7140 mutex_unlock(&event->mmap_mutex); 7141 + 7142 + if (ret) 7143 + return ret; 7149 7144 7150 7145 /* 7151 7146 * Since pinned accounting is per vm we cannot allow fork() to copy our ··· 7158 7145 vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP); 7159 7146 vma->vm_ops = &perf_mmap_vmops; 7160 7147 7161 - if (!ret) 7162 - ret = map_range(rb, vma); 7163 - 7164 7148 mapped = get_mapped(event, event_mapped); 7165 7149 if (mapped) 7166 7150 mapped(event, vma->vm_mm); 7151 + 7152 + /* 7153 + * Try to map it into the page table. On fail, invoke 7154 + * perf_mmap_close() to undo the above, as the callsite expects 7155 + * full cleanup in this case and therefore does not invoke 7156 + * vmops::close(). 7157 + */ 7158 + ret = map_range(rb, vma); 7159 + if (ret) 7160 + perf_mmap_close(vma); 7167 7161 7168 7162 return ret; 7169 7163 }
+2 -2
kernel/events/uprobes.c
··· 580 580 581 581 out: 582 582 /* Revert back reference counter if instruction update failed. */ 583 - if (ret < 0 && is_register && ref_ctr_updated) 584 - update_ref_ctr(uprobe, mm, -1); 583 + if (ret < 0 && ref_ctr_updated) 584 + update_ref_ctr(uprobe, mm, is_register ? -1 : 1); 585 585 586 586 /* try collapse pmd for compound page */ 587 587 if (ret > 0)
+1 -6
kernel/exit.c
··· 693 693 } 694 694 695 695 /* 696 - * This does two things: 697 - * 698 - * A. Make init inherit all the child processes 699 - * B. Check to see if any process groups have become orphaned 700 - * as a result of our exiting, and if they have any stopped 701 - * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) 696 + * Make init inherit all the child processes 702 697 */ 703 698 static void forget_original_parent(struct task_struct *father, 704 699 struct list_head *dead)
+53 -51
kernel/fork.c
··· 189 189 kmem_cache_free(task_struct_cachep, tsk); 190 190 } 191 191 192 - /* 193 - * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a 194 - * kmemcache based allocator. 195 - */ 196 - # if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK) 197 - 198 - # ifdef CONFIG_VMAP_STACK 192 + #ifdef CONFIG_VMAP_STACK 199 193 /* 200 194 * vmalloc() is a bit slow, and calling vfree() enough times will force a TLB 201 195 * flush. Try to minimize the number of calls by caching stacks. 202 196 */ 203 197 #define NR_CACHED_STACKS 2 204 198 static DEFINE_PER_CPU(struct vm_struct *, cached_stacks[NR_CACHED_STACKS]); 199 + /* 200 + * Allocated stacks are cached and later reused by new threads, so memcg 201 + * accounting is performed by the code assigning/releasing stacks to tasks. 202 + * We need a zeroed memory without __GFP_ACCOUNT. 203 + */ 204 + #define GFP_VMAP_STACK (GFP_KERNEL | __GFP_ZERO) 205 205 206 206 struct vm_stack { 207 207 struct rcu_head rcu; 208 208 struct vm_struct *stack_vm_area; 209 209 }; 210 210 211 - static bool try_release_thread_stack_to_cache(struct vm_struct *vm) 211 + static bool try_release_thread_stack_to_cache(struct vm_struct *vm_area) 212 212 { 213 213 unsigned int i; 214 214 215 215 for (i = 0; i < NR_CACHED_STACKS; i++) { 216 216 struct vm_struct *tmp = NULL; 217 217 218 - if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm)) 218 + if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm_area)) 219 219 return true; 220 220 } 221 221 return false; ··· 224 224 static void thread_stack_free_rcu(struct rcu_head *rh) 225 225 { 226 226 struct vm_stack *vm_stack = container_of(rh, struct vm_stack, rcu); 227 + struct vm_struct *vm_area = vm_stack->stack_vm_area; 227 228 228 229 if (try_release_thread_stack_to_cache(vm_stack->stack_vm_area)) 229 230 return; 230 231 231 - vfree(vm_stack); 232 + vfree(vm_area->addr); 232 233 } 233 234 234 235 static void thread_stack_delayed_free(struct task_struct *tsk) ··· 242 241 243 242 static int free_vm_stack_cache(unsigned int cpu) 244 243 { 245 - struct vm_struct **cached_vm_stacks = per_cpu_ptr(cached_stacks, cpu); 244 + struct vm_struct **cached_vm_stack_areas = per_cpu_ptr(cached_stacks, cpu); 246 245 int i; 247 246 248 247 for (i = 0; i < NR_CACHED_STACKS; i++) { 249 - struct vm_struct *vm_stack = cached_vm_stacks[i]; 248 + struct vm_struct *vm_area = cached_vm_stack_areas[i]; 250 249 251 - if (!vm_stack) 250 + if (!vm_area) 252 251 continue; 253 252 254 - vfree(vm_stack->addr); 255 - cached_vm_stacks[i] = NULL; 253 + vfree(vm_area->addr); 254 + cached_vm_stack_areas[i] = NULL; 256 255 } 257 256 258 257 return 0; 259 258 } 260 259 261 - static int memcg_charge_kernel_stack(struct vm_struct *vm) 260 + static int memcg_charge_kernel_stack(struct vm_struct *vm_area) 262 261 { 263 262 int i; 264 263 int ret; 265 264 int nr_charged = 0; 266 265 267 - BUG_ON(vm->nr_pages != THREAD_SIZE / PAGE_SIZE); 266 + BUG_ON(vm_area->nr_pages != THREAD_SIZE / PAGE_SIZE); 268 267 269 268 for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++) { 270 - ret = memcg_kmem_charge_page(vm->pages[i], GFP_KERNEL, 0); 269 + ret = memcg_kmem_charge_page(vm_area->pages[i], GFP_KERNEL, 0); 271 270 if (ret) 272 271 goto err; 273 272 nr_charged++; ··· 275 274 return 0; 276 275 err: 277 276 for (i = 0; i < nr_charged; i++) 278 - memcg_kmem_uncharge_page(vm->pages[i], 0); 277 + memcg_kmem_uncharge_page(vm_area->pages[i], 0); 279 278 return ret; 280 279 } 281 280 282 281 static int alloc_thread_stack_node(struct task_struct *tsk, int node) 283 282 { 284 - struct vm_struct *vm; 283 + struct vm_struct *vm_area; 285 284 void *stack; 286 285 int i; 287 286 288 287 for (i = 0; i < NR_CACHED_STACKS; i++) { 289 - struct vm_struct *s; 290 - 291 - s = this_cpu_xchg(cached_stacks[i], NULL); 292 - 293 - if (!s) 288 + vm_area = this_cpu_xchg(cached_stacks[i], NULL); 289 + if (!vm_area) 294 290 continue; 295 291 296 292 /* Reset stack metadata. */ 297 - kasan_unpoison_range(s->addr, THREAD_SIZE); 293 + kasan_unpoison_range(vm_area->addr, THREAD_SIZE); 298 294 299 - stack = kasan_reset_tag(s->addr); 295 + stack = kasan_reset_tag(vm_area->addr); 300 296 301 297 /* Clear stale pointers from reused stack. */ 302 298 memset(stack, 0, THREAD_SIZE); 303 299 304 - if (memcg_charge_kernel_stack(s)) { 305 - vfree(s->addr); 300 + if (memcg_charge_kernel_stack(vm_area)) { 301 + vfree(vm_area->addr); 306 302 return -ENOMEM; 307 303 } 308 304 309 - tsk->stack_vm_area = s; 305 + tsk->stack_vm_area = vm_area; 310 306 tsk->stack = stack; 311 307 return 0; 312 308 } 313 309 314 - /* 315 - * Allocated stacks are cached and later reused by new threads, 316 - * so memcg accounting is performed manually on assigning/releasing 317 - * stacks to tasks. Drop __GFP_ACCOUNT. 318 - */ 319 310 stack = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN, 320 - THREADINFO_GFP & ~__GFP_ACCOUNT, 311 + GFP_VMAP_STACK, 321 312 node, __builtin_return_address(0)); 322 313 if (!stack) 323 314 return -ENOMEM; 324 315 325 - vm = find_vm_area(stack); 326 - if (memcg_charge_kernel_stack(vm)) { 316 + vm_area = find_vm_area(stack); 317 + if (memcg_charge_kernel_stack(vm_area)) { 327 318 vfree(stack); 328 319 return -ENOMEM; 329 320 } ··· 324 331 * free_thread_stack() can be called in interrupt context, 325 332 * so cache the vm_struct. 326 333 */ 327 - tsk->stack_vm_area = vm; 334 + tsk->stack_vm_area = vm_area; 328 335 stack = kasan_reset_tag(stack); 329 336 tsk->stack = stack; 330 337 return 0; ··· 339 346 tsk->stack_vm_area = NULL; 340 347 } 341 348 342 - # else /* !CONFIG_VMAP_STACK */ 349 + #else /* !CONFIG_VMAP_STACK */ 350 + 351 + /* 352 + * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a 353 + * kmemcache based allocator. 354 + */ 355 + #if THREAD_SIZE >= PAGE_SIZE 343 356 344 357 static void thread_stack_free_rcu(struct rcu_head *rh) 345 358 { ··· 377 378 tsk->stack = NULL; 378 379 } 379 380 380 - # endif /* CONFIG_VMAP_STACK */ 381 - # else /* !(THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)) */ 381 + #else /* !(THREAD_SIZE >= PAGE_SIZE) */ 382 382 383 383 static struct kmem_cache *thread_stack_cache; 384 384 ··· 416 418 BUG_ON(thread_stack_cache == NULL); 417 419 } 418 420 419 - # endif /* THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK) */ 421 + #endif /* THREAD_SIZE >= PAGE_SIZE */ 422 + #endif /* CONFIG_VMAP_STACK */ 420 423 421 424 /* SLAB cache for signal_struct structures (tsk->signal) */ 422 425 static struct kmem_cache *signal_cachep; ··· 437 438 static void account_kernel_stack(struct task_struct *tsk, int account) 438 439 { 439 440 if (IS_ENABLED(CONFIG_VMAP_STACK)) { 440 - struct vm_struct *vm = task_stack_vm_area(tsk); 441 + struct vm_struct *vm_area = task_stack_vm_area(tsk); 441 442 int i; 442 443 443 444 for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++) 444 - mod_lruvec_page_state(vm->pages[i], NR_KERNEL_STACK_KB, 445 + mod_lruvec_page_state(vm_area->pages[i], NR_KERNEL_STACK_KB, 445 446 account * (PAGE_SIZE / 1024)); 446 447 } else { 447 448 void *stack = task_stack_page(tsk); ··· 457 458 account_kernel_stack(tsk, -1); 458 459 459 460 if (IS_ENABLED(CONFIG_VMAP_STACK)) { 460 - struct vm_struct *vm; 461 + struct vm_struct *vm_area; 461 462 int i; 462 463 463 - vm = task_stack_vm_area(tsk); 464 + vm_area = task_stack_vm_area(tsk); 464 465 for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++) 465 - memcg_kmem_uncharge_page(vm->pages[i], 0); 466 + memcg_kmem_uncharge_page(vm_area->pages[i], 0); 466 467 } 467 468 } 468 469 ··· 585 586 for (i = 0; i < NR_MM_COUNTERS; i++) { 586 587 long x = percpu_counter_sum(&mm->rss_stat[i]); 587 588 588 - if (unlikely(x)) 589 - pr_alert("BUG: Bad rss-counter state mm:%p type:%s val:%ld\n", 590 - mm, resident_page_types[i], x); 589 + if (unlikely(x)) { 590 + pr_alert("BUG: Bad rss-counter state mm:%p type:%s val:%ld Comm:%s Pid:%d\n", 591 + mm, resident_page_types[i], x, 592 + current->comm, 593 + task_pid_nr(current)); 594 + } 591 595 } 592 596 593 597 if (mm_pgtables_bytes(mm))
+22 -71
kernel/gen_kheaders.sh
··· 4 4 # This script generates an archive consisting of kernel headers 5 5 # for CONFIG_IKHEADERS. 6 6 set -e 7 - sfile="$(readlink -f "$0")" 8 - outdir="$(pwd)" 9 7 tarfile=$1 10 - tmpdir=$outdir/${tarfile%/*}/.tmp_dir 8 + srclist=$2 9 + objlist=$3 10 + timestamp=$4 11 11 12 - dir_list=" 13 - include/ 14 - arch/$SRCARCH/include/ 15 - " 12 + dir=$(dirname "${tarfile}") 13 + tmpdir=${dir}/.tmp_dir 14 + depfile=${dir}/.$(basename "${tarfile}").d 16 15 17 - # Support incremental builds by skipping archive generation 18 - # if timestamps of files being archived are not changed. 16 + # generate dependency list. 17 + { 18 + echo 19 + echo "deps_${tarfile} := \\" 20 + sed 's:\(.*\): \1 \\:' "${srclist}" 21 + sed -n '/^include\/generated\/autoconf\.h$/!s:\(.*\): \1 \\:p' "${objlist}" 22 + echo 23 + echo "${tarfile}: \$(deps_${tarfile})" 24 + echo 25 + echo "\$(deps_${tarfile}):" 19 26 20 - # This block is useful for debugging the incremental builds. 21 - # Uncomment it for debugging. 22 - # if [ ! -f /tmp/iter ]; then iter=1; echo 1 > /tmp/iter; 23 - # else iter=$(($(cat /tmp/iter) + 1)); echo $iter > /tmp/iter; fi 24 - # find $all_dirs -name "*.h" | xargs ls -l > /tmp/ls-$iter 25 - 26 - all_dirs= 27 - if [ "$building_out_of_srctree" ]; then 28 - for d in $dir_list; do 29 - all_dirs="$all_dirs $srctree/$d" 30 - done 31 - fi 32 - all_dirs="$all_dirs $dir_list" 33 - 34 - # include/generated/utsversion.h is ignored because it is generated after this 35 - # script is executed. (utsversion.h is unneeded for kheaders) 36 - # 37 - # When Kconfig regenerates include/generated/autoconf.h, its timestamp is 38 - # updated, but the contents might be still the same. When any CONFIG option is 39 - # changed, Kconfig touches the corresponding timestamp file include/config/*. 40 - # Hence, the md5sum detects the configuration change anyway. We do not need to 41 - # check include/generated/autoconf.h explicitly. 42 - # 43 - # Ignore them for md5 calculation to avoid pointless regeneration. 44 - headers_md5="$(find $all_dirs -name "*.h" -a \ 45 - ! -path include/generated/utsversion.h -a \ 46 - ! -path include/generated/autoconf.h | 47 - xargs ls -l | md5sum | cut -d ' ' -f1)" 48 - 49 - # Any changes to this script will also cause a rebuild of the archive. 50 - this_file_md5="$(ls -l $sfile | md5sum | cut -d ' ' -f1)" 51 - if [ -f $tarfile ]; then tarfile_md5="$(md5sum $tarfile | cut -d ' ' -f1)"; fi 52 - if [ -f kernel/kheaders.md5 ] && 53 - [ "$(head -n 1 kernel/kheaders.md5)" = "$headers_md5" ] && 54 - [ "$(head -n 2 kernel/kheaders.md5 | tail -n 1)" = "$this_file_md5" ] && 55 - [ "$(tail -n 1 kernel/kheaders.md5)" = "$tarfile_md5" ]; then 56 - exit 57 - fi 58 - 59 - echo " GEN $tarfile" 27 + } > "${depfile}" 60 28 61 29 rm -rf "${tmpdir}" 62 30 mkdir "${tmpdir}" 63 31 64 - if [ "$building_out_of_srctree" ]; then 65 - ( 66 - cd $srctree 67 - for f in $dir_list 68 - do find "$f" -name "*.h"; 69 - done | tar -c -f - -T - | tar -xf - -C "${tmpdir}" 70 - ) 71 - fi 72 - 73 - for f in $dir_list; 74 - do find "$f" -name "*.h"; 75 - done | tar -c -f - -T - | tar -xf - -C "${tmpdir}" 76 - 77 - # Always exclude include/generated/utsversion.h 78 - # Otherwise, the contents of the tarball may vary depending on the build steps. 79 - rm -f "${tmpdir}/include/generated/utsversion.h" 32 + # shellcheck disable=SC2154 # srctree is passed as an env variable 33 + sed "s:^${srctree}/::" "${srclist}" | ${TAR} -c -f - -C "${srctree}" -T - | ${TAR} -xf - -C "${tmpdir}" 34 + ${TAR} -c -f - -T "${objlist}" | ${TAR} -xf - -C "${tmpdir}" 80 35 81 36 # Remove comments except SDPX lines 82 37 # Use a temporary file to store directory contents to prevent find/xargs from ··· 43 88 rm -f "${tmpdir}.contents.txt" 44 89 45 90 # Create archive and try to normalize metadata for reproducibility. 46 - tar "${KBUILD_BUILD_TIMESTAMP:+--mtime=$KBUILD_BUILD_TIMESTAMP}" \ 91 + ${TAR} "${timestamp:+--mtime=$timestamp}" \ 47 92 --owner=0 --group=0 --sort=name --numeric-owner --mode=u=rw,go=r,a+X \ 48 - -I $XZ -cf $tarfile -C "${tmpdir}/" . > /dev/null 49 - 50 - echo $headers_md5 > kernel/kheaders.md5 51 - echo "$this_file_md5" >> kernel/kheaders.md5 52 - echo "$(md5sum $tarfile | cut -d ' ' -f1)" >> kernel/kheaders.md5 93 + -I "${XZ}" -cf "${tarfile}" -C "${tmpdir}/" . > /dev/null 53 94 54 95 rm -rf "${tmpdir}"
+25 -4
kernel/hung_task.c
··· 23 23 #include <linux/sched/debug.h> 24 24 #include <linux/sched/sysctl.h> 25 25 #include <linux/hung_task.h> 26 + #include <linux/rwsem.h> 26 27 27 28 #include <trace/events/sched.h> 28 29 ··· 101 100 { 102 101 struct task_struct *g, *t; 103 102 unsigned long owner, blocker, blocker_type; 103 + const char *rwsem_blocked_by, *rwsem_blocked_as; 104 104 105 105 RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "No rcu lock held"); 106 106 ··· 113 111 114 112 switch (blocker_type) { 115 113 case BLOCKER_TYPE_MUTEX: 116 - owner = mutex_get_owner( 117 - (struct mutex *)hung_task_blocker_to_lock(blocker)); 114 + owner = mutex_get_owner(hung_task_blocker_to_lock(blocker)); 118 115 break; 119 116 case BLOCKER_TYPE_SEM: 120 - owner = sem_last_holder( 121 - (struct semaphore *)hung_task_blocker_to_lock(blocker)); 117 + owner = sem_last_holder(hung_task_blocker_to_lock(blocker)); 118 + break; 119 + case BLOCKER_TYPE_RWSEM_READER: 120 + case BLOCKER_TYPE_RWSEM_WRITER: 121 + owner = (unsigned long)rwsem_owner( 122 + hung_task_blocker_to_lock(blocker)); 123 + rwsem_blocked_as = (blocker_type == BLOCKER_TYPE_RWSEM_READER) ? 124 + "reader" : "writer"; 125 + rwsem_blocked_by = is_rwsem_reader_owned( 126 + hung_task_blocker_to_lock(blocker)) ? 127 + "reader" : "writer"; 122 128 break; 123 129 default: 124 130 WARN_ON_ONCE(1); ··· 142 132 break; 143 133 case BLOCKER_TYPE_SEM: 144 134 pr_err("INFO: task %s:%d is blocked on a semaphore, but the last holder is not found.\n", 135 + task->comm, task->pid); 136 + break; 137 + case BLOCKER_TYPE_RWSEM_READER: 138 + case BLOCKER_TYPE_RWSEM_WRITER: 139 + pr_err("INFO: task %s:%d is blocked on an rw-semaphore, but the owner is not found.\n", 145 140 task->comm, task->pid); 146 141 break; 147 142 } ··· 166 151 case BLOCKER_TYPE_SEM: 167 152 pr_err("INFO: task %s:%d blocked on a semaphore likely last held by task %s:%d\n", 168 153 task->comm, task->pid, t->comm, t->pid); 154 + break; 155 + case BLOCKER_TYPE_RWSEM_READER: 156 + case BLOCKER_TYPE_RWSEM_WRITER: 157 + pr_err("INFO: task %s:%d <%s> blocked on an rw-semaphore likely owned by task %s:%d <%s>\n", 158 + task->comm, task->pid, rwsem_blocked_as, t->comm, 159 + t->pid, rwsem_blocked_by); 169 160 break; 170 161 } 171 162 sched_show_task(t);
+1 -1
kernel/kcov.c
··· 552 552 553 553 /* 554 554 * Fault in a lazily-faulted vmalloc area before it can be used by 555 - * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the 555 + * __sanitizer_cov_trace_pc(), to avoid recursion issues if any code on the 556 556 * vmalloc fault handling path is instrumented. 557 557 */ 558 558 static void kcov_fault_in_area(struct kcov *kcov)
+1 -1
kernel/kexec.c
··· 152 152 goto out; 153 153 154 154 for (i = 0; i < nr_segments; i++) { 155 - ret = kimage_load_segment(image, &image->segment[i]); 155 + ret = kimage_load_segment(image, i); 156 156 if (ret) 157 157 goto out; 158 158 }
+92 -8
kernel/kexec_core.c
··· 40 40 #include <linux/hugetlb.h> 41 41 #include <linux/objtool.h> 42 42 #include <linux/kmsg_dump.h> 43 + #include <linux/dma-map-ops.h> 43 44 44 45 #include <asm/page.h> 45 46 #include <asm/sections.h> ··· 554 553 kimage_free_pages(page); 555 554 } 556 555 556 + static void kimage_free_cma(struct kimage *image) 557 + { 558 + unsigned long i; 559 + 560 + for (i = 0; i < image->nr_segments; i++) { 561 + struct page *cma = image->segment_cma[i]; 562 + u32 nr_pages = image->segment[i].memsz >> PAGE_SHIFT; 563 + 564 + if (!cma) 565 + continue; 566 + 567 + arch_kexec_pre_free_pages(page_address(cma), nr_pages); 568 + dma_release_from_contiguous(NULL, cma, nr_pages); 569 + image->segment_cma[i] = NULL; 570 + } 571 + 572 + } 573 + 557 574 void kimage_free(struct kimage *image) 558 575 { 559 576 kimage_entry_t *ptr, entry; ··· 609 590 610 591 /* Free the kexec control pages... */ 611 592 kimage_free_page_list(&image->control_pages); 593 + 594 + /* Free CMA allocations */ 595 + kimage_free_cma(image); 612 596 613 597 /* 614 598 * Free up any temporary buffers allocated. This might hit if ··· 738 716 return page; 739 717 } 740 718 741 - static int kimage_load_normal_segment(struct kimage *image, 742 - struct kexec_segment *segment) 719 + static int kimage_load_cma_segment(struct kimage *image, int idx) 743 720 { 721 + struct kexec_segment *segment = &image->segment[idx]; 722 + struct page *cma = image->segment_cma[idx]; 723 + char *ptr = page_address(cma); 724 + unsigned long maddr; 725 + size_t ubytes, mbytes; 726 + int result = 0; 727 + unsigned char __user *buf = NULL; 728 + unsigned char *kbuf = NULL; 729 + 730 + if (image->file_mode) 731 + kbuf = segment->kbuf; 732 + else 733 + buf = segment->buf; 734 + ubytes = segment->bufsz; 735 + mbytes = segment->memsz; 736 + maddr = segment->mem; 737 + 738 + /* Then copy from source buffer to the CMA one */ 739 + while (mbytes) { 740 + size_t uchunk, mchunk; 741 + 742 + ptr += maddr & ~PAGE_MASK; 743 + mchunk = min_t(size_t, mbytes, 744 + PAGE_SIZE - (maddr & ~PAGE_MASK)); 745 + uchunk = min(ubytes, mchunk); 746 + 747 + if (uchunk) { 748 + /* For file based kexec, source pages are in kernel memory */ 749 + if (image->file_mode) 750 + memcpy(ptr, kbuf, uchunk); 751 + else 752 + result = copy_from_user(ptr, buf, uchunk); 753 + ubytes -= uchunk; 754 + if (image->file_mode) 755 + kbuf += uchunk; 756 + else 757 + buf += uchunk; 758 + } 759 + 760 + if (result) { 761 + result = -EFAULT; 762 + goto out; 763 + } 764 + 765 + ptr += mchunk; 766 + maddr += mchunk; 767 + mbytes -= mchunk; 768 + 769 + cond_resched(); 770 + } 771 + 772 + /* Clear any remainder */ 773 + memset(ptr, 0, mbytes); 774 + 775 + out: 776 + return result; 777 + } 778 + 779 + static int kimage_load_normal_segment(struct kimage *image, int idx) 780 + { 781 + struct kexec_segment *segment = &image->segment[idx]; 744 782 unsigned long maddr; 745 783 size_t ubytes, mbytes; 746 784 int result; ··· 814 732 ubytes = segment->bufsz; 815 733 mbytes = segment->memsz; 816 734 maddr = segment->mem; 735 + 736 + if (image->segment_cma[idx]) 737 + return kimage_load_cma_segment(image, idx); 817 738 818 739 result = kimage_set_destination(image, maddr); 819 740 if (result < 0) ··· 872 787 } 873 788 874 789 #ifdef CONFIG_CRASH_DUMP 875 - static int kimage_load_crash_segment(struct kimage *image, 876 - struct kexec_segment *segment) 790 + static int kimage_load_crash_segment(struct kimage *image, int idx) 877 791 { 878 792 /* For crash dumps kernels we simply copy the data from 879 793 * user space to it's destination. 880 794 * We do things a page at a time for the sake of kmap. 881 795 */ 796 + struct kexec_segment *segment = &image->segment[idx]; 882 797 unsigned long maddr; 883 798 size_t ubytes, mbytes; 884 799 int result; ··· 943 858 } 944 859 #endif 945 860 946 - int kimage_load_segment(struct kimage *image, 947 - struct kexec_segment *segment) 861 + int kimage_load_segment(struct kimage *image, int idx) 948 862 { 949 863 int result = -ENOMEM; 950 864 951 865 switch (image->type) { 952 866 case KEXEC_TYPE_DEFAULT: 953 - result = kimage_load_normal_segment(image, segment); 867 + result = kimage_load_normal_segment(image, idx); 954 868 break; 955 869 #ifdef CONFIG_CRASH_DUMP 956 870 case KEXEC_TYPE_CRASH: 957 - result = kimage_load_crash_segment(image, segment); 871 + result = kimage_load_crash_segment(image, idx); 958 872 break; 959 873 #endif 960 874 }
+50 -1
kernel/kexec_file.c
··· 26 26 #include <linux/kernel_read_file.h> 27 27 #include <linux/syscalls.h> 28 28 #include <linux/vmalloc.h> 29 + #include <linux/dma-map-ops.h> 29 30 #include "kexec_internal.h" 30 31 31 32 #ifdef CONFIG_KEXEC_SIG ··· 254 253 ret = 0; 255 254 } 256 255 256 + image->no_cma = !!(flags & KEXEC_FILE_NO_CMA); 257 + 257 258 if (cmdline_len) { 258 259 image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len); 259 260 if (IS_ERR(image->cmdline_buf)) { ··· 437 434 i, ksegment->buf, ksegment->bufsz, ksegment->mem, 438 435 ksegment->memsz); 439 436 440 - ret = kimage_load_segment(image, &image->segment[i]); 437 + ret = kimage_load_segment(image, i); 441 438 if (ret) 442 439 goto out; 443 440 } ··· 666 663 return walk_system_ram_res(0, ULONG_MAX, kbuf, func); 667 664 } 668 665 666 + static int kexec_alloc_contig(struct kexec_buf *kbuf) 667 + { 668 + size_t nr_pages = kbuf->memsz >> PAGE_SHIFT; 669 + unsigned long mem; 670 + struct page *p; 671 + 672 + /* User space disabled CMA allocations, bail out. */ 673 + if (kbuf->image->no_cma) 674 + return -EPERM; 675 + 676 + /* Skip CMA logic for crash kernel */ 677 + if (kbuf->image->type == KEXEC_TYPE_CRASH) 678 + return -EPERM; 679 + 680 + p = dma_alloc_from_contiguous(NULL, nr_pages, get_order(kbuf->buf_align), true); 681 + if (!p) 682 + return -ENOMEM; 683 + 684 + pr_debug("allocated %zu DMA pages at 0x%lx", nr_pages, page_to_boot_pfn(p)); 685 + 686 + mem = page_to_boot_pfn(p) << PAGE_SHIFT; 687 + 688 + if (kimage_is_destination_range(kbuf->image, mem, mem + kbuf->memsz)) { 689 + /* Our region is already in use by a statically defined one. Bail out. */ 690 + pr_debug("CMA overlaps existing mem: 0x%lx+0x%lx\n", mem, kbuf->memsz); 691 + dma_release_from_contiguous(NULL, p, nr_pages); 692 + return -EBUSY; 693 + } 694 + 695 + kbuf->mem = page_to_boot_pfn(p) << PAGE_SHIFT; 696 + kbuf->cma = p; 697 + 698 + arch_kexec_post_alloc_pages(page_address(p), (int)nr_pages, 0); 699 + 700 + return 0; 701 + } 702 + 669 703 /** 670 704 * kexec_locate_mem_hole - find free memory for the purgatory or the next kernel 671 705 * @kbuf: Parameters for the memory search. ··· 726 686 ret = kho_locate_mem_hole(kbuf, locate_mem_hole_callback); 727 687 if (ret <= 0) 728 688 return ret; 689 + 690 + /* 691 + * Try to find a free physically contiguous block of memory first. With that, we 692 + * can avoid any copying at kexec time. 693 + */ 694 + if (!kexec_alloc_contig(kbuf)) 695 + return 0; 729 696 730 697 if (!IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK)) 731 698 ret = kexec_walk_resources(kbuf, locate_mem_hole_callback); ··· 779 732 /* Ensure minimum alignment needed for segments. */ 780 733 kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE); 781 734 kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE); 735 + kbuf->cma = NULL; 782 736 783 737 /* Walk the RAM ranges and allocate a suitable range for the buffer */ 784 738 ret = arch_kexec_locate_mem_hole(kbuf); ··· 792 744 ksegment->bufsz = kbuf->bufsz; 793 745 ksegment->mem = kbuf->mem; 794 746 ksegment->memsz = kbuf->memsz; 747 + kbuf->image->segment_cma[kbuf->image->nr_segments] = kbuf->cma; 795 748 kbuf->image->nr_segments++; 796 749 return 0; 797 750 }
+1 -1
kernel/kexec_internal.h
··· 10 10 int sanity_check_segment_list(struct kimage *image); 11 11 void kimage_free_page_list(struct list_head *list); 12 12 void kimage_free(struct kimage *image); 13 - int kimage_load_segment(struct kimage *image, struct kexec_segment *segment); 13 + int kimage_load_segment(struct kimage *image, int idx); 14 14 void kimage_terminate(struct kimage *image); 15 15 int kimage_is_destination_range(struct kimage *image, 16 16 unsigned long start, unsigned long end);
+5 -6
kernel/kthread.c
··· 88 88 /* 89 89 * Variant of to_kthread() that doesn't assume @p is a kthread. 90 90 * 91 - * Per construction; when: 91 + * When "(p->flags & PF_KTHREAD)" is set the task is a kthread and will 92 + * always remain a kthread. For kthreads p->worker_private always 93 + * points to a struct kthread. For tasks that are not kthreads 94 + * p->worker_private is used to point to other things. 92 95 * 93 - * (p->flags & PF_KTHREAD) && p->worker_private 94 - * 95 - * the task is both a kthread and struct kthread is persistent. However 96 - * PF_KTHREAD on it's own is not, kernel_thread() can exec() (See umh.c and 97 - * begin_new_exec()). 96 + * Return NULL for any task that is not a kthread. 98 97 */ 99 98 static inline struct kthread *__to_kthread(struct task_struct *p) 100 99 {
+23 -8
kernel/locking/rwsem.c
··· 27 27 #include <linux/export.h> 28 28 #include <linux/rwsem.h> 29 29 #include <linux/atomic.h> 30 + #include <linux/hung_task.h> 30 31 #include <trace/events/lock.h> 31 32 32 33 #ifndef CONFIG_PREEMPT_RT ··· 182 181 __rwsem_set_reader_owned(sem, current); 183 182 } 184 183 185 - #ifdef CONFIG_DEBUG_RWSEMS 184 + #if defined(CONFIG_DEBUG_RWSEMS) || defined(CONFIG_DETECT_HUNG_TASK_BLOCKER) 186 185 /* 187 186 * Return just the real task structure pointer of the owner 188 187 */ 189 - static inline struct task_struct *rwsem_owner(struct rw_semaphore *sem) 188 + struct task_struct *rwsem_owner(struct rw_semaphore *sem) 190 189 { 191 190 return (struct task_struct *) 192 191 (atomic_long_read(&sem->owner) & ~RWSEM_OWNER_FLAGS_MASK); ··· 195 194 /* 196 195 * Return true if the rwsem is owned by a reader. 197 196 */ 198 - static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem) 197 + bool is_rwsem_reader_owned(struct rw_semaphore *sem) 199 198 { 200 199 /* 201 200 * Check the count to see if it is write-locked. ··· 208 207 } 209 208 210 209 /* 211 - * With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there 212 - * is a task pointer in owner of a reader-owned rwsem, it will be the 213 - * real owner or one of the real owners. The only exception is when the 214 - * unlock is done by up_read_non_owner(). 210 + * With CONFIG_DEBUG_RWSEMS or CONFIG_DETECT_HUNG_TASK_BLOCKER configured, 211 + * it will make sure that the owner field of a reader-owned rwsem either 212 + * points to a real reader-owner(s) or gets cleared. The only exception is 213 + * when the unlock is done by up_read_non_owner(). 215 214 */ 216 215 static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem) 217 216 { ··· 1064 1063 wake_up_q(&wake_q); 1065 1064 1066 1065 trace_contention_begin(sem, LCB_F_READ); 1066 + set_current_state(state); 1067 + 1068 + if (state == TASK_UNINTERRUPTIBLE) 1069 + hung_task_set_blocker(sem, BLOCKER_TYPE_RWSEM_READER); 1067 1070 1068 1071 /* wait to be given the lock */ 1069 1072 for (;;) { 1070 - set_current_state(state); 1071 1073 if (!smp_load_acquire(&waiter.task)) { 1072 1074 /* Matches rwsem_mark_wake()'s smp_store_release(). */ 1073 1075 break; ··· 1085 1081 } 1086 1082 schedule_preempt_disabled(); 1087 1083 lockevent_inc(rwsem_sleep_reader); 1084 + set_current_state(state); 1088 1085 } 1086 + 1087 + if (state == TASK_UNINTERRUPTIBLE) 1088 + hung_task_clear_blocker(); 1089 1089 1090 1090 __set_current_state(TASK_RUNNING); 1091 1091 lockevent_inc(rwsem_rlock); ··· 1152 1144 set_current_state(state); 1153 1145 trace_contention_begin(sem, LCB_F_WRITE); 1154 1146 1147 + if (state == TASK_UNINTERRUPTIBLE) 1148 + hung_task_set_blocker(sem, BLOCKER_TYPE_RWSEM_WRITER); 1149 + 1155 1150 for (;;) { 1156 1151 if (rwsem_try_write_lock(sem, &waiter)) { 1157 1152 /* rwsem_try_write_lock() implies ACQUIRE on success */ ··· 1188 1177 trylock_again: 1189 1178 raw_spin_lock_irq(&sem->wait_lock); 1190 1179 } 1180 + 1181 + if (state == TASK_UNINTERRUPTIBLE) 1182 + hung_task_clear_blocker(); 1183 + 1191 1184 __set_current_state(TASK_RUNNING); 1192 1185 raw_spin_unlock_irq(&sem->wait_lock); 1193 1186 lockevent_inc(rwsem_wlock);
+7
kernel/module/internal.h
··· 112 112 enum mod_license license; 113 113 }; 114 114 115 + /* modules using other modules */ 116 + struct module_use { 117 + struct list_head source_list; 118 + struct list_head target_list; 119 + struct module *source, *target; 120 + }; 121 + 115 122 int mod_verify_sig(const void *mod, struct load_info *info); 116 123 int try_to_force_load(struct module *mod, const char *reason); 117 124 bool find_symbol(struct find_symbol_arg *fsa);
+9 -16
kernel/module/main.c
··· 608 608 MODINFO_ATTR(srcversion); 609 609 610 610 static struct { 611 - char name[MODULE_NAME_LEN + 1]; 611 + char name[MODULE_NAME_LEN]; 612 612 char taints[MODULE_FLAGS_BUF_SIZE]; 613 613 } last_unloaded_module; 614 614 ··· 779 779 struct module *mod; 780 780 char name[MODULE_NAME_LEN]; 781 781 char buf[MODULE_FLAGS_BUF_SIZE]; 782 - int ret, forced = 0; 782 + int ret, len, forced = 0; 783 783 784 784 if (!capable(CAP_SYS_MODULE) || modules_disabled) 785 785 return -EPERM; 786 786 787 - if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) 788 - return -EFAULT; 789 - name[MODULE_NAME_LEN-1] = '\0'; 787 + len = strncpy_from_user(name, name_user, MODULE_NAME_LEN); 788 + if (len == 0 || len == MODULE_NAME_LEN) 789 + return -ENOENT; 790 + if (len < 0) 791 + return len; 790 792 791 793 audit_log_kern_module(name); 792 794 ··· 1322 1320 else 1323 1321 execmem_type = EXECMEM_MODULE_TEXT; 1324 1322 1325 - ptr = execmem_alloc(execmem_type, size); 1323 + ptr = execmem_alloc_rw(execmem_type, size); 1326 1324 if (!ptr) 1327 1325 return -ENOMEM; 1328 1326 1329 - if (execmem_is_rox(execmem_type)) { 1330 - int err = execmem_make_temp_rw(ptr, size); 1331 - 1332 - if (err) { 1333 - execmem_free(ptr); 1334 - return -ENOMEM; 1335 - } 1336 - 1337 - mod->mem[type].is_rox = true; 1338 - } 1327 + mod->mem[type].is_rox = execmem_is_rox(execmem_type); 1339 1328 1340 1329 /* 1341 1330 * The pointer to these blocks of memory are stored on the module
+32 -39
kernel/panic.c
··· 36 36 #include <linux/sysfs.h> 37 37 #include <linux/context_tracking.h> 38 38 #include <linux/seq_buf.h> 39 + #include <linux/sys_info.h> 39 40 #include <trace/events/error_report.h> 40 41 #include <asm/sections.h> 41 42 ··· 64 63 unsigned long panic_on_taint; 65 64 bool panic_on_taint_nousertaint = false; 66 65 static unsigned int warn_limit __read_mostly; 66 + static bool panic_console_replay; 67 67 68 68 bool panic_triggering_all_cpu_backtrace; 69 69 70 70 int panic_timeout = CONFIG_PANIC_TIMEOUT; 71 71 EXPORT_SYMBOL_GPL(panic_timeout); 72 72 73 - #define PANIC_PRINT_TASK_INFO 0x00000001 74 - #define PANIC_PRINT_MEM_INFO 0x00000002 75 - #define PANIC_PRINT_TIMER_INFO 0x00000004 76 - #define PANIC_PRINT_LOCK_INFO 0x00000008 77 - #define PANIC_PRINT_FTRACE_INFO 0x00000010 78 - #define PANIC_PRINT_ALL_PRINTK_MSG 0x00000020 79 - #define PANIC_PRINT_ALL_CPU_BT 0x00000040 80 - #define PANIC_PRINT_BLOCKED_TASKS 0x00000080 81 73 unsigned long panic_print; 82 74 83 75 ATOMIC_NOTIFIER_HEAD(panic_notifier_list); ··· 122 128 return err; 123 129 } 124 130 131 + static int sysctl_panic_print_handler(const struct ctl_table *table, int write, 132 + void *buffer, size_t *lenp, loff_t *ppos) 133 + { 134 + pr_info_once("Kernel: 'panic_print' sysctl interface will be obsoleted by both 'panic_sys_info' and 'panic_console_replay'\n"); 135 + return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); 136 + } 137 + 125 138 static const struct ctl_table kern_panic_table[] = { 126 139 #ifdef CONFIG_SMP 127 140 { ··· 166 165 .data = &panic_print, 167 166 .maxlen = sizeof(unsigned long), 168 167 .mode = 0644, 169 - .proc_handler = proc_doulongvec_minmax, 168 + .proc_handler = sysctl_panic_print_handler, 170 169 }, 171 170 { 172 171 .procname = "panic_on_warn", ··· 194 193 .proc_handler = proc_dointvec, 195 194 }, 196 195 #endif 196 + { 197 + .procname = "panic_sys_info", 198 + .data = &panic_print, 199 + .maxlen = sizeof(panic_print), 200 + .mode = 0644, 201 + .proc_handler = sysctl_sys_info_handler, 202 + }, 197 203 }; 198 204 199 205 static __init int kernel_panic_sysctls_init(void) ··· 210 202 } 211 203 late_initcall(kernel_panic_sysctls_init); 212 204 #endif 205 + 206 + /* The format is "panic_sys_info=tasks,mem,locks,ftrace,..." */ 207 + static int __init setup_panic_sys_info(char *buf) 208 + { 209 + /* There is no risk of race in kernel boot phase */ 210 + panic_print = sys_info_parse_param(buf); 211 + return 1; 212 + } 213 + __setup("panic_sys_info=", setup_panic_sys_info); 213 214 214 215 static atomic_t warn_count = ATOMIC_INIT(0); 215 216 ··· 315 298 } 316 299 EXPORT_SYMBOL(nmi_panic); 317 300 318 - static void panic_print_sys_info(bool console_flush) 319 - { 320 - if (console_flush) { 321 - if (panic_print & PANIC_PRINT_ALL_PRINTK_MSG) 322 - console_flush_on_panic(CONSOLE_REPLAY_ALL); 323 - return; 324 - } 325 - 326 - if (panic_print & PANIC_PRINT_TASK_INFO) 327 - show_state(); 328 - 329 - if (panic_print & PANIC_PRINT_MEM_INFO) 330 - show_mem(); 331 - 332 - if (panic_print & PANIC_PRINT_TIMER_INFO) 333 - sysrq_timer_list_show(); 334 - 335 - if (panic_print & PANIC_PRINT_LOCK_INFO) 336 - debug_show_all_locks(); 337 - 338 - if (panic_print & PANIC_PRINT_FTRACE_INFO) 339 - ftrace_dump(DUMP_ALL); 340 - 341 - if (panic_print & PANIC_PRINT_BLOCKED_TASKS) 342 - show_state_filter(TASK_UNINTERRUPTIBLE); 343 - } 344 - 345 301 void check_panic_on_warn(const char *origin) 346 302 { 347 303 unsigned int limit; ··· 335 345 */ 336 346 static void panic_other_cpus_shutdown(bool crash_kexec) 337 347 { 338 - if (panic_print & PANIC_PRINT_ALL_CPU_BT) { 348 + if (panic_print & SYS_INFO_ALL_CPU_BT) { 339 349 /* Temporary allow non-panic CPUs to write their backtraces. */ 340 350 panic_triggering_all_cpu_backtrace = true; 341 351 trigger_all_cpu_backtrace(); ··· 458 468 */ 459 469 atomic_notifier_call_chain(&panic_notifier_list, 0, buf); 460 470 461 - panic_print_sys_info(false); 471 + sys_info(panic_print); 462 472 463 473 kmsg_dump_desc(KMSG_DUMP_PANIC, buf); 464 474 ··· 487 497 debug_locks_off(); 488 498 console_flush_on_panic(CONSOLE_FLUSH_PENDING); 489 499 490 - panic_print_sys_info(true); 500 + if ((panic_print & SYS_INFO_PANIC_CONSOLE_REPLAY) || 501 + panic_console_replay) 502 + console_flush_on_panic(CONSOLE_REPLAY_ALL); 491 503 492 504 if (!panic_blink) 493 505 panic_blink = no_blink; ··· 941 949 core_param(pause_on_oops, pause_on_oops, int, 0644); 942 950 core_param(panic_on_warn, panic_on_warn, int, 0644); 943 951 core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644); 952 + core_param(panic_console_replay, panic_console_replay, bool, 0644); 944 953 945 954 static int __init oops_setup(char *s) 946 955 {
+2
kernel/printk/internal.h
··· 64 64 65 65 extern struct printk_ringbuffer *prb; 66 66 extern bool printk_kthreads_running; 67 + extern bool printk_kthreads_ready; 67 68 extern bool debug_non_panic_cpus; 68 69 69 70 __printf(4, 0) ··· 180 179 #define PRINTKRB_RECORD_MAX 0 181 180 182 181 #define printk_kthreads_running (false) 182 + #define printk_kthreads_ready (false) 183 183 184 184 /* 185 185 * In !PRINTK builds we still export console_sem
+65 -24
kernel/printk/nbcon.c
··· 214 214 215 215 /** 216 216 * nbcon_context_try_acquire_direct - Try to acquire directly 217 - * @ctxt: The context of the caller 218 - * @cur: The current console state 217 + * @ctxt: The context of the caller 218 + * @cur: The current console state 219 + * @is_reacquire: This acquire is a reacquire 219 220 * 220 221 * Acquire the console when it is released. Also acquire the console when 221 222 * the current owner has a lower priority and the console is in a safe state. ··· 226 225 * 227 226 * Errors: 228 227 * 229 - * -EPERM: A panic is in progress and this is not the panic CPU. 230 - * Or the current owner or waiter has the same or higher 231 - * priority. No acquire method can be successful in 232 - * this case. 228 + * -EPERM: A panic is in progress and this is neither the panic 229 + * CPU nor is this a reacquire. Or the current owner or 230 + * waiter has the same or higher priority. No acquire 231 + * method can be successful in these cases. 233 232 * 234 233 * -EBUSY: The current owner has a lower priority but the console 235 234 * in an unsafe state. The caller should try using 236 235 * the handover acquire method. 237 236 */ 238 237 static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt, 239 - struct nbcon_state *cur) 238 + struct nbcon_state *cur, bool is_reacquire) 240 239 { 241 240 unsigned int cpu = smp_processor_id(); 242 241 struct console *con = ctxt->console; ··· 244 243 245 244 do { 246 245 /* 247 - * Panic does not imply that the console is owned. However, it 248 - * is critical that non-panic CPUs during panic are unable to 249 - * acquire ownership in order to satisfy the assumptions of 250 - * nbcon_waiter_matches(). In particular, the assumption that 251 - * lower priorities are ignored during panic. 246 + * Panic does not imply that the console is owned. However, 247 + * since all non-panic CPUs are stopped during panic(), it 248 + * is safer to have them avoid gaining console ownership. 249 + * 250 + * If this acquire is a reacquire (and an unsafe takeover 251 + * has not previously occurred) then it is allowed to attempt 252 + * a direct acquire in panic. This gives console drivers an 253 + * opportunity to perform any necessary cleanup if they were 254 + * interrupted by the panic CPU while printing. 252 255 */ 253 - if (other_cpu_in_panic()) 256 + if (other_cpu_in_panic() && 257 + (!is_reacquire || cur->unsafe_takeover)) { 254 258 return -EPERM; 259 + } 255 260 256 261 if (ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio) 257 262 return -EPERM; ··· 308 301 * Event #1 implies this context is EMERGENCY. 309 302 * Event #2 implies the new context is PANIC. 310 303 * Event #3 occurs when panic() has flushed the console. 311 - * Events #4 and #5 are not possible due to the other_cpu_in_panic() 312 - * check in nbcon_context_try_acquire_direct(). 304 + * Event #4 occurs when a non-panic CPU reacquires. 305 + * Event #5 is not possible due to the other_cpu_in_panic() check 306 + * in nbcon_context_try_acquire_handover(). 313 307 */ 314 308 315 309 return (cur->req_prio == expected_prio); ··· 439 431 WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio); 440 432 WARN_ON_ONCE(!cur->unsafe); 441 433 434 + /* 435 + * Panic does not imply that the console is owned. However, it 436 + * is critical that non-panic CPUs during panic are unable to 437 + * wait for a handover in order to satisfy the assumptions of 438 + * nbcon_waiter_matches(). In particular, the assumption that 439 + * lower priorities are ignored during panic. 440 + */ 441 + if (other_cpu_in_panic()) 442 + return -EPERM; 443 + 442 444 /* Handover is not possible on the same CPU. */ 443 445 if (cur->cpu == cpu) 444 446 return -EBUSY; ··· 576 558 577 559 /** 578 560 * nbcon_context_try_acquire - Try to acquire nbcon console 579 - * @ctxt: The context of the caller 561 + * @ctxt: The context of the caller 562 + * @is_reacquire: This acquire is a reacquire 580 563 * 581 564 * Context: Under @ctxt->con->device_lock() or local_irq_save(). 582 565 * Return: True if the console was acquired. False otherwise. ··· 587 568 * in an unsafe state. Otherwise, on success the caller may assume 588 569 * the console is not in an unsafe state. 589 570 */ 590 - static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) 571 + static bool nbcon_context_try_acquire(struct nbcon_context *ctxt, bool is_reacquire) 591 572 { 592 573 unsigned int cpu = smp_processor_id(); 593 574 struct console *con = ctxt->console; ··· 596 577 597 578 nbcon_state_read(con, &cur); 598 579 try_again: 599 - err = nbcon_context_try_acquire_direct(ctxt, &cur); 580 + err = nbcon_context_try_acquire_direct(ctxt, &cur, is_reacquire); 600 581 if (err != -EBUSY) 601 582 goto out; 602 583 ··· 932 913 { 933 914 struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); 934 915 935 - while (!nbcon_context_try_acquire(ctxt)) 916 + while (!nbcon_context_try_acquire(ctxt, true)) 936 917 cpu_relax(); 937 918 938 919 nbcon_write_context_set_buf(wctxt, NULL, 0); ··· 1120 1101 cant_migrate(); 1121 1102 } 1122 1103 1123 - if (!nbcon_context_try_acquire(ctxt)) 1104 + if (!nbcon_context_try_acquire(ctxt, false)) 1124 1105 goto out; 1125 1106 1126 1107 /* ··· 1505 1486 ctxt->prio = nbcon_get_default_prio(); 1506 1487 ctxt->allow_unsafe_takeover = allow_unsafe_takeover; 1507 1488 1508 - if (!nbcon_context_try_acquire(ctxt)) 1489 + if (!nbcon_context_try_acquire(ctxt, false)) 1509 1490 return -EPERM; 1510 1491 1511 1492 while (nbcon_seq_read(con) < stop_seq) { ··· 1690 1671 { 1691 1672 struct nbcon_state state = { }; 1692 1673 1674 + /* Synchronize the kthread start. */ 1675 + lockdep_assert_console_list_lock_held(); 1676 + 1693 1677 /* The write_thread() callback is mandatory. */ 1694 1678 if (WARN_ON(!con->write_thread)) 1695 1679 return false; ··· 1723 1701 return false; 1724 1702 } 1725 1703 1726 - if (printk_kthreads_running) { 1704 + if (printk_kthreads_ready && !have_boot_console) { 1727 1705 if (!nbcon_kthread_create(con)) { 1728 1706 kfree(con->pbufs); 1729 1707 con->pbufs = NULL; 1730 1708 return false; 1731 1709 } 1710 + 1711 + /* Might be the first kthread. */ 1712 + printk_kthreads_running = true; 1732 1713 } 1733 1714 } 1734 1715 ··· 1741 1716 /** 1742 1717 * nbcon_free - Free and cleanup the nbcon console specific data 1743 1718 * @con: Console to free/cleanup nbcon data 1719 + * 1720 + * Important: @have_nbcon_console must be updated before calling 1721 + * this function. In particular, it can be set only when there 1722 + * is still another nbcon console registered. 1744 1723 */ 1745 1724 void nbcon_free(struct console *con) 1746 1725 { 1747 1726 struct nbcon_state state = { }; 1748 1727 1749 - if (printk_kthreads_running) 1728 + /* Synchronize the kthread stop. */ 1729 + lockdep_assert_console_list_lock_held(); 1730 + 1731 + if (printk_kthreads_running) { 1750 1732 nbcon_kthread_stop(con); 1733 + 1734 + /* Might be the last nbcon console. 1735 + * 1736 + * Do not rely on printk_kthreads_check_locked(). It is not 1737 + * called in some code paths, see nbcon_free() callers. 1738 + */ 1739 + if (!have_nbcon_console) 1740 + printk_kthreads_running = false; 1741 + } 1751 1742 1752 1743 nbcon_state_set(con, &state); 1753 1744 ··· 1803 1762 ctxt->console = con; 1804 1763 ctxt->prio = NBCON_PRIO_NORMAL; 1805 1764 1806 - if (!nbcon_context_try_acquire(ctxt)) 1765 + if (!nbcon_context_try_acquire(ctxt, false)) 1807 1766 return false; 1808 1767 1809 1768 if (!nbcon_context_enter_unsafe(ctxt))
+11 -9
kernel/printk/printk.c
··· 3574 3574 static int unregister_console_locked(struct console *console); 3575 3575 3576 3576 /* True when system boot is far enough to create printer threads. */ 3577 - static bool printk_kthreads_ready __ro_after_init; 3577 + bool printk_kthreads_ready __ro_after_init; 3578 3578 3579 3579 static struct task_struct *printk_legacy_kthread; 3580 3580 ··· 3713 3713 if (!printk_kthreads_ready) 3714 3714 return; 3715 3715 3716 + /* Start or stop the legacy kthread when needed. */ 3716 3717 if (have_legacy_console || have_boot_console) { 3717 3718 if (!printk_legacy_kthread && 3718 3719 force_legacy_kthread() && ··· 4205 4204 */ 4206 4205 synchronize_srcu(&console_srcu); 4207 4206 4208 - if (console->flags & CON_NBCON) 4209 - nbcon_free(console); 4210 - 4211 - console_sysfs_notify(); 4212 - 4213 - if (console->exit) 4214 - res = console->exit(console); 4215 - 4216 4207 /* 4217 4208 * With this console gone, the global flags tracking registered 4218 4209 * console types may have changed. Update them. ··· 4224 4231 have_legacy_console = found_legacy_con; 4225 4232 if (!found_nbcon_con) 4226 4233 have_nbcon_console = found_nbcon_con; 4234 + 4235 + /* @have_nbcon_console must be updated before calling nbcon_free(). */ 4236 + if (console->flags & CON_NBCON) 4237 + nbcon_free(console); 4238 + 4239 + console_sysfs_notify(); 4240 + 4241 + if (console->exit) 4242 + res = console->exit(console); 4227 4243 4228 4244 /* Changed console list, may require printer threads to start/stop. */ 4229 4245 printk_kthreads_check_locked();
+54 -15
kernel/relay.c
··· 118 118 return NULL; 119 119 120 120 for (i = 0; i < n_pages; i++) { 121 - buf->page_array[i] = alloc_page(GFP_KERNEL); 121 + buf->page_array[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); 122 122 if (unlikely(!buf->page_array[i])) 123 123 goto depopulate; 124 124 set_page_private(buf->page_array[i], (unsigned long)buf); ··· 127 127 if (!mem) 128 128 goto depopulate; 129 129 130 - memset(mem, 0, *size); 131 130 buf->page_count = n_pages; 132 131 return mem; 133 132 ··· 249 250 */ 250 251 251 252 static int relay_subbuf_start(struct rchan_buf *buf, void *subbuf, 252 - void *prev_subbuf, size_t prev_padding) 253 + void *prev_subbuf) 253 254 { 255 + int full = relay_buf_full(buf); 256 + 257 + if (full) 258 + buf->stats.full_count++; 259 + 254 260 if (!buf->chan->cb->subbuf_start) 255 - return !relay_buf_full(buf); 261 + return !full; 256 262 257 263 return buf->chan->cb->subbuf_start(buf, subbuf, 258 - prev_subbuf, prev_padding); 264 + prev_subbuf); 259 265 } 260 266 261 267 /** ··· 302 298 buf->finalized = 0; 303 299 buf->data = buf->start; 304 300 buf->offset = 0; 301 + buf->stats.full_count = 0; 302 + buf->stats.big_count = 0; 305 303 306 304 for (i = 0; i < buf->chan->n_subbufs; i++) 307 305 buf->padding[i] = 0; 308 306 309 - relay_subbuf_start(buf, buf->data, NULL, 0); 307 + relay_subbuf_start(buf, buf->data, NULL); 310 308 } 311 309 312 310 /** ··· 561 555 goto toobig; 562 556 563 557 if (buf->offset != buf->chan->subbuf_size + 1) { 564 - buf->prev_padding = buf->chan->subbuf_size - buf->offset; 558 + size_t prev_padding; 559 + 560 + prev_padding = buf->chan->subbuf_size - buf->offset; 565 561 old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; 566 - buf->padding[old_subbuf] = buf->prev_padding; 562 + buf->padding[old_subbuf] = prev_padding; 567 563 buf->subbufs_produced++; 568 564 if (buf->dentry) 569 565 d_inode(buf->dentry)->i_size += ··· 590 582 new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; 591 583 new = buf->start + new_subbuf * buf->chan->subbuf_size; 592 584 buf->offset = 0; 593 - if (!relay_subbuf_start(buf, new, old, buf->prev_padding)) { 585 + if (!relay_subbuf_start(buf, new, old)) { 594 586 buf->offset = buf->chan->subbuf_size + 1; 595 587 return 0; 596 588 } ··· 603 595 return length; 604 596 605 597 toobig: 606 - buf->chan->last_toobig = length; 598 + buf->stats.big_count++; 607 599 return 0; 608 600 } 609 601 EXPORT_SYMBOL_GPL(relay_switch_subbuf); ··· 663 655 if ((buf = *per_cpu_ptr(chan->buf, i))) 664 656 relay_close_buf(buf); 665 657 666 - if (chan->last_toobig) 667 - printk(KERN_WARNING "relay: one or more items not logged " 668 - "[item size (%zd) > sub-buffer size (%zd)]\n", 669 - chan->last_toobig, chan->subbuf_size); 670 - 671 658 list_del(&chan->list); 672 659 kref_put(&chan->kref, relay_destroy_channel); 673 660 mutex_unlock(&relay_channels_mutex); ··· 695 692 mutex_unlock(&relay_channels_mutex); 696 693 } 697 694 EXPORT_SYMBOL_GPL(relay_flush); 695 + 696 + /** 697 + * relay_stats - get channel buffer statistics 698 + * @chan: the channel 699 + * @flags: select particular information to get 700 + * 701 + * Returns the count of certain field that caller specifies. 702 + */ 703 + size_t relay_stats(struct rchan *chan, int flags) 704 + { 705 + unsigned int i, count = 0; 706 + struct rchan_buf *rbuf; 707 + 708 + if (!chan || flags > RELAY_STATS_LAST) 709 + return 0; 710 + 711 + if (chan->is_global) { 712 + rbuf = *per_cpu_ptr(chan->buf, 0); 713 + if (flags & RELAY_STATS_BUF_FULL) 714 + count = rbuf->stats.full_count; 715 + else if (flags & RELAY_STATS_WRT_BIG) 716 + count = rbuf->stats.big_count; 717 + } else { 718 + for_each_online_cpu(i) { 719 + rbuf = *per_cpu_ptr(chan->buf, i); 720 + if (rbuf) { 721 + if (flags & RELAY_STATS_BUF_FULL) 722 + count += rbuf->stats.full_count; 723 + else if (flags & RELAY_STATS_WRT_BIG) 724 + count += rbuf->stats.big_count; 725 + } 726 + } 727 + } 728 + 729 + return count; 730 + } 698 731 699 732 /** 700 733 * relay_file_open - open file op for relay files
+1 -5
kernel/sched/psi.c
··· 176 176 .pcpu = &system_group_pcpu, 177 177 }; 178 178 179 - static DEFINE_PER_CPU(seqcount_t, psi_seq); 179 + static DEFINE_PER_CPU(seqcount_t, psi_seq) = SEQCNT_ZERO(psi_seq); 180 180 181 181 static inline void psi_write_begin(int cpu) 182 182 { ··· 204 204 205 205 static void group_init(struct psi_group *group) 206 206 { 207 - int cpu; 208 - 209 207 group->enabled = true; 210 - for_each_possible_cpu(cpu) 211 - seqcount_init(per_cpu_ptr(&psi_seq, cpu)); 212 208 group->avg_last_update = sched_clock(); 213 209 group->avg_next_update = group->avg_last_update + psi_period; 214 210 mutex_init(&group->avgs_lock);
+2 -20
kernel/trace/blktrace.c
··· 415 415 size_t count, loff_t *ppos) 416 416 { 417 417 struct blk_trace *bt = filp->private_data; 418 + size_t dropped = relay_stats(bt->rchan, RELAY_STATS_BUF_FULL); 418 419 char buf[16]; 419 420 420 - snprintf(buf, sizeof(buf), "%u\n", atomic_read(&bt->dropped)); 421 + snprintf(buf, sizeof(buf), "%zu\n", dropped); 421 422 422 423 return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 423 424 } ··· 457 456 .llseek = noop_llseek, 458 457 }; 459 458 460 - /* 461 - * Keep track of how many times we encountered a full subbuffer, to aid 462 - * the user space app in telling how many lost events there were. 463 - */ 464 - static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, 465 - void *prev_subbuf, size_t prev_padding) 466 - { 467 - struct blk_trace *bt; 468 - 469 - if (!relay_buf_full(buf)) 470 - return 1; 471 - 472 - bt = buf->chan->private_data; 473 - atomic_inc(&bt->dropped); 474 - return 0; 475 - } 476 - 477 459 static int blk_remove_buf_file_callback(struct dentry *dentry) 478 460 { 479 461 debugfs_remove(dentry); ··· 475 491 } 476 492 477 493 static const struct rchan_callbacks blk_relay_callbacks = { 478 - .subbuf_start = blk_subbuf_start_callback, 479 494 .create_buf_file = blk_create_buf_file_callback, 480 495 .remove_buf_file = blk_remove_buf_file_callback, 481 496 }; ··· 563 580 } 564 581 565 582 bt->dev = dev; 566 - atomic_set(&bt->dropped, 0); 567 583 INIT_LIST_HEAD(&bt->running_list); 568 584 569 585 ret = -EIO;
+6 -10
kernel/trace/ring_buffer.c
··· 4812 4812 int ret = -EBUSY; 4813 4813 int cpu; 4814 4814 4815 - preempt_disable_notrace(); 4815 + guard(preempt_notrace)(); 4816 4816 4817 4817 if (atomic_read(&buffer->record_disabled)) 4818 - goto out; 4818 + return -EBUSY; 4819 4819 4820 4820 cpu = raw_smp_processor_id(); 4821 4821 4822 4822 if (!cpumask_test_cpu(cpu, buffer->cpumask)) 4823 - goto out; 4823 + return -EBUSY; 4824 4824 4825 4825 cpu_buffer = buffer->buffers[cpu]; 4826 4826 4827 4827 if (atomic_read(&cpu_buffer->record_disabled)) 4828 - goto out; 4828 + return -EBUSY; 4829 4829 4830 4830 if (length > buffer->max_data_size) 4831 - goto out; 4831 + return -EBUSY; 4832 4832 4833 4833 if (unlikely(trace_recursive_lock(cpu_buffer))) 4834 - goto out; 4834 + return -EBUSY; 4835 4835 4836 4836 event = rb_reserve_next_event(buffer, cpu_buffer, length); 4837 4837 if (!event) ··· 4849 4849 4850 4850 out_unlock: 4851 4851 trace_recursive_unlock(cpu_buffer); 4852 - 4853 - out: 4854 - preempt_enable_notrace(); 4855 - 4856 4852 return ret; 4857 4853 } 4858 4854 EXPORT_SYMBOL_GPL(ring_buffer_write);
+103 -186
kernel/trace/trace.c
··· 432 432 { 433 433 struct trace_export *export; 434 434 435 - preempt_disable_notrace(); 435 + guard(preempt_notrace)(); 436 436 437 437 export = rcu_dereference_raw_check(ftrace_exports_list); 438 438 while (export) { 439 439 trace_process_export(export, event, flag); 440 440 export = rcu_dereference_raw_check(export->next); 441 441 } 442 - 443 - preempt_enable_notrace(); 444 442 } 445 443 446 444 static inline void ··· 495 497 if (WARN_ON_ONCE(!export->write)) 496 498 return -1; 497 499 498 - mutex_lock(&ftrace_export_lock); 500 + guard(mutex)(&ftrace_export_lock); 499 501 500 502 add_ftrace_export(&ftrace_exports_list, export); 501 - 502 - mutex_unlock(&ftrace_export_lock); 503 503 504 504 return 0; 505 505 } ··· 505 509 506 510 int unregister_ftrace_export(struct trace_export *export) 507 511 { 508 - int ret; 509 - 510 - mutex_lock(&ftrace_export_lock); 511 - 512 - ret = rm_ftrace_export(&ftrace_exports_list, export); 513 - 514 - mutex_unlock(&ftrace_export_lock); 515 - 516 - return ret; 512 + guard(mutex)(&ftrace_export_lock); 513 + return rm_ftrace_export(&ftrace_exports_list, export); 517 514 } 518 515 EXPORT_SYMBOL_GPL(unregister_ftrace_export); 519 516 ··· 629 640 if (!this_tr) 630 641 return; 631 642 632 - mutex_lock(&trace_types_lock); 643 + guard(mutex)(&trace_types_lock); 633 644 __trace_array_put(this_tr); 634 - mutex_unlock(&trace_types_lock); 635 645 } 636 646 EXPORT_SYMBOL_GPL(trace_array_put); 637 647 ··· 1148 1160 1149 1161 trace_ctx = tracing_gen_ctx(); 1150 1162 buffer = tr->array_buffer.buffer; 1151 - ring_buffer_nest_start(buffer); 1163 + guard(ring_buffer_nest)(buffer); 1152 1164 event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc, 1153 1165 trace_ctx); 1154 - if (!event) { 1155 - size = 0; 1156 - goto out; 1157 - } 1166 + if (!event) 1167 + return 0; 1158 1168 1159 1169 entry = ring_buffer_event_data(event); 1160 1170 entry->ip = ip; ··· 1168 1182 1169 1183 __buffer_unlock_commit(buffer, event); 1170 1184 ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL); 1171 - out: 1172 - ring_buffer_nest_end(buffer); 1173 1185 return size; 1174 1186 } 1175 1187 EXPORT_SYMBOL_GPL(__trace_array_puts); ··· 1197 1213 struct bputs_entry *entry; 1198 1214 unsigned int trace_ctx; 1199 1215 int size = sizeof(struct bputs_entry); 1200 - int ret = 0; 1201 1216 1202 1217 if (!printk_binsafe(tr)) 1203 1218 return __trace_puts(ip, str, strlen(str)); ··· 1210 1227 trace_ctx = tracing_gen_ctx(); 1211 1228 buffer = tr->array_buffer.buffer; 1212 1229 1213 - ring_buffer_nest_start(buffer); 1230 + guard(ring_buffer_nest)(buffer); 1214 1231 event = __trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size, 1215 1232 trace_ctx); 1216 1233 if (!event) 1217 - goto out; 1234 + return 0; 1218 1235 1219 1236 entry = ring_buffer_event_data(event); 1220 1237 entry->ip = ip; ··· 1223 1240 __buffer_unlock_commit(buffer, event); 1224 1241 ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL); 1225 1242 1226 - ret = 1; 1227 - out: 1228 - ring_buffer_nest_end(buffer); 1229 - return ret; 1243 + return 1; 1230 1244 } 1231 1245 EXPORT_SYMBOL_GPL(__trace_bputs); 1232 1246 ··· 1412 1432 1413 1433 int tracing_arm_snapshot(struct trace_array *tr) 1414 1434 { 1415 - int ret; 1416 - 1417 - mutex_lock(&trace_types_lock); 1418 - ret = tracing_arm_snapshot_locked(tr); 1419 - mutex_unlock(&trace_types_lock); 1420 - 1421 - return ret; 1435 + guard(mutex)(&trace_types_lock); 1436 + return tracing_arm_snapshot_locked(tr); 1422 1437 } 1423 1438 1424 1439 void tracing_disarm_snapshot(struct trace_array *tr) ··· 1816 1841 1817 1842 ret = get_user(ch, ubuf++); 1818 1843 if (ret) 1819 - goto out; 1844 + return ret; 1820 1845 1821 1846 read++; 1822 1847 cnt--; ··· 1830 1855 while (cnt && isspace(ch)) { 1831 1856 ret = get_user(ch, ubuf++); 1832 1857 if (ret) 1833 - goto out; 1858 + return ret; 1834 1859 read++; 1835 1860 cnt--; 1836 1861 } ··· 1840 1865 /* only spaces were written */ 1841 1866 if (isspace(ch) || !ch) { 1842 1867 *ppos += read; 1843 - ret = read; 1844 - goto out; 1868 + return read; 1845 1869 } 1846 1870 } 1847 1871 ··· 1848 1874 while (cnt && !isspace(ch) && ch) { 1849 1875 if (parser->idx < parser->size - 1) 1850 1876 parser->buffer[parser->idx++] = ch; 1851 - else { 1852 - ret = -EINVAL; 1853 - goto out; 1854 - } 1877 + else 1878 + return -EINVAL; 1879 + 1855 1880 ret = get_user(ch, ubuf++); 1856 1881 if (ret) 1857 - goto out; 1882 + return ret; 1858 1883 read++; 1859 1884 cnt--; 1860 1885 } ··· 1868 1895 /* Make sure the parsed string always terminates with '\0'. */ 1869 1896 parser->buffer[parser->idx] = 0; 1870 1897 } else { 1871 - ret = -EINVAL; 1872 - goto out; 1898 + return -EINVAL; 1873 1899 } 1874 1900 1875 1901 *ppos += read; 1876 - ret = read; 1877 - 1878 - out: 1879 - return ret; 1902 + return read; 1880 1903 } 1881 1904 1882 1905 /* TODO add a seq_buf_to_buffer() */ ··· 2374 2405 mutex_unlock(&trace_types_lock); 2375 2406 2376 2407 if (ret || !default_bootup_tracer) 2377 - goto out_unlock; 2408 + return ret; 2378 2409 2379 2410 if (strncmp(default_bootup_tracer, type->name, MAX_TRACER_SIZE)) 2380 - goto out_unlock; 2411 + return 0; 2381 2412 2382 2413 printk(KERN_INFO "Starting tracer '%s'\n", type->name); 2383 2414 /* Do we want this tracer to start on bootup? */ ··· 2389 2420 /* disable other selftests, since this will break it. */ 2390 2421 disable_tracing_selftest("running a tracer"); 2391 2422 2392 - out_unlock: 2393 - return ret; 2423 + return 0; 2394 2424 } 2395 2425 2396 2426 static void tracing_reset_cpu(struct array_buffer *buf, int cpu) ··· 2466 2498 2467 2499 void tracing_reset_all_online_cpus(void) 2468 2500 { 2469 - mutex_lock(&trace_types_lock); 2501 + guard(mutex)(&trace_types_lock); 2470 2502 tracing_reset_all_online_cpus_unlocked(); 2471 - mutex_unlock(&trace_types_lock); 2472 2503 } 2473 2504 2474 2505 int is_tracing_stopped(void) ··· 2478 2511 static void tracing_start_tr(struct trace_array *tr) 2479 2512 { 2480 2513 struct trace_buffer *buffer; 2481 - unsigned long flags; 2482 2514 2483 2515 if (tracing_disabled) 2484 2516 return; 2485 2517 2486 - raw_spin_lock_irqsave(&tr->start_lock, flags); 2518 + guard(raw_spinlock_irqsave)(&tr->start_lock); 2487 2519 if (--tr->stop_count) { 2488 2520 if (WARN_ON_ONCE(tr->stop_count < 0)) { 2489 2521 /* Someone screwed up their debugging */ 2490 2522 tr->stop_count = 0; 2491 2523 } 2492 - goto out; 2524 + return; 2493 2525 } 2494 2526 2495 2527 /* Prevent the buffers from switching */ ··· 2505 2539 #endif 2506 2540 2507 2541 arch_spin_unlock(&tr->max_lock); 2508 - 2509 - out: 2510 - raw_spin_unlock_irqrestore(&tr->start_lock, flags); 2511 2542 } 2512 2543 2513 2544 /** ··· 2522 2559 static void tracing_stop_tr(struct trace_array *tr) 2523 2560 { 2524 2561 struct trace_buffer *buffer; 2525 - unsigned long flags; 2526 2562 2527 - raw_spin_lock_irqsave(&tr->start_lock, flags); 2563 + guard(raw_spinlock_irqsave)(&tr->start_lock); 2528 2564 if (tr->stop_count++) 2529 - goto out; 2565 + return; 2530 2566 2531 2567 /* Prevent the buffers from switching */ 2532 2568 arch_spin_lock(&tr->max_lock); ··· 2541 2579 #endif 2542 2580 2543 2581 arch_spin_unlock(&tr->max_lock); 2544 - 2545 - out: 2546 - raw_spin_unlock_irqrestore(&tr->start_lock, flags); 2547 2582 } 2548 2583 2549 2584 /** ··· 2653 2694 2654 2695 per_cpu(trace_buffered_event, cpu) = event; 2655 2696 2656 - preempt_disable(); 2657 - if (cpu == smp_processor_id() && 2658 - __this_cpu_read(trace_buffered_event) != 2659 - per_cpu(trace_buffered_event, cpu)) 2660 - WARN_ON_ONCE(1); 2661 - preempt_enable(); 2697 + scoped_guard(preempt,) { 2698 + if (cpu == smp_processor_id() && 2699 + __this_cpu_read(trace_buffered_event) != 2700 + per_cpu(trace_buffered_event, cpu)) 2701 + WARN_ON_ONCE(1); 2702 + } 2662 2703 } 2663 2704 } 2664 2705 ··· 3003 3044 skip++; 3004 3045 #endif 3005 3046 3006 - preempt_disable_notrace(); 3047 + guard(preempt_notrace)(); 3007 3048 3008 3049 stackidx = __this_cpu_inc_return(ftrace_stack_reserve) - 1; 3009 3050 ··· 3061 3102 /* Again, don't let gcc optimize things here */ 3062 3103 barrier(); 3063 3104 __this_cpu_dec(ftrace_stack_reserve); 3064 - preempt_enable_notrace(); 3065 - 3066 3105 } 3067 3106 3068 3107 static inline void ftrace_trace_stack(struct trace_array *tr, ··· 3143 3186 * prevent recursion, since the user stack tracing may 3144 3187 * trigger other kernel events. 3145 3188 */ 3146 - preempt_disable(); 3189 + guard(preempt)(); 3147 3190 if (__this_cpu_read(user_stack_count)) 3148 - goto out; 3191 + return; 3149 3192 3150 3193 __this_cpu_inc(user_stack_count); 3151 3194 ··· 3163 3206 3164 3207 out_drop_count: 3165 3208 __this_cpu_dec(user_stack_count); 3166 - out: 3167 - preempt_enable(); 3168 3209 } 3169 3210 #else /* CONFIG_USER_STACKTRACE_SUPPORT */ 3170 3211 static void ftrace_trace_userstack(struct trace_array *tr, ··· 3344 3389 pause_graph_tracing(); 3345 3390 3346 3391 trace_ctx = tracing_gen_ctx(); 3347 - preempt_disable_notrace(); 3392 + guard(preempt_notrace)(); 3348 3393 3349 3394 tbuffer = get_trace_buf(); 3350 3395 if (!tbuffer) { ··· 3359 3404 3360 3405 size = sizeof(*entry) + sizeof(u32) * len; 3361 3406 buffer = tr->array_buffer.buffer; 3362 - ring_buffer_nest_start(buffer); 3363 - event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size, 3364 - trace_ctx); 3365 - if (!event) 3366 - goto out; 3367 - entry = ring_buffer_event_data(event); 3368 - entry->ip = ip; 3369 - entry->fmt = fmt; 3407 + scoped_guard(ring_buffer_nest, buffer) { 3408 + event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size, 3409 + trace_ctx); 3410 + if (!event) 3411 + goto out_put; 3412 + entry = ring_buffer_event_data(event); 3413 + entry->ip = ip; 3414 + entry->fmt = fmt; 3370 3415 3371 - memcpy(entry->buf, tbuffer, sizeof(u32) * len); 3372 - __buffer_unlock_commit(buffer, event); 3373 - ftrace_trace_stack(tr, buffer, trace_ctx, 6, NULL); 3374 - 3375 - out: 3376 - ring_buffer_nest_end(buffer); 3416 + memcpy(entry->buf, tbuffer, sizeof(u32) * len); 3417 + __buffer_unlock_commit(buffer, event); 3418 + ftrace_trace_stack(tr, buffer, trace_ctx, 6, NULL); 3419 + } 3377 3420 out_put: 3378 3421 put_trace_buf(); 3379 3422 3380 3423 out_nobuffer: 3381 - preempt_enable_notrace(); 3382 3424 unpause_graph_tracing(); 3383 3425 3384 3426 return len; ··· 3399 3447 pause_graph_tracing(); 3400 3448 3401 3449 trace_ctx = tracing_gen_ctx(); 3402 - preempt_disable_notrace(); 3450 + guard(preempt_notrace)(); 3403 3451 3404 3452 3405 3453 tbuffer = get_trace_buf(); ··· 3411 3459 len = vscnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args); 3412 3460 3413 3461 size = sizeof(*entry) + len + 1; 3414 - ring_buffer_nest_start(buffer); 3415 - event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size, 3416 - trace_ctx); 3417 - if (!event) 3418 - goto out; 3419 - entry = ring_buffer_event_data(event); 3420 - entry->ip = ip; 3462 + scoped_guard(ring_buffer_nest, buffer) { 3463 + event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size, 3464 + trace_ctx); 3465 + if (!event) 3466 + goto out; 3467 + entry = ring_buffer_event_data(event); 3468 + entry->ip = ip; 3421 3469 3422 - memcpy(&entry->buf, tbuffer, len + 1); 3423 - __buffer_unlock_commit(buffer, event); 3424 - ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL); 3425 - 3470 + memcpy(&entry->buf, tbuffer, len + 1); 3471 + __buffer_unlock_commit(buffer, event); 3472 + ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL); 3473 + } 3426 3474 out: 3427 - ring_buffer_nest_end(buffer); 3428 3475 put_trace_buf(); 3429 3476 3430 3477 out_nobuffer: 3431 - preempt_enable_notrace(); 3432 3478 unpause_graph_tracing(); 3433 3479 3434 3480 return len; ··· 4750 4800 if (ret) 4751 4801 return ret; 4752 4802 4753 - mutex_lock(&event_mutex); 4803 + guard(mutex)(&event_mutex); 4754 4804 4755 4805 /* Fail if the file is marked for removal */ 4756 4806 if (file->flags & EVENT_FILE_FL_FREED) { 4757 4807 trace_array_put(file->tr); 4758 - ret = -ENODEV; 4808 + return -ENODEV; 4759 4809 } else { 4760 4810 event_file_get(file); 4761 4811 } 4762 - 4763 - mutex_unlock(&event_mutex); 4764 - if (ret) 4765 - return ret; 4766 4812 4767 4813 filp->private_data = inode->i_private; 4768 4814 ··· 5036 5090 size_t count, loff_t *ppos) 5037 5091 { 5038 5092 struct trace_array *tr = file_inode(filp)->i_private; 5039 - char *mask_str; 5093 + char *mask_str __free(kfree) = NULL; 5040 5094 int len; 5041 5095 5042 5096 len = snprintf(NULL, 0, "%*pb\n", ··· 5047 5101 5048 5102 len = snprintf(mask_str, len, "%*pb\n", 5049 5103 cpumask_pr_args(tr->tracing_cpumask)); 5050 - if (len >= count) { 5051 - count = -EINVAL; 5052 - goto out_err; 5053 - } 5054 - count = simple_read_from_buffer(ubuf, count, ppos, mask_str, len); 5104 + if (len >= count) 5105 + return -EINVAL; 5055 5106 5056 - out_err: 5057 - kfree(mask_str); 5058 - 5059 - return count; 5107 + return simple_read_from_buffer(ubuf, count, ppos, mask_str, len); 5060 5108 } 5061 5109 5062 5110 int tracing_set_cpumask(struct trace_array *tr, ··· 5897 5957 char buf[MAX_TRACER_SIZE+2]; 5898 5958 int r; 5899 5959 5900 - mutex_lock(&trace_types_lock); 5901 - r = sprintf(buf, "%s\n", tr->current_trace->name); 5902 - mutex_unlock(&trace_types_lock); 5960 + scoped_guard(mutex, &trace_types_lock) { 5961 + r = sprintf(buf, "%s\n", tr->current_trace->name); 5962 + } 5903 5963 5904 5964 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 5905 5965 } ··· 6201 6261 { 6202 6262 int ret = 0; 6203 6263 6204 - mutex_lock(&trace_types_lock); 6264 + guard(mutex)(&trace_types_lock); 6205 6265 6206 6266 update_last_data(tr); 6207 6267 6208 6268 if (!tr->ring_buffer_expanded) 6209 6269 ret = __tracing_resize_ring_buffer(tr, trace_buf_size, 6210 6270 RING_BUFFER_ALL_CPUS); 6211 - mutex_unlock(&trace_types_lock); 6212 - 6213 6271 return ret; 6214 6272 } 6215 6273 ··· 6504 6566 if (ret) 6505 6567 return ret; 6506 6568 6507 - mutex_lock(&trace_types_lock); 6569 + guard(mutex)(&trace_types_lock); 6508 6570 cpu = tracing_get_cpu(inode); 6509 6571 ret = open_pipe_on_cpu(tr, cpu); 6510 6572 if (ret) ··· 6548 6610 6549 6611 tr->trace_ref++; 6550 6612 6551 - mutex_unlock(&trace_types_lock); 6552 6613 return ret; 6553 6614 6554 6615 fail: ··· 6556 6619 close_pipe_on_cpu(tr, cpu); 6557 6620 fail_pipe_on_cpu: 6558 6621 __trace_array_put(tr); 6559 - mutex_unlock(&trace_types_lock); 6560 6622 return ret; 6561 6623 } 6562 6624 ··· 6564 6628 struct trace_iterator *iter = file->private_data; 6565 6629 struct trace_array *tr = inode->i_private; 6566 6630 6567 - mutex_lock(&trace_types_lock); 6631 + scoped_guard(mutex, &trace_types_lock) { 6632 + tr->trace_ref--; 6568 6633 6569 - tr->trace_ref--; 6570 - 6571 - if (iter->trace->pipe_close) 6572 - iter->trace->pipe_close(iter); 6573 - close_pipe_on_cpu(tr, iter->cpu_file); 6574 - mutex_unlock(&trace_types_lock); 6634 + if (iter->trace->pipe_close) 6635 + iter->trace->pipe_close(iter); 6636 + close_pipe_on_cpu(tr, iter->cpu_file); 6637 + } 6575 6638 6576 6639 free_trace_iter_content(iter); 6577 6640 kfree(iter); ··· 7373 7438 if (i == ARRAY_SIZE(trace_clocks)) 7374 7439 return -EINVAL; 7375 7440 7376 - mutex_lock(&trace_types_lock); 7441 + guard(mutex)(&trace_types_lock); 7377 7442 7378 7443 tr->clock_id = i; 7379 7444 ··· 7396 7461 7397 7462 tscratch->clock_id = i; 7398 7463 } 7399 - 7400 - mutex_unlock(&trace_types_lock); 7401 7464 7402 7465 return 0; 7403 7466 } ··· 7448 7515 { 7449 7516 struct trace_array *tr = m->private; 7450 7517 7451 - mutex_lock(&trace_types_lock); 7518 + guard(mutex)(&trace_types_lock); 7452 7519 7453 7520 if (ring_buffer_time_stamp_abs(tr->array_buffer.buffer)) 7454 7521 seq_puts(m, "delta [absolute]\n"); 7455 7522 else 7456 7523 seq_puts(m, "[delta] absolute\n"); 7457 - 7458 - mutex_unlock(&trace_types_lock); 7459 7524 7460 7525 return 0; 7461 7526 } ··· 8042 8111 { 8043 8112 struct tracing_log_err *err, *next; 8044 8113 8045 - mutex_lock(&tracing_err_log_lock); 8114 + guard(mutex)(&tracing_err_log_lock); 8115 + 8046 8116 list_for_each_entry_safe(err, next, &tr->err_log, list) { 8047 8117 list_del(&err->list); 8048 8118 free_tracing_log_err(err); 8049 8119 } 8050 8120 8051 8121 tr->n_err_log_entries = 0; 8052 - mutex_unlock(&tracing_err_log_lock); 8053 8122 } 8054 8123 8055 8124 static void *tracing_err_log_seq_start(struct seq_file *m, loff_t *pos) ··· 8320 8389 struct ftrace_buffer_info *info = file->private_data; 8321 8390 struct trace_iterator *iter = &info->iter; 8322 8391 8323 - mutex_lock(&trace_types_lock); 8392 + guard(mutex)(&trace_types_lock); 8324 8393 8325 8394 iter->tr->trace_ref--; 8326 8395 ··· 8330 8399 ring_buffer_free_read_page(iter->array_buffer->buffer, 8331 8400 info->spare_cpu, info->spare); 8332 8401 kvfree(info); 8333 - 8334 - mutex_unlock(&trace_types_lock); 8335 8402 8336 8403 return 0; 8337 8404 } ··· 8538 8609 * An ioctl call with cmd 0 to the ring buffer file will wake up all 8539 8610 * waiters 8540 8611 */ 8541 - mutex_lock(&trace_types_lock); 8612 + guard(mutex)(&trace_types_lock); 8542 8613 8543 8614 /* Make sure the waiters see the new wait_index */ 8544 8615 (void)atomic_fetch_inc_release(&iter->wait_index); 8545 8616 8546 8617 ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file); 8547 8618 8548 - mutex_unlock(&trace_types_lock); 8549 8619 return 0; 8550 8620 } 8551 8621 ··· 8885 8957 out_reg: 8886 8958 ret = tracing_arm_snapshot(tr); 8887 8959 if (ret < 0) 8888 - goto out; 8960 + return ret; 8889 8961 8890 8962 ret = register_ftrace_function_probe(glob, tr, ops, count); 8891 8963 if (ret < 0) 8892 8964 tracing_disarm_snapshot(tr); 8893 - out: 8965 + 8894 8966 return ret < 0 ? ret : 0; 8895 8967 } 8896 8968 ··· 9034 9106 return -EINVAL; 9035 9107 9036 9108 if (!!(topt->flags->val & topt->opt->bit) != val) { 9037 - mutex_lock(&trace_types_lock); 9109 + guard(mutex)(&trace_types_lock); 9038 9110 ret = __set_tracer_option(topt->tr, topt->flags, 9039 9111 topt->opt, !val); 9040 - mutex_unlock(&trace_types_lock); 9041 9112 if (ret) 9042 9113 return ret; 9043 9114 } ··· 9345 9418 return ret; 9346 9419 9347 9420 if (buffer) { 9348 - mutex_lock(&trace_types_lock); 9421 + guard(mutex)(&trace_types_lock); 9349 9422 if (!!val == tracer_tracing_is_on(tr)) { 9350 9423 val = 0; /* do nothing */ 9351 9424 } else if (val) { ··· 9359 9432 /* Wake up any waiters */ 9360 9433 ring_buffer_wake_waiters(buffer, RING_BUFFER_ALL_CPUS); 9361 9434 } 9362 - mutex_unlock(&trace_types_lock); 9363 9435 } 9364 9436 9365 9437 (*ppos)++; ··· 9742 9816 9743 9817 static void update_tracer_options(struct trace_array *tr) 9744 9818 { 9745 - mutex_lock(&trace_types_lock); 9819 + guard(mutex)(&trace_types_lock); 9746 9820 tracer_options_updated = true; 9747 9821 __update_tracer_options(tr); 9748 - mutex_unlock(&trace_types_lock); 9749 9822 } 9750 9823 9751 9824 /* Must have trace_types_lock held */ ··· 9766 9841 { 9767 9842 struct trace_array *tr; 9768 9843 9769 - mutex_lock(&trace_types_lock); 9844 + guard(mutex)(&trace_types_lock); 9770 9845 tr = trace_array_find(instance); 9771 9846 if (tr) 9772 9847 tr->ref++; 9773 - mutex_unlock(&trace_types_lock); 9774 9848 9775 9849 return tr; 9776 9850 } ··· 10300 10376 { 10301 10377 /* All modules have the symbol __this_module */ 10302 10378 static const char this_mod[] = "__this_module"; 10303 - char modname[MAX_PARAM_PREFIX_LEN + sizeof(this_mod) + 2]; 10379 + char modname[MODULE_NAME_LEN + sizeof(this_mod) + 2]; 10304 10380 unsigned long val; 10305 10381 int n; 10306 10382 ··· 10727 10803 size_t count, loff_t *ppos, 10728 10804 int (*createfn)(const char *)) 10729 10805 { 10730 - char *kbuf, *buf, *tmp; 10806 + char *kbuf __free(kfree) = NULL; 10807 + char *buf, *tmp; 10731 10808 int ret = 0; 10732 10809 size_t done = 0; 10733 10810 size_t size; ··· 10743 10818 if (size >= WRITE_BUFSIZE) 10744 10819 size = WRITE_BUFSIZE - 1; 10745 10820 10746 - if (copy_from_user(kbuf, buffer + done, size)) { 10747 - ret = -EFAULT; 10748 - goto out; 10749 - } 10821 + if (copy_from_user(kbuf, buffer + done, size)) 10822 + return -EFAULT; 10823 + 10750 10824 kbuf[size] = '\0'; 10751 10825 buf = kbuf; 10752 10826 do { ··· 10761 10837 /* This can accept WRITE_BUFSIZE - 2 ('\n' + '\0') */ 10762 10838 pr_warn("Line length is too long: Should be less than %d\n", 10763 10839 WRITE_BUFSIZE - 2); 10764 - ret = -EINVAL; 10765 - goto out; 10840 + return -EINVAL; 10766 10841 } 10767 10842 } 10768 10843 done += size; ··· 10774 10851 10775 10852 ret = createfn(buf); 10776 10853 if (ret) 10777 - goto out; 10854 + return ret; 10778 10855 buf += size; 10779 10856 10780 10857 } while (done < count); 10781 10858 } 10782 - ret = done; 10783 - 10784 - out: 10785 - kfree(kbuf); 10786 - 10787 - return ret; 10859 + return done; 10788 10860 } 10789 10861 10790 10862 #ifdef CONFIG_TRACER_MAX_TRACE ··· 10982 11064 BUILD_BUG_ON(TRACE_ITER_LAST_BIT > TRACE_FLAGS_MAX_SIZE); 10983 11065 10984 11066 if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL)) 10985 - goto out; 11067 + return -ENOMEM; 10986 11068 10987 11069 if (!alloc_cpumask_var(&global_trace.tracing_cpumask, GFP_KERNEL)) 10988 11070 goto out_free_buffer_mask; ··· 11100 11182 free_cpumask_var(global_trace.tracing_cpumask); 11101 11183 out_free_buffer_mask: 11102 11184 free_cpumask_var(tracing_buffer_mask); 11103 - out: 11104 11185 return ret; 11105 11186 } 11106 11187
+2 -4
kernel/trace/trace_events_synth.c
··· 536 536 * is being performed within another event. 537 537 */ 538 538 buffer = trace_file->tr->array_buffer.buffer; 539 - ring_buffer_nest_start(buffer); 539 + guard(ring_buffer_nest)(buffer); 540 540 541 541 entry = trace_event_buffer_reserve(&fbuffer, trace_file, 542 542 sizeof(*entry) + fields_size); 543 543 if (!entry) 544 - goto out; 544 + return; 545 545 546 546 for (i = 0, n_u64 = 0; i < event->n_fields; i++) { 547 547 val_idx = var_ref_idx[i]; ··· 584 584 } 585 585 586 586 trace_event_buffer_commit(&fbuffer); 587 - out: 588 - ring_buffer_nest_end(buffer); 589 587 } 590 588 591 589 static void free_synth_event_print_fmt(struct trace_event_call *call)
+7 -1
kernel/trace/trace_output.c
··· 701 701 struct btf *btf; 702 702 s32 tid, nr = 0; 703 703 int a, p, x; 704 + u16 encode; 704 705 705 706 trace_seq_printf(s, "("); 706 707 ··· 745 744 trace_seq_printf(s, "0x%lx", arg); 746 745 break; 747 746 case BTF_KIND_INT: 748 - trace_seq_printf(s, "%ld", arg); 747 + encode = btf_int_encoding(t); 748 + /* Print unsigned ints as hex */ 749 + if (encode & BTF_INT_SIGNED) 750 + trace_seq_printf(s, "%ld", arg); 751 + else 752 + trace_seq_printf(s, "0x%lx", arg); 749 753 break; 750 754 case BTF_KIND_ENUM: 751 755 trace_seq_printf(s, "%ld", arg);
+7 -9
kernel/ucount.c
··· 199 199 } 200 200 } 201 201 202 - static inline bool atomic_long_inc_below(atomic_long_t *v, int u) 202 + static inline bool atomic_long_inc_below(atomic_long_t *v, long u) 203 203 { 204 - long c, old; 205 - c = atomic_long_read(v); 206 - for (;;) { 204 + long c = atomic_long_read(v); 205 + 206 + do { 207 207 if (unlikely(c >= u)) 208 208 return false; 209 - old = atomic_long_cmpxchg(v, c, c+1); 210 - if (likely(old == c)) 211 - return true; 212 - c = old; 213 - } 209 + } while (!atomic_long_try_cmpxchg(v, &c, c+1)); 210 + 211 + return true; 214 212 } 215 213 216 214 struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
+20
lib/Kconfig.debug
··· 3214 3214 3215 3215 If unsure, say N. 3216 3216 3217 + config TEST_KEXEC_HANDOVER 3218 + bool "Test for Kexec HandOver" 3219 + default n 3220 + depends on KEXEC_HANDOVER 3221 + help 3222 + This option enables test for Kexec HandOver (KHO). 3223 + The test consists of two parts: saving kernel data before kexec and 3224 + restoring the data after kexec and verifying that it was properly 3225 + handed over. This test module creates and saves data on the boot of 3226 + the first kernel and restores and verifies the data on the boot of 3227 + kexec'ed kernel. 3228 + 3229 + For detailed documentation about KHO, see Documentation/core-api/kho. 3230 + 3231 + To run the test run: 3232 + 3233 + tools/testing/selftests/kho/vmtest.sh -h 3234 + 3235 + If unsure, say N. 3236 + 3217 3237 config RATELIMIT_KUNIT_TEST 3218 3238 tristate "KUnit Test for correctness and stress of ratelimit" if !KUNIT_ALL_TESTS 3219 3239 depends on KUNIT
+2 -1
lib/Makefile
··· 40 40 is_single_threaded.o plist.o decompress.o kobject_uevent.o \ 41 41 earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ 42 42 nmi_backtrace.o win_minmax.o memcat_p.o \ 43 - buildid.o objpool.o iomem_copy.o 43 + buildid.o objpool.o iomem_copy.o sys_info.o 44 44 45 45 lib-$(CONFIG_UNION_FIND) += union_find.o 46 46 lib-$(CONFIG_PRINTK) += dump_stack.o ··· 102 102 obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o 103 103 obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o 104 104 obj-$(CONFIG_TEST_OBJPOOL) += test_objpool.o 105 + obj-$(CONFIG_TEST_KEXEC_HANDOVER) += test_kho.o 105 106 106 107 obj-$(CONFIG_TEST_FPU) += test_fpu.o 107 108 test_fpu-y := test_fpu_glue.o test_fpu_impl.o
-8
lib/kunit/test.c
··· 802 802 } 803 803 EXPORT_SYMBOL_GPL(__kunit_test_suites_exit); 804 804 805 - #ifdef CONFIG_MODULES 806 805 static void kunit_module_init(struct module *mod) 807 806 { 808 807 struct kunit_suite_set suite_set, filtered_set; ··· 889 890 .notifier_call = kunit_module_notify, 890 891 .priority = 0, 891 892 }; 892 - #endif 893 893 894 894 KUNIT_DEFINE_ACTION_WRAPPER(kfree_action_wrapper, kfree, const void *) 895 895 ··· 979 981 kunit_debugfs_init(); 980 982 981 983 kunit_bus_init(); 982 - #ifdef CONFIG_MODULES 983 984 return register_module_notifier(&kunit_mod_nb); 984 - #else 985 - return 0; 986 - #endif 987 985 } 988 986 late_initcall(kunit_init); 989 987 990 988 static void __exit kunit_exit(void) 991 989 { 992 990 memset(&kunit_hooks, 0, sizeof(kunit_hooks)); 993 - #ifdef CONFIG_MODULES 994 991 unregister_module_notifier(&kunit_mod_nb); 995 - #endif 996 992 997 993 kunit_bus_shutdown(); 998 994
+7 -6
lib/math/div64.c
··· 212 212 213 213 #endif 214 214 215 - /* make sure c is not zero, trigger exception otherwise */ 216 - #pragma GCC diagnostic push 217 - #pragma GCC diagnostic ignored "-Wdiv-by-zero" 218 - if (unlikely(c == 0)) 219 - return 1/0; 220 - #pragma GCC diagnostic pop 215 + /* make sure c is not zero, trigger runtime exception otherwise */ 216 + if (unlikely(c == 0)) { 217 + unsigned long zero = 0; 218 + 219 + OPTIMIZER_HIDE_VAR(zero); 220 + return ~0UL/zero; 221 + } 221 222 222 223 int shift = __builtin_ctzll(c); 223 224
+15 -12
lib/math/gcd.c
··· 11 11 * has decent hardware division. 12 12 */ 13 13 14 + DEFINE_STATIC_KEY_TRUE(efficient_ffs_key); 15 + 14 16 #if !defined(CONFIG_CPU_NO_EFFICIENT_FFS) 15 17 16 18 /* If __ffs is available, the even/odd algorithm benchmarks slower. */ 17 19 18 - /** 19 - * gcd - calculate and return the greatest common divisor of 2 unsigned longs 20 - * @a: first value 21 - * @b: second value 22 - */ 23 - unsigned long gcd(unsigned long a, unsigned long b) 20 + static unsigned long binary_gcd(unsigned long a, unsigned long b) 24 21 { 25 22 unsigned long r = a | b; 26 - 27 - if (!a || !b) 28 - return r; 29 23 30 24 b >>= __ffs(b); 31 25 if (b == 1) ··· 38 44 } 39 45 } 40 46 41 - #else 47 + #endif 42 48 43 49 /* If normalization is done by loops, the even/odd algorithm is a win. */ 50 + 51 + /** 52 + * gcd - calculate and return the greatest common divisor of 2 unsigned longs 53 + * @a: first value 54 + * @b: second value 55 + */ 44 56 unsigned long gcd(unsigned long a, unsigned long b) 45 57 { 46 58 unsigned long r = a | b; 47 59 48 60 if (!a || !b) 49 61 return r; 62 + 63 + #if !defined(CONFIG_CPU_NO_EFFICIENT_FFS) 64 + if (static_branch_likely(&efficient_ffs_key)) 65 + return binary_gcd(a, b); 66 + #endif 50 67 51 68 /* Isolate lsbit of r */ 52 69 r &= -r; ··· 84 79 a >>= 1; 85 80 } 86 81 } 87 - 88 - #endif 89 82 90 83 EXPORT_SYMBOL_GPL(gcd);
-3
lib/raid6/algos.c
··· 18 18 #else 19 19 #include <linux/module.h> 20 20 #include <linux/gfp.h> 21 - /* In .bss so it's zeroed */ 22 - const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); 23 - EXPORT_SYMBOL(raid6_empty_zero_page); 24 21 #endif 25 22 26 23 struct raid6_calls raid6_call;
+3 -3
lib/raid6/recov.c
··· 31 31 Use the dead data pages as temporary storage for 32 32 delta p and delta q */ 33 33 dp = (u8 *)ptrs[faila]; 34 - ptrs[faila] = (void *)raid6_empty_zero_page; 34 + ptrs[faila] = raid6_get_zero_page(); 35 35 ptrs[disks-2] = dp; 36 36 dq = (u8 *)ptrs[failb]; 37 - ptrs[failb] = (void *)raid6_empty_zero_page; 37 + ptrs[failb] = raid6_get_zero_page(); 38 38 ptrs[disks-1] = dq; 39 39 40 40 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 72 72 /* Compute syndrome with zero for the missing data page 73 73 Use the dead data page as temporary storage for delta q */ 74 74 dq = (u8 *)ptrs[faila]; 75 - ptrs[faila] = (void *)raid6_empty_zero_page; 75 + ptrs[faila] = raid6_get_zero_page(); 76 76 ptrs[disks-1] = dq; 77 77 78 78 raid6_call.gen_syndrome(disks, bytes, ptrs);
+3 -3
lib/raid6/recov_avx2.c
··· 28 28 Use the dead data pages as temporary storage for 29 29 delta p and delta q */ 30 30 dp = (u8 *)ptrs[faila]; 31 - ptrs[faila] = (void *)raid6_empty_zero_page; 31 + ptrs[faila] = raid6_get_zero_page(); 32 32 ptrs[disks-2] = dp; 33 33 dq = (u8 *)ptrs[failb]; 34 - ptrs[failb] = (void *)raid6_empty_zero_page; 34 + ptrs[failb] = raid6_get_zero_page(); 35 35 ptrs[disks-1] = dq; 36 36 37 37 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 196 196 /* Compute syndrome with zero for the missing data page 197 197 Use the dead data page as temporary storage for delta q */ 198 198 dq = (u8 *)ptrs[faila]; 199 - ptrs[faila] = (void *)raid6_empty_zero_page; 199 + ptrs[faila] = raid6_get_zero_page(); 200 200 ptrs[disks-1] = dq; 201 201 202 202 raid6_call.gen_syndrome(disks, bytes, ptrs);
+3 -3
lib/raid6/recov_avx512.c
··· 37 37 */ 38 38 39 39 dp = (u8 *)ptrs[faila]; 40 - ptrs[faila] = (void *)raid6_empty_zero_page; 40 + ptrs[faila] = raid6_get_zero_page(); 41 41 ptrs[disks-2] = dp; 42 42 dq = (u8 *)ptrs[failb]; 43 - ptrs[failb] = (void *)raid6_empty_zero_page; 43 + ptrs[failb] = raid6_get_zero_page(); 44 44 ptrs[disks-1] = dq; 45 45 46 46 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 238 238 */ 239 239 240 240 dq = (u8 *)ptrs[faila]; 241 - ptrs[faila] = (void *)raid6_empty_zero_page; 241 + ptrs[faila] = raid6_get_zero_page(); 242 242 ptrs[disks-1] = dq; 243 243 244 244 raid6_call.gen_syndrome(disks, bytes, ptrs);
+6 -6
lib/raid6/recov_loongarch_simd.c
··· 42 42 * delta p and delta q 43 43 */ 44 44 dp = (u8 *)ptrs[faila]; 45 - ptrs[faila] = (void *)raid6_empty_zero_page; 45 + ptrs[faila] = raid6_get_zero_page(); 46 46 ptrs[disks - 2] = dp; 47 47 dq = (u8 *)ptrs[failb]; 48 - ptrs[failb] = (void *)raid6_empty_zero_page; 48 + ptrs[failb] = raid6_get_zero_page(); 49 49 ptrs[disks - 1] = dq; 50 50 51 51 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 197 197 * Use the dead data page as temporary storage for delta q 198 198 */ 199 199 dq = (u8 *)ptrs[faila]; 200 - ptrs[faila] = (void *)raid6_empty_zero_page; 200 + ptrs[faila] = raid6_get_zero_page(); 201 201 ptrs[disks - 1] = dq; 202 202 203 203 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 316 316 * delta p and delta q 317 317 */ 318 318 dp = (u8 *)ptrs[faila]; 319 - ptrs[faila] = (void *)raid6_empty_zero_page; 319 + ptrs[faila] = raid6_get_zero_page(); 320 320 ptrs[disks - 2] = dp; 321 321 dq = (u8 *)ptrs[failb]; 322 - ptrs[failb] = (void *)raid6_empty_zero_page; 322 + ptrs[failb] = raid6_get_zero_page(); 323 323 ptrs[disks - 1] = dq; 324 324 325 325 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 436 436 * Use the dead data page as temporary storage for delta q 437 437 */ 438 438 dq = (u8 *)ptrs[faila]; 439 - ptrs[faila] = (void *)raid6_empty_zero_page; 439 + ptrs[faila] = raid6_get_zero_page(); 440 440 ptrs[disks - 1] = dq; 441 441 442 442 raid6_call.gen_syndrome(disks, bytes, ptrs);
+3 -3
lib/raid6/recov_neon.c
··· 36 36 * delta p and delta q 37 37 */ 38 38 dp = (u8 *)ptrs[faila]; 39 - ptrs[faila] = (void *)raid6_empty_zero_page; 39 + ptrs[faila] = raid6_get_zero_page(); 40 40 ptrs[disks - 2] = dp; 41 41 dq = (u8 *)ptrs[failb]; 42 - ptrs[failb] = (void *)raid6_empty_zero_page; 42 + ptrs[failb] = raid6_get_zero_page(); 43 43 ptrs[disks - 1] = dq; 44 44 45 45 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 74 74 * Use the dead data page as temporary storage for delta q 75 75 */ 76 76 dq = (u8 *)ptrs[faila]; 77 - ptrs[faila] = (void *)raid6_empty_zero_page; 77 + ptrs[faila] = raid6_get_zero_page(); 78 78 ptrs[disks - 1] = dq; 79 79 80 80 raid6_call.gen_syndrome(disks, bytes, ptrs);
+3 -3
lib/raid6/recov_rvv.c
··· 165 165 * delta p and delta q 166 166 */ 167 167 dp = (u8 *)ptrs[faila]; 168 - ptrs[faila] = (void *)raid6_empty_zero_page; 168 + ptrs[faila] = raid6_get_zero_page(); 169 169 ptrs[disks - 2] = dp; 170 170 dq = (u8 *)ptrs[failb]; 171 - ptrs[failb] = (void *)raid6_empty_zero_page; 171 + ptrs[failb] = raid6_get_zero_page(); 172 172 ptrs[disks - 1] = dq; 173 173 174 174 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 203 203 * Use the dead data page as temporary storage for delta q 204 204 */ 205 205 dq = (u8 *)ptrs[faila]; 206 - ptrs[faila] = (void *)raid6_empty_zero_page; 206 + ptrs[faila] = raid6_get_zero_page(); 207 207 ptrs[disks - 1] = dq; 208 208 209 209 raid6_call.gen_syndrome(disks, bytes, ptrs);
+3 -3
lib/raid6/recov_s390xc.c
··· 34 34 Use the dead data pages as temporary storage for 35 35 delta p and delta q */ 36 36 dp = (u8 *)ptrs[faila]; 37 - ptrs[faila] = (void *)raid6_empty_zero_page; 37 + ptrs[faila] = raid6_get_zero_page(); 38 38 ptrs[disks-2] = dp; 39 39 dq = (u8 *)ptrs[failb]; 40 - ptrs[failb] = (void *)raid6_empty_zero_page; 40 + ptrs[failb] = raid6_get_zero_page(); 41 41 ptrs[disks-1] = dq; 42 42 43 43 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 81 81 /* Compute syndrome with zero for the missing data page 82 82 Use the dead data page as temporary storage for delta q */ 83 83 dq = (u8 *)ptrs[faila]; 84 - ptrs[faila] = (void *)raid6_empty_zero_page; 84 + ptrs[faila] = raid6_get_zero_page(); 85 85 ptrs[disks-1] = dq; 86 86 87 87 raid6_call.gen_syndrome(disks, bytes, ptrs);
+3 -3
lib/raid6/recov_ssse3.c
··· 30 30 Use the dead data pages as temporary storage for 31 31 delta p and delta q */ 32 32 dp = (u8 *)ptrs[faila]; 33 - ptrs[faila] = (void *)raid6_empty_zero_page; 33 + ptrs[faila] = raid6_get_zero_page(); 34 34 ptrs[disks-2] = dp; 35 35 dq = (u8 *)ptrs[failb]; 36 - ptrs[failb] = (void *)raid6_empty_zero_page; 36 + ptrs[failb] = raid6_get_zero_page(); 37 37 ptrs[disks-1] = dq; 38 38 39 39 raid6_call.gen_syndrome(disks, bytes, ptrs); ··· 203 203 /* Compute syndrome with zero for the missing data page 204 204 Use the dead data page as temporary storage for delta q */ 205 205 dq = (u8 *)ptrs[faila]; 206 - ptrs[faila] = (void *)raid6_empty_zero_page; 206 + ptrs[faila] = raid6_get_zero_page(); 207 207 ptrs[disks-1] = dq; 208 208 209 209 raid6_call.gen_syndrome(disks, bytes, ptrs);
+58 -9
lib/stackdepot.c
··· 36 36 #include <linux/memblock.h> 37 37 #include <linux/kasan-enabled.h> 38 38 39 - #define DEPOT_POOLS_CAP 8192 40 - /* The pool_index is offset by 1 so the first record does not have a 0 handle. */ 41 - #define DEPOT_MAX_POOLS \ 42 - (((1LL << (DEPOT_POOL_INDEX_BITS)) - 1 < DEPOT_POOLS_CAP) ? \ 43 - (1LL << (DEPOT_POOL_INDEX_BITS)) - 1 : DEPOT_POOLS_CAP) 39 + /* 40 + * The pool_index is offset by 1 so the first record does not have a 0 handle. 41 + */ 42 + static unsigned int stack_max_pools __read_mostly = 43 + MIN((1LL << DEPOT_POOL_INDEX_BITS) - 1, 8192); 44 44 45 45 static bool stack_depot_disabled; 46 46 static bool __stack_depot_early_init_requested __initdata = IS_ENABLED(CONFIG_STACKDEPOT_ALWAYS_INIT); ··· 62 62 static unsigned int stack_hash_mask; 63 63 64 64 /* Array of memory regions that store stack records. */ 65 - static void *stack_pools[DEPOT_MAX_POOLS]; 65 + static void **stack_pools; 66 66 /* Newly allocated pool that is not yet added to stack_pools. */ 67 67 static void *new_pool; 68 68 /* Number of pools in stack_pools. */ ··· 100 100 return kstrtobool(str, &stack_depot_disabled); 101 101 } 102 102 early_param("stack_depot_disable", disable_stack_depot); 103 + 104 + static int __init parse_max_pools(char *str) 105 + { 106 + const long long limit = (1LL << (DEPOT_POOL_INDEX_BITS)) - 1; 107 + unsigned int max_pools; 108 + int rv; 109 + 110 + rv = kstrtouint(str, 0, &max_pools); 111 + if (rv) 112 + return rv; 113 + 114 + if (max_pools < 1024) { 115 + pr_err("stack_depot_max_pools below 1024, using default of %u\n", 116 + stack_max_pools); 117 + goto out; 118 + } 119 + 120 + if (max_pools > limit) { 121 + pr_err("stack_depot_max_pools exceeds %lld, using default of %u\n", 122 + limit, stack_max_pools); 123 + goto out; 124 + } 125 + 126 + stack_max_pools = max_pools; 127 + out: 128 + return 0; 129 + } 130 + early_param("stack_depot_max_pools", parse_max_pools); 103 131 104 132 void __init stack_depot_request_early_init(void) 105 133 { ··· 210 182 } 211 183 init_stack_table(entries); 212 184 185 + pr_info("allocating space for %u stack pools via memblock\n", 186 + stack_max_pools); 187 + stack_pools = 188 + memblock_alloc(stack_max_pools * sizeof(void *), PAGE_SIZE); 189 + if (!stack_pools) { 190 + pr_err("stack pools allocation failed, disabling\n"); 191 + memblock_free(stack_table, entries * sizeof(struct list_head)); 192 + stack_depot_disabled = true; 193 + return -ENOMEM; 194 + } 195 + 213 196 return 0; 214 197 } 215 198 ··· 270 231 stack_hash_mask = entries - 1; 271 232 init_stack_table(entries); 272 233 234 + pr_info("allocating space for %u stack pools via kvcalloc\n", 235 + stack_max_pools); 236 + stack_pools = kvcalloc(stack_max_pools, sizeof(void *), GFP_KERNEL); 237 + if (!stack_pools) { 238 + pr_err("stack pools allocation failed, disabling\n"); 239 + kvfree(stack_table); 240 + stack_depot_disabled = true; 241 + ret = -ENOMEM; 242 + } 243 + 273 244 out_unlock: 274 245 mutex_unlock(&stack_depot_init_mutex); 275 246 ··· 294 245 { 295 246 lockdep_assert_held(&pool_lock); 296 247 297 - if (unlikely(pools_num >= DEPOT_MAX_POOLS)) { 248 + if (unlikely(pools_num >= stack_max_pools)) { 298 249 /* Bail out if we reached the pool limit. */ 299 - WARN_ON_ONCE(pools_num > DEPOT_MAX_POOLS); /* should never happen */ 250 + WARN_ON_ONCE(pools_num > stack_max_pools); /* should never happen */ 300 251 WARN_ON_ONCE(!new_pool); /* to avoid unnecessary pre-allocation */ 301 252 WARN_ONCE(1, "Stack depot reached limit capacity"); 302 253 return false; ··· 322 273 * NULL; do not reset to NULL if we have reached the maximum number of 323 274 * pools. 324 275 */ 325 - if (pools_num < DEPOT_MAX_POOLS) 276 + if (pools_num < stack_max_pools) 326 277 WRITE_ONCE(new_pool, NULL); 327 278 else 328 279 WRITE_ONCE(new_pool, STACK_DEPOT_POISON);
+122
lib/sys_info.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <linux/sched/debug.h> 3 + #include <linux/console.h> 4 + #include <linux/kernel.h> 5 + #include <linux/ftrace.h> 6 + #include <linux/sysctl.h> 7 + #include <linux/nmi.h> 8 + 9 + #include <linux/sys_info.h> 10 + 11 + struct sys_info_name { 12 + unsigned long bit; 13 + const char *name; 14 + }; 15 + 16 + /* 17 + * When 'si_names' gets updated, please make sure the 'sys_info_avail' 18 + * below is updated accordingly. 19 + */ 20 + static const struct sys_info_name si_names[] = { 21 + { SYS_INFO_TASKS, "tasks" }, 22 + { SYS_INFO_MEM, "mem" }, 23 + { SYS_INFO_TIMERS, "timers" }, 24 + { SYS_INFO_LOCKS, "locks" }, 25 + { SYS_INFO_FTRACE, "ftrace" }, 26 + { SYS_INFO_ALL_CPU_BT, "all_bt" }, 27 + { SYS_INFO_BLOCKED_TASKS, "blocked_tasks" }, 28 + }; 29 + 30 + /* Expecting string like "xxx_sys_info=tasks,mem,timers,locks,ftrace,..." */ 31 + unsigned long sys_info_parse_param(char *str) 32 + { 33 + unsigned long si_bits = 0; 34 + char *s, *name; 35 + int i; 36 + 37 + s = str; 38 + while ((name = strsep(&s, ",")) && *name) { 39 + for (i = 0; i < ARRAY_SIZE(si_names); i++) { 40 + if (!strcmp(name, si_names[i].name)) { 41 + si_bits |= si_names[i].bit; 42 + break; 43 + } 44 + } 45 + } 46 + 47 + return si_bits; 48 + } 49 + 50 + #ifdef CONFIG_SYSCTL 51 + 52 + static const char sys_info_avail[] __maybe_unused = "tasks,mem,timers,locks,ftrace,all_bt,blocked_tasks"; 53 + 54 + int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write, 55 + void *buffer, size_t *lenp, 56 + loff_t *ppos) 57 + { 58 + char names[sizeof(sys_info_avail) + 1]; 59 + struct ctl_table table; 60 + unsigned long *si_bits_global; 61 + 62 + si_bits_global = ro_table->data; 63 + 64 + if (write) { 65 + unsigned long si_bits; 66 + int ret; 67 + 68 + table = *ro_table; 69 + table.data = names; 70 + table.maxlen = sizeof(names); 71 + ret = proc_dostring(&table, write, buffer, lenp, ppos); 72 + if (ret) 73 + return ret; 74 + 75 + si_bits = sys_info_parse_param(names); 76 + /* The access to the global value is not synchronized. */ 77 + WRITE_ONCE(*si_bits_global, si_bits); 78 + return 0; 79 + } else { 80 + /* for 'read' operation */ 81 + char *delim = ""; 82 + int i, len = 0; 83 + 84 + for (i = 0; i < ARRAY_SIZE(si_names); i++) { 85 + if (*si_bits_global & si_names[i].bit) { 86 + len += scnprintf(names + len, sizeof(names) - len, 87 + "%s%s", delim, si_names[i].name); 88 + delim = ","; 89 + } 90 + } 91 + 92 + table = *ro_table; 93 + table.data = names; 94 + table.maxlen = sizeof(names); 95 + return proc_dostring(&table, write, buffer, lenp, ppos); 96 + } 97 + } 98 + #endif 99 + 100 + void sys_info(unsigned long si_mask) 101 + { 102 + if (si_mask & SYS_INFO_TASKS) 103 + show_state(); 104 + 105 + if (si_mask & SYS_INFO_MEM) 106 + show_mem(); 107 + 108 + if (si_mask & SYS_INFO_TIMERS) 109 + sysrq_timer_list_show(); 110 + 111 + if (si_mask & SYS_INFO_LOCKS) 112 + debug_show_all_locks(); 113 + 114 + if (si_mask & SYS_INFO_FTRACE) 115 + ftrace_dump(DUMP_ALL); 116 + 117 + if (si_mask & SYS_INFO_ALL_CPU_BT) 118 + trigger_all_cpu_backtrace(); 119 + 120 + if (si_mask & SYS_INFO_BLOCKED_TASKS) 121 + show_state_filter(TASK_UNINTERRUPTIBLE); 122 + }
+305
lib/test_kho.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Test module for KHO 4 + * Copyright (c) 2025 Microsoft Corporation. 5 + * 6 + * Authors: 7 + * Saurabh Sengar <ssengar@microsoft.com> 8 + * Mike Rapoport <rppt@kernel.org> 9 + */ 10 + 11 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 + 13 + #include <linux/mm.h> 14 + #include <linux/gfp.h> 15 + #include <linux/slab.h> 16 + #include <linux/kexec.h> 17 + #include <linux/libfdt.h> 18 + #include <linux/module.h> 19 + #include <linux/printk.h> 20 + #include <linux/vmalloc.h> 21 + #include <linux/kexec_handover.h> 22 + 23 + #include <net/checksum.h> 24 + 25 + #define KHO_TEST_MAGIC 0x4b484f21 /* KHO! */ 26 + #define KHO_TEST_FDT "kho_test" 27 + #define KHO_TEST_COMPAT "kho-test-v1" 28 + 29 + static long max_mem = (PAGE_SIZE << MAX_PAGE_ORDER) * 2; 30 + module_param(max_mem, long, 0644); 31 + 32 + struct kho_test_state { 33 + unsigned int nr_folios; 34 + struct folio **folios; 35 + struct folio *fdt; 36 + __wsum csum; 37 + }; 38 + 39 + static struct kho_test_state kho_test_state; 40 + 41 + static int kho_test_notifier(struct notifier_block *self, unsigned long cmd, 42 + void *v) 43 + { 44 + struct kho_test_state *state = &kho_test_state; 45 + struct kho_serialization *ser = v; 46 + int err = 0; 47 + 48 + switch (cmd) { 49 + case KEXEC_KHO_ABORT: 50 + return NOTIFY_DONE; 51 + case KEXEC_KHO_FINALIZE: 52 + /* Handled below */ 53 + break; 54 + default: 55 + return NOTIFY_BAD; 56 + } 57 + 58 + err |= kho_preserve_folio(state->fdt); 59 + err |= kho_add_subtree(ser, KHO_TEST_FDT, folio_address(state->fdt)); 60 + 61 + return err ? NOTIFY_BAD : NOTIFY_DONE; 62 + } 63 + 64 + static struct notifier_block kho_test_nb = { 65 + .notifier_call = kho_test_notifier, 66 + }; 67 + 68 + static int kho_test_save_data(struct kho_test_state *state, void *fdt) 69 + { 70 + phys_addr_t *folios_info __free(kvfree) = NULL; 71 + int err = 0; 72 + 73 + folios_info = kvmalloc_array(state->nr_folios, sizeof(*folios_info), 74 + GFP_KERNEL); 75 + if (!folios_info) 76 + return -ENOMEM; 77 + 78 + for (int i = 0; i < state->nr_folios; i++) { 79 + struct folio *folio = state->folios[i]; 80 + unsigned int order = folio_order(folio); 81 + 82 + folios_info[i] = virt_to_phys(folio_address(folio)) | order; 83 + 84 + err = kho_preserve_folio(folio); 85 + if (err) 86 + return err; 87 + } 88 + 89 + err |= fdt_begin_node(fdt, "data"); 90 + err |= fdt_property(fdt, "nr_folios", &state->nr_folios, 91 + sizeof(state->nr_folios)); 92 + err |= fdt_property(fdt, "folios_info", folios_info, 93 + state->nr_folios * sizeof(*folios_info)); 94 + err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum)); 95 + err |= fdt_end_node(fdt); 96 + 97 + return err; 98 + } 99 + 100 + static int kho_test_prepare_fdt(struct kho_test_state *state) 101 + { 102 + const char compatible[] = KHO_TEST_COMPAT; 103 + unsigned int magic = KHO_TEST_MAGIC; 104 + ssize_t fdt_size; 105 + int err = 0; 106 + void *fdt; 107 + 108 + fdt_size = state->nr_folios * sizeof(phys_addr_t) + PAGE_SIZE; 109 + state->fdt = folio_alloc(GFP_KERNEL, get_order(fdt_size)); 110 + if (!state->fdt) 111 + return -ENOMEM; 112 + 113 + fdt = folio_address(state->fdt); 114 + 115 + err |= fdt_create(fdt, fdt_size); 116 + err |= fdt_finish_reservemap(fdt); 117 + 118 + err |= fdt_begin_node(fdt, ""); 119 + err |= fdt_property(fdt, "compatible", compatible, sizeof(compatible)); 120 + err |= fdt_property(fdt, "magic", &magic, sizeof(magic)); 121 + err |= kho_test_save_data(state, fdt); 122 + err |= fdt_end_node(fdt); 123 + 124 + err |= fdt_finish(fdt); 125 + 126 + if (err) 127 + folio_put(state->fdt); 128 + 129 + return err; 130 + } 131 + 132 + static int kho_test_generate_data(struct kho_test_state *state) 133 + { 134 + size_t alloc_size = 0; 135 + __wsum csum = 0; 136 + 137 + while (alloc_size < max_mem) { 138 + int order = get_random_u32() % NR_PAGE_ORDERS; 139 + struct folio *folio; 140 + unsigned int size; 141 + void *addr; 142 + 143 + /* cap allocation so that we won't exceed max_mem */ 144 + if (alloc_size + (PAGE_SIZE << order) > max_mem) { 145 + order = get_order(max_mem - alloc_size); 146 + if (order) 147 + order--; 148 + } 149 + size = PAGE_SIZE << order; 150 + 151 + folio = folio_alloc(GFP_KERNEL | __GFP_NORETRY, order); 152 + if (!folio) 153 + goto err_free_folios; 154 + 155 + state->folios[state->nr_folios++] = folio; 156 + addr = folio_address(folio); 157 + get_random_bytes(addr, size); 158 + csum = csum_partial(addr, size, csum); 159 + alloc_size += size; 160 + } 161 + 162 + state->csum = csum; 163 + return 0; 164 + 165 + err_free_folios: 166 + for (int i = 0; i < state->nr_folios; i++) 167 + folio_put(state->folios[i]); 168 + return -ENOMEM; 169 + } 170 + 171 + static int kho_test_save(void) 172 + { 173 + struct kho_test_state *state = &kho_test_state; 174 + struct folio **folios __free(kvfree) = NULL; 175 + unsigned long max_nr; 176 + int err; 177 + 178 + max_mem = PAGE_ALIGN(max_mem); 179 + max_nr = max_mem >> PAGE_SHIFT; 180 + 181 + folios = kvmalloc_array(max_nr, sizeof(*state->folios), GFP_KERNEL); 182 + if (!folios) 183 + return -ENOMEM; 184 + state->folios = folios; 185 + 186 + err = kho_test_generate_data(state); 187 + if (err) 188 + return err; 189 + 190 + err = kho_test_prepare_fdt(state); 191 + if (err) 192 + return err; 193 + 194 + return register_kho_notifier(&kho_test_nb); 195 + } 196 + 197 + static int kho_test_restore_data(const void *fdt, int node) 198 + { 199 + const unsigned int *nr_folios; 200 + const phys_addr_t *folios_info; 201 + const __wsum *old_csum; 202 + __wsum csum = 0; 203 + int len; 204 + 205 + node = fdt_path_offset(fdt, "/data"); 206 + 207 + nr_folios = fdt_getprop(fdt, node, "nr_folios", &len); 208 + if (!nr_folios || len != sizeof(*nr_folios)) 209 + return -EINVAL; 210 + 211 + old_csum = fdt_getprop(fdt, node, "csum", &len); 212 + if (!old_csum || len != sizeof(*old_csum)) 213 + return -EINVAL; 214 + 215 + folios_info = fdt_getprop(fdt, node, "folios_info", &len); 216 + if (!folios_info || len != sizeof(*folios_info) * *nr_folios) 217 + return -EINVAL; 218 + 219 + for (int i = 0; i < *nr_folios; i++) { 220 + unsigned int order = folios_info[i] & ~PAGE_MASK; 221 + phys_addr_t phys = folios_info[i] & PAGE_MASK; 222 + unsigned int size = PAGE_SIZE << order; 223 + struct folio *folio; 224 + 225 + folio = kho_restore_folio(phys); 226 + if (!folio) 227 + break; 228 + 229 + if (folio_order(folio) != order) 230 + break; 231 + 232 + csum = csum_partial(folio_address(folio), size, csum); 233 + folio_put(folio); 234 + } 235 + 236 + if (csum != *old_csum) 237 + return -EINVAL; 238 + 239 + return 0; 240 + } 241 + 242 + static int kho_test_restore(phys_addr_t fdt_phys) 243 + { 244 + void *fdt = phys_to_virt(fdt_phys); 245 + const unsigned int *magic; 246 + int node, len, err; 247 + 248 + node = fdt_path_offset(fdt, "/"); 249 + if (node < 0) 250 + return -EINVAL; 251 + 252 + if (fdt_node_check_compatible(fdt, node, KHO_TEST_COMPAT)) 253 + return -EINVAL; 254 + 255 + magic = fdt_getprop(fdt, node, "magic", &len); 256 + if (!magic || len != sizeof(*magic)) 257 + return -EINVAL; 258 + 259 + if (*magic != KHO_TEST_MAGIC) 260 + return -EINVAL; 261 + 262 + err = kho_test_restore_data(fdt, node); 263 + if (err) 264 + return err; 265 + 266 + pr_info("KHO restore succeeded\n"); 267 + return 0; 268 + } 269 + 270 + static int __init kho_test_init(void) 271 + { 272 + phys_addr_t fdt_phys; 273 + int err; 274 + 275 + err = kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys); 276 + if (!err) 277 + return kho_test_restore(fdt_phys); 278 + 279 + if (err != -ENOENT) { 280 + pr_warn("failed to retrieve %s FDT: %d\n", KHO_TEST_FDT, err); 281 + return err; 282 + } 283 + 284 + return kho_test_save(); 285 + } 286 + module_init(kho_test_init); 287 + 288 + static void kho_test_cleanup(void) 289 + { 290 + for (int i = 0; i < kho_test_state.nr_folios; i++) 291 + folio_put(kho_test_state.folios[i]); 292 + 293 + kvfree(kho_test_state.folios); 294 + } 295 + 296 + static void __exit kho_test_exit(void) 297 + { 298 + unregister_kho_notifier(&kho_test_nb); 299 + kho_test_cleanup(); 300 + } 301 + module_exit(kho_test_exit); 302 + 303 + MODULE_AUTHOR("Mike Rapoport <rppt@kernel.org>"); 304 + MODULE_DESCRIPTION("KHO test module"); 305 + MODULE_LICENSE("GPL");
+61 -9
lib/vsprintf.c
··· 60 60 bool no_hash_pointers __ro_after_init; 61 61 EXPORT_SYMBOL_GPL(no_hash_pointers); 62 62 63 + /* 64 + * Hashed pointers policy selected by "hash_pointers=..." boot param 65 + * 66 + * `auto` - Hashed pointers enabled unless disabled by slub_debug_enabled=true 67 + * `always` - Hashed pointers enabled unconditionally 68 + * `never` - Hashed pointers disabled unconditionally 69 + */ 70 + enum hash_pointers_policy { 71 + HASH_PTR_AUTO = 0, 72 + HASH_PTR_ALWAYS, 73 + HASH_PTR_NEVER 74 + }; 75 + static enum hash_pointers_policy hash_pointers_mode __initdata; 76 + 63 77 noinline 64 78 static unsigned long long simple_strntoull(const char *startp, char **endp, unsigned int base, size_t max_chars) 65 79 { ··· 1713 1699 return buf; 1714 1700 } 1715 1701 1716 - #pragma GCC diagnostic push 1717 - #ifndef __clang__ 1718 - #pragma GCC diagnostic ignored "-Wsuggest-attribute=format" 1719 - #endif 1702 + __diag_push(); 1703 + __diag_ignore(GCC, all, "-Wsuggest-attribute=format", 1704 + "Not a valid __printf() conversion candidate."); 1720 1705 static char *va_format(char *buf, char *end, struct va_format *va_fmt, 1721 1706 struct printf_spec spec) 1722 1707 { ··· 1730 1717 1731 1718 return buf; 1732 1719 } 1733 - #pragma GCC diagnostic pop 1720 + __diag_pop(); 1734 1721 1735 1722 static noinline_for_stack 1736 1723 char *uuid_string(char *buf, char *end, const u8 *addr, ··· 2302 2289 return resource_string(buf, end, ptr, spec, fmt); 2303 2290 } 2304 2291 2305 - int __init no_hash_pointers_enable(char *str) 2292 + void __init hash_pointers_finalize(bool slub_debug) 2306 2293 { 2307 - if (no_hash_pointers) 2308 - return 0; 2294 + switch (hash_pointers_mode) { 2295 + case HASH_PTR_ALWAYS: 2296 + no_hash_pointers = false; 2297 + break; 2298 + case HASH_PTR_NEVER: 2299 + no_hash_pointers = true; 2300 + break; 2301 + case HASH_PTR_AUTO: 2302 + default: 2303 + no_hash_pointers = slub_debug; 2304 + break; 2305 + } 2309 2306 2310 - no_hash_pointers = true; 2307 + if (!no_hash_pointers) 2308 + return; 2311 2309 2312 2310 pr_warn("**********************************************************\n"); 2313 2311 pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); ··· 2331 2307 pr_warn("** the kernel, report this immediately to your system **\n"); 2332 2308 pr_warn("** administrator! **\n"); 2333 2309 pr_warn("** **\n"); 2310 + pr_warn("** Use hash_pointers=always to force this mode off **\n"); 2311 + pr_warn("** **\n"); 2334 2312 pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); 2335 2313 pr_warn("**********************************************************\n"); 2314 + } 2315 + 2316 + static int __init hash_pointers_mode_parse(char *str) 2317 + { 2318 + if (!str) { 2319 + pr_warn("Hash pointers mode empty; falling back to auto.\n"); 2320 + hash_pointers_mode = HASH_PTR_AUTO; 2321 + } else if (strncmp(str, "auto", 4) == 0) { 2322 + pr_info("Hash pointers mode set to auto.\n"); 2323 + hash_pointers_mode = HASH_PTR_AUTO; 2324 + } else if (strncmp(str, "never", 5) == 0) { 2325 + pr_info("Hash pointers mode set to never.\n"); 2326 + hash_pointers_mode = HASH_PTR_NEVER; 2327 + } else if (strncmp(str, "always", 6) == 0) { 2328 + pr_info("Hash pointers mode set to always.\n"); 2329 + hash_pointers_mode = HASH_PTR_ALWAYS; 2330 + } else { 2331 + pr_warn("Unknown hash_pointers mode '%s' specified; assuming auto.\n", str); 2332 + hash_pointers_mode = HASH_PTR_AUTO; 2333 + } 2336 2334 2337 2335 return 0; 2336 + } 2337 + early_param("hash_pointers", hash_pointers_mode_parse); 2338 + 2339 + static int __init no_hash_pointers_enable(char *str) 2340 + { 2341 + return hash_pointers_mode_parse("never"); 2338 2342 } 2339 2343 early_param("no_hash_pointers", no_hash_pointers_enable); 2340 2344
-107
lib/xxhash.c
··· 267 267 } 268 268 EXPORT_SYMBOL(xxh64_reset); 269 269 270 - int xxh32_update(struct xxh32_state *state, const void *input, const size_t len) 271 - { 272 - const uint8_t *p = (const uint8_t *)input; 273 - const uint8_t *const b_end = p + len; 274 - 275 - if (input == NULL) 276 - return -EINVAL; 277 - 278 - state->total_len_32 += (uint32_t)len; 279 - state->large_len |= (len >= 16) | (state->total_len_32 >= 16); 280 - 281 - if (state->memsize + len < 16) { /* fill in tmp buffer */ 282 - memcpy((uint8_t *)(state->mem32) + state->memsize, input, len); 283 - state->memsize += (uint32_t)len; 284 - return 0; 285 - } 286 - 287 - if (state->memsize) { /* some data left from previous update */ 288 - const uint32_t *p32 = state->mem32; 289 - 290 - memcpy((uint8_t *)(state->mem32) + state->memsize, input, 291 - 16 - state->memsize); 292 - 293 - state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32)); 294 - p32++; 295 - state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32)); 296 - p32++; 297 - state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32)); 298 - p32++; 299 - state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32)); 300 - p32++; 301 - 302 - p += 16-state->memsize; 303 - state->memsize = 0; 304 - } 305 - 306 - if (p <= b_end - 16) { 307 - const uint8_t *const limit = b_end - 16; 308 - uint32_t v1 = state->v1; 309 - uint32_t v2 = state->v2; 310 - uint32_t v3 = state->v3; 311 - uint32_t v4 = state->v4; 312 - 313 - do { 314 - v1 = xxh32_round(v1, get_unaligned_le32(p)); 315 - p += 4; 316 - v2 = xxh32_round(v2, get_unaligned_le32(p)); 317 - p += 4; 318 - v3 = xxh32_round(v3, get_unaligned_le32(p)); 319 - p += 4; 320 - v4 = xxh32_round(v4, get_unaligned_le32(p)); 321 - p += 4; 322 - } while (p <= limit); 323 - 324 - state->v1 = v1; 325 - state->v2 = v2; 326 - state->v3 = v3; 327 - state->v4 = v4; 328 - } 329 - 330 - if (p < b_end) { 331 - memcpy(state->mem32, p, (size_t)(b_end-p)); 332 - state->memsize = (uint32_t)(b_end-p); 333 - } 334 - 335 - return 0; 336 - } 337 - EXPORT_SYMBOL(xxh32_update); 338 - 339 - uint32_t xxh32_digest(const struct xxh32_state *state) 340 - { 341 - const uint8_t *p = (const uint8_t *)state->mem32; 342 - const uint8_t *const b_end = (const uint8_t *)(state->mem32) + 343 - state->memsize; 344 - uint32_t h32; 345 - 346 - if (state->large_len) { 347 - h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) + 348 - xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18); 349 - } else { 350 - h32 = state->v3 /* == seed */ + PRIME32_5; 351 - } 352 - 353 - h32 += state->total_len_32; 354 - 355 - while (p + 4 <= b_end) { 356 - h32 += get_unaligned_le32(p) * PRIME32_3; 357 - h32 = xxh_rotl32(h32, 17) * PRIME32_4; 358 - p += 4; 359 - } 360 - 361 - while (p < b_end) { 362 - h32 += (*p) * PRIME32_5; 363 - h32 = xxh_rotl32(h32, 11) * PRIME32_1; 364 - p++; 365 - } 366 - 367 - h32 ^= h32 >> 15; 368 - h32 *= PRIME32_2; 369 - h32 ^= h32 >> 13; 370 - h32 *= PRIME32_3; 371 - h32 ^= h32 >> 16; 372 - 373 - return h32; 374 - } 375 - EXPORT_SYMBOL(xxh32_digest); 376 - 377 270 int xxh64_update(struct xxh64_state *state, const void *input, const size_t len) 378 271 { 379 272 const uint8_t *p = (const uint8_t *)input;
-4
mm/Kconfig
··· 1242 1242 config KMAP_LOCAL_NON_LINEAR_PTE_ARRAY 1243 1243 bool 1244 1244 1245 - # struct io_mapping based helper. Selected by drivers that need them 1246 - config IO_MAPPING 1247 - bool 1248 - 1249 1245 config MEMFD_CREATE 1250 1246 bool "Enable memfd_create() system call" if EXPERT 1251 1247
-1
mm/Makefile
··· 141 141 obj-$(CONFIG_MAPPING_DIRTY_HELPERS) += mapping_dirty_helpers.o 142 142 obj-$(CONFIG_PTDUMP) += ptdump.o 143 143 obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o 144 - obj-$(CONFIG_IO_MAPPING) += io-mapping.o 145 144 obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o 146 145 obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o 147 146 obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o
+4
mm/damon/vaddr.c
··· 711 711 target -= dests->weight_arr[i]; 712 712 } 713 713 714 + /* If the folio is already in the right node, don't do anything */ 715 + if (folio_nid(folio) == dests->node_id_arr[i]) 716 + return; 717 + 714 718 isolate: 715 719 if (!folio_isolate_lru(folio)) 716 720 return;
+157 -55
mm/execmem.c
··· 26 26 27 27 #ifdef CONFIG_MMU 28 28 static void *execmem_vmalloc(struct execmem_range *range, size_t size, 29 - pgprot_t pgprot, vm_flags_t vm_flags) 29 + pgprot_t pgprot, unsigned long vm_flags) 30 30 { 31 31 bool kasan = range->flags & EXECMEM_KASAN_SHADOW; 32 32 gfp_t gfp_flags = GFP_KERNEL | __GFP_NOWARN; ··· 82 82 } 83 83 #else 84 84 static void *execmem_vmalloc(struct execmem_range *range, size_t size, 85 - pgprot_t pgprot, vm_flags_t vm_flags) 85 + pgprot_t pgprot, unsigned long vm_flags) 86 86 { 87 87 return vmalloc(size); 88 88 } ··· 93 93 struct mutex mutex; 94 94 struct maple_tree busy_areas; 95 95 struct maple_tree free_areas; 96 + unsigned int pending_free_cnt; /* protected by mutex */ 96 97 }; 98 + 99 + /* delay to schedule asynchronous free if fast path free fails */ 100 + #define FREE_DELAY (msecs_to_jiffies(10)) 101 + 102 + /* mark entries in busy_areas that should be freed asynchronously */ 103 + #define PENDING_FREE_MASK (1 << (PAGE_SHIFT - 1)) 97 104 98 105 static struct execmem_cache execmem_cache = { 99 106 .mutex = __MUTEX_INITIALIZER(execmem_cache.mutex), ··· 137 130 return err; 138 131 } 139 132 133 + static int execmem_force_rw(void *ptr, size_t size) 134 + { 135 + unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT; 136 + unsigned long addr = (unsigned long)ptr; 137 + int ret; 138 + 139 + ret = set_memory_nx(addr, nr); 140 + if (ret) 141 + return ret; 142 + 143 + return set_memory_rw(addr, nr); 144 + } 145 + 146 + int execmem_restore_rox(void *ptr, size_t size) 147 + { 148 + unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT; 149 + unsigned long addr = (unsigned long)ptr; 150 + 151 + return set_memory_rox(addr, nr); 152 + } 153 + 140 154 static void execmem_cache_clean(struct work_struct *work) 141 155 { 142 156 struct maple_tree *free_areas = &execmem_cache.free_areas; ··· 183 155 184 156 static DECLARE_WORK(execmem_cache_clean_work, execmem_cache_clean); 185 157 186 - static int execmem_cache_add(void *ptr, size_t size) 158 + static int execmem_cache_add_locked(void *ptr, size_t size, gfp_t gfp_mask) 187 159 { 188 160 struct maple_tree *free_areas = &execmem_cache.free_areas; 189 - struct mutex *mutex = &execmem_cache.mutex; 190 161 unsigned long addr = (unsigned long)ptr; 191 162 MA_STATE(mas, free_areas, addr - 1, addr + 1); 192 163 unsigned long lower, upper; 193 164 void *area = NULL; 194 - int err; 195 165 196 166 lower = addr; 197 167 upper = addr + size - 1; 198 168 199 - mutex_lock(mutex); 200 169 area = mas_walk(&mas); 201 170 if (area && mas.last == addr - 1) 202 171 lower = mas.index; ··· 203 178 upper = mas.last; 204 179 205 180 mas_set_range(&mas, lower, upper); 206 - err = mas_store_gfp(&mas, (void *)lower, GFP_KERNEL); 207 - mutex_unlock(mutex); 208 - if (err) 209 - return err; 181 + return mas_store_gfp(&mas, (void *)lower, gfp_mask); 182 + } 210 183 211 - return 0; 184 + static int execmem_cache_add(void *ptr, size_t size, gfp_t gfp_mask) 185 + { 186 + guard(mutex)(&execmem_cache.mutex); 187 + 188 + return execmem_cache_add_locked(ptr, size, gfp_mask); 212 189 } 213 190 214 191 static bool within_range(struct execmem_range *range, struct ma_state *mas, ··· 283 256 284 257 static int execmem_cache_populate(struct execmem_range *range, size_t size) 285 258 { 286 - vm_flags_t vm_flags = VM_ALLOW_HUGE_VMAP; 259 + unsigned long vm_flags = VM_ALLOW_HUGE_VMAP; 287 260 struct vm_struct *vm; 288 261 size_t alloc_size; 289 262 int err = -ENOMEM; ··· 291 264 292 265 alloc_size = round_up(size, PMD_SIZE); 293 266 p = execmem_vmalloc(range, alloc_size, PAGE_KERNEL, vm_flags); 267 + if (!p) { 268 + alloc_size = size; 269 + p = execmem_vmalloc(range, alloc_size, PAGE_KERNEL, vm_flags); 270 + } 271 + 294 272 if (!p) 295 273 return err; 296 274 ··· 304 272 goto err_free_mem; 305 273 306 274 /* fill memory with instructions that will trap */ 307 - execmem_fill_trapping_insns(p, alloc_size, /* writable = */ true); 275 + execmem_fill_trapping_insns(p, alloc_size); 308 276 309 277 err = set_memory_rox((unsigned long)p, vm->nr_pages); 310 278 if (err) 311 279 goto err_free_mem; 312 280 313 - err = execmem_cache_add(p, alloc_size); 281 + err = execmem_cache_add(p, alloc_size, GFP_KERNEL); 314 282 if (err) 315 283 goto err_reset_direct_map; 316 284 ··· 339 307 return __execmem_cache_alloc(range, size); 340 308 } 341 309 310 + static inline bool is_pending_free(void *ptr) 311 + { 312 + return ((unsigned long)ptr & PENDING_FREE_MASK); 313 + } 314 + 315 + static inline void *pending_free_set(void *ptr) 316 + { 317 + return (void *)((unsigned long)ptr | PENDING_FREE_MASK); 318 + } 319 + 320 + static inline void *pending_free_clear(void *ptr) 321 + { 322 + return (void *)((unsigned long)ptr & ~PENDING_FREE_MASK); 323 + } 324 + 325 + static int __execmem_cache_free(struct ma_state *mas, void *ptr, gfp_t gfp_mask) 326 + { 327 + size_t size = mas_range_len(mas); 328 + int err; 329 + 330 + err = execmem_force_rw(ptr, size); 331 + if (err) 332 + return err; 333 + 334 + execmem_fill_trapping_insns(ptr, size); 335 + execmem_restore_rox(ptr, size); 336 + 337 + err = execmem_cache_add_locked(ptr, size, gfp_mask); 338 + if (err) 339 + return err; 340 + 341 + mas_store_gfp(mas, NULL, gfp_mask); 342 + return 0; 343 + } 344 + 345 + static void execmem_cache_free_slow(struct work_struct *work); 346 + static DECLARE_DELAYED_WORK(execmem_cache_free_work, execmem_cache_free_slow); 347 + 348 + static void execmem_cache_free_slow(struct work_struct *work) 349 + { 350 + struct maple_tree *busy_areas = &execmem_cache.busy_areas; 351 + MA_STATE(mas, busy_areas, 0, ULONG_MAX); 352 + void *area; 353 + 354 + guard(mutex)(&execmem_cache.mutex); 355 + 356 + if (!execmem_cache.pending_free_cnt) 357 + return; 358 + 359 + mas_for_each(&mas, area, ULONG_MAX) { 360 + if (!is_pending_free(area)) 361 + continue; 362 + 363 + area = pending_free_clear(area); 364 + if (__execmem_cache_free(&mas, area, GFP_KERNEL)) 365 + continue; 366 + 367 + execmem_cache.pending_free_cnt--; 368 + } 369 + 370 + if (execmem_cache.pending_free_cnt) 371 + schedule_delayed_work(&execmem_cache_free_work, FREE_DELAY); 372 + else 373 + schedule_work(&execmem_cache_clean_work); 374 + } 375 + 342 376 static bool execmem_cache_free(void *ptr) 343 377 { 344 378 struct maple_tree *busy_areas = &execmem_cache.busy_areas; 345 - struct mutex *mutex = &execmem_cache.mutex; 346 379 unsigned long addr = (unsigned long)ptr; 347 380 MA_STATE(mas, busy_areas, addr, addr); 348 - size_t size; 349 381 void *area; 382 + int err; 350 383 351 - mutex_lock(mutex); 384 + guard(mutex)(&execmem_cache.mutex); 385 + 352 386 area = mas_walk(&mas); 353 - if (!area) { 354 - mutex_unlock(mutex); 387 + if (!area) 355 388 return false; 389 + 390 + err = __execmem_cache_free(&mas, area, GFP_KERNEL | __GFP_NORETRY); 391 + if (err) { 392 + /* 393 + * mas points to exact slot we've got the area from, nothing 394 + * else can modify the tree because of the mutex, so there 395 + * won't be any allocations in mas_store_gfp() and it will just 396 + * change the pointer. 397 + */ 398 + area = pending_free_set(area); 399 + mas_store_gfp(&mas, area, GFP_KERNEL); 400 + execmem_cache.pending_free_cnt++; 401 + schedule_delayed_work(&execmem_cache_free_work, FREE_DELAY); 402 + return true; 356 403 } 357 - size = mas_range_len(&mas); 358 - 359 - mas_store_gfp(&mas, NULL, GFP_KERNEL); 360 - mutex_unlock(mutex); 361 - 362 - execmem_fill_trapping_insns(ptr, size, /* writable = */ false); 363 - 364 - execmem_cache_add(ptr, size); 365 404 366 405 schedule_work(&execmem_cache_clean_work); 367 406 368 407 return true; 369 408 } 370 409 371 - int execmem_make_temp_rw(void *ptr, size_t size) 372 - { 373 - unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT; 374 - unsigned long addr = (unsigned long)ptr; 375 - int ret; 376 - 377 - ret = set_memory_nx(addr, nr); 378 - if (ret) 379 - return ret; 380 - 381 - return set_memory_rw(addr, nr); 382 - } 383 - 384 - int execmem_restore_rox(void *ptr, size_t size) 385 - { 386 - unsigned int nr = PAGE_ALIGN(size) >> PAGE_SHIFT; 387 - unsigned long addr = (unsigned long)ptr; 388 - 389 - return set_memory_rox(addr, nr); 390 - } 391 - 392 410 #else /* CONFIG_ARCH_HAS_EXECMEM_ROX */ 411 + /* 412 + * when ROX cache is not used the permissions defined by architectures for 413 + * execmem ranges that are updated before use (e.g. EXECMEM_MODULE_TEXT) must 414 + * be writable anyway 415 + */ 416 + static inline int execmem_force_rw(void *ptr, size_t size) 417 + { 418 + return 0; 419 + } 420 + 393 421 static void *execmem_cache_alloc(struct execmem_range *range, size_t size) 394 422 { 395 423 return NULL; ··· 465 373 { 466 374 struct execmem_range *range = &execmem_info->ranges[type]; 467 375 bool use_cache = range->flags & EXECMEM_ROX_CACHE; 468 - vm_flags_t vm_flags = VM_FLUSH_RESET_PERMS; 376 + unsigned long vm_flags = VM_FLUSH_RESET_PERMS; 469 377 pgprot_t pgprot = range->pgprot; 470 - void *p; 378 + void *p = NULL; 471 379 472 380 size = PAGE_ALIGN(size); 473 381 ··· 477 385 p = execmem_vmalloc(range, size, pgprot, vm_flags); 478 386 479 387 return kasan_reset_tag(p); 388 + } 389 + 390 + void *execmem_alloc_rw(enum execmem_type type, size_t size) 391 + { 392 + void *p __free(execmem) = execmem_alloc(type, size); 393 + int err; 394 + 395 + if (!p) 396 + return NULL; 397 + 398 + err = execmem_force_rw(p, size); 399 + if (err) 400 + return NULL; 401 + 402 + return no_free_ptr(p); 480 403 } 481 404 482 405 void execmem_free(void *ptr) ··· 504 397 505 398 if (!execmem_cache_free(ptr)) 506 399 vfree(ptr); 507 - } 508 - 509 - void *execmem_update_copy(void *dst, const void *src, size_t size) 510 - { 511 - return text_poke_copy(dst, src, size); 512 400 } 513 401 514 402 bool execmem_is_rox(enum execmem_type type)
+1 -1
mm/internal.h
··· 1391 1391 1392 1392 struct vm_struct *__get_vm_area_node(unsigned long size, 1393 1393 unsigned long align, unsigned long shift, 1394 - vm_flags_t vm_flags, unsigned long start, 1394 + unsigned long vm_flags, unsigned long start, 1395 1395 unsigned long end, int node, gfp_t gfp_mask, 1396 1396 const void *caller); 1397 1397
-30
mm/io-mapping.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - 3 - #include <linux/mm.h> 4 - #include <linux/io-mapping.h> 5 - 6 - /** 7 - * io_mapping_map_user - remap an I/O mapping to userspace 8 - * @iomap: the source io_mapping 9 - * @vma: user vma to map to 10 - * @addr: target user address to start at 11 - * @pfn: physical address of kernel memory 12 - * @size: size of map area 13 - * 14 - * Note: this is only safe if the mm semaphore is held when called. 15 - */ 16 - int io_mapping_map_user(struct io_mapping *iomap, struct vm_area_struct *vma, 17 - unsigned long addr, unsigned long pfn, unsigned long size) 18 - { 19 - vm_flags_t expected_flags = VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; 20 - 21 - if (WARN_ON_ONCE((vma->vm_flags & expected_flags) != expected_flags)) 22 - return -EINVAL; 23 - 24 - pgprot_t remap_prot = __pgprot((pgprot_val(iomap->prot) & _PAGE_CACHE_MASK) | 25 - (pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK)); 26 - 27 - /* We rely on prevalidation of the io-mapping to skip pfnmap tracking. */ 28 - return remap_pfn_range_notrack(vma, addr, pfn, size, remap_prot); 29 - } 30 - EXPORT_SYMBOL_GPL(io_mapping_map_user);
+18 -7
mm/kasan/common.c
··· 230 230 } 231 231 232 232 static inline void poison_slab_object(struct kmem_cache *cache, void *object, 233 - bool init, bool still_accessible) 233 + bool init) 234 234 { 235 235 void *tagged_object = object; 236 236 237 237 object = kasan_reset_tag(object); 238 - 239 - /* RCU slabs could be legally used after free within the RCU period. */ 240 - if (unlikely(still_accessible)) 241 - return; 242 238 243 239 kasan_poison(object, round_up(cache->object_size, KASAN_GRANULE_SIZE), 244 240 KASAN_SLAB_FREE, init); ··· 257 261 if (!kasan_arch_is_ready() || is_kfence_address(object)) 258 262 return false; 259 263 260 - poison_slab_object(cache, object, init, still_accessible); 264 + /* 265 + * If this point is reached with an object that must still be 266 + * accessible under RCU, we can't poison it; in that case, also skip the 267 + * quarantine. This should mostly only happen when CONFIG_SLUB_RCU_DEBUG 268 + * has been disabled manually. 269 + * 270 + * Putting the object on the quarantine wouldn't help catch UAFs (since 271 + * we can't poison it here), and it would mask bugs caused by 272 + * SLAB_TYPESAFE_BY_RCU users not being careful enough about object 273 + * reuse; so overall, putting the object into the quarantine here would 274 + * be counterproductive. 275 + */ 276 + if (still_accessible) 277 + return false; 278 + 279 + poison_slab_object(cache, object, init); 261 280 262 281 /* 263 282 * If the object is put into quarantine, do not let slab put the object ··· 530 519 if (check_slab_allocation(slab->slab_cache, ptr, ip)) 531 520 return false; 532 521 533 - poison_slab_object(slab->slab_cache, ptr, false, false); 522 + poison_slab_object(slab->slab_cache, ptr, false); 534 523 return true; 535 524 } 536 525
+39 -19
mm/khugepaged.c
··· 700 700 spinlock_t *ptl, 701 701 struct list_head *compound_pagelist) 702 702 { 703 + unsigned long end = address + HPAGE_PMD_SIZE; 703 704 struct folio *src, *tmp; 704 - pte_t *_pte; 705 705 pte_t pteval; 706 + pte_t *_pte; 707 + unsigned int nr_ptes; 706 708 707 - for (_pte = pte; _pte < pte + HPAGE_PMD_NR; 708 - _pte++, address += PAGE_SIZE) { 709 + for (_pte = pte; _pte < pte + HPAGE_PMD_NR; _pte += nr_ptes, 710 + address += nr_ptes * PAGE_SIZE) { 711 + nr_ptes = 1; 709 712 pteval = ptep_get(_pte); 710 713 if (pte_none(pteval) || is_zero_pfn(pte_pfn(pteval))) { 711 714 add_mm_counter(vma->vm_mm, MM_ANONPAGES, 1); ··· 725 722 struct page *src_page = pte_page(pteval); 726 723 727 724 src = page_folio(src_page); 728 - if (!folio_test_large(src)) 725 + 726 + if (folio_test_large(src)) { 727 + unsigned int max_nr_ptes = (end - address) >> PAGE_SHIFT; 728 + 729 + nr_ptes = folio_pte_batch(src, _pte, pteval, max_nr_ptes); 730 + } else { 729 731 release_pte_folio(src); 732 + } 733 + 730 734 /* 731 735 * ptl mostly unnecessary, but preempt has to 732 736 * be disabled to update the per-cpu stats 733 737 * inside folio_remove_rmap_pte(). 734 738 */ 735 739 spin_lock(ptl); 736 - ptep_clear(vma->vm_mm, address, _pte); 737 - folio_remove_rmap_pte(src, src_page, vma); 740 + clear_ptes(vma->vm_mm, address, _pte, nr_ptes); 741 + folio_remove_rmap_ptes(src, src_page, nr_ptes, vma); 738 742 spin_unlock(ptl); 739 - free_folio_and_swap_cache(src); 743 + free_swap_cache(src); 744 + folio_put_refs(src, nr_ptes); 740 745 } 741 746 } 742 747 ··· 1503 1492 int collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr, 1504 1493 bool install_pmd) 1505 1494 { 1495 + int nr_mapped_ptes = 0, result = SCAN_FAIL; 1496 + unsigned int nr_batch_ptes; 1506 1497 struct mmu_notifier_range range; 1507 1498 bool notified = false; 1508 1499 unsigned long haddr = addr & HPAGE_PMD_MASK; 1500 + unsigned long end = haddr + HPAGE_PMD_SIZE; 1509 1501 struct vm_area_struct *vma = vma_lookup(mm, haddr); 1510 1502 struct folio *folio; 1511 1503 pte_t *start_pte, *pte; 1512 1504 pmd_t *pmd, pgt_pmd; 1513 1505 spinlock_t *pml = NULL, *ptl; 1514 - int nr_ptes = 0, result = SCAN_FAIL; 1515 1506 int i; 1516 1507 1517 1508 mmap_assert_locked(mm); ··· 1627 1614 goto abort; 1628 1615 1629 1616 /* step 2: clear page table and adjust rmap */ 1630 - for (i = 0, addr = haddr, pte = start_pte; 1631 - i < HPAGE_PMD_NR; i++, addr += PAGE_SIZE, pte++) { 1617 + for (i = 0, addr = haddr, pte = start_pte; i < HPAGE_PMD_NR; 1618 + i += nr_batch_ptes, addr += nr_batch_ptes * PAGE_SIZE, 1619 + pte += nr_batch_ptes) { 1620 + unsigned int max_nr_batch_ptes = (end - addr) >> PAGE_SHIFT; 1632 1621 struct page *page; 1633 1622 pte_t ptent = ptep_get(pte); 1623 + 1624 + nr_batch_ptes = 1; 1634 1625 1635 1626 if (pte_none(ptent)) 1636 1627 continue; ··· 1649 1632 goto abort; 1650 1633 } 1651 1634 page = vm_normal_page(vma, addr, ptent); 1635 + 1652 1636 if (folio_page(folio, i) != page) 1653 1637 goto abort; 1638 + 1639 + nr_batch_ptes = folio_pte_batch(folio, pte, ptent, max_nr_batch_ptes); 1654 1640 1655 1641 /* 1656 1642 * Must clear entry, or a racing truncate may re-remove it. 1657 1643 * TLB flush can be left until pmdp_collapse_flush() does it. 1658 1644 * PTE dirty? Shmem page is already dirty; file is read-only. 1659 1645 */ 1660 - ptep_clear(mm, addr, pte); 1661 - folio_remove_rmap_pte(folio, page, vma); 1662 - nr_ptes++; 1646 + clear_ptes(mm, addr, pte, nr_batch_ptes); 1647 + folio_remove_rmap_ptes(folio, page, nr_batch_ptes, vma); 1648 + nr_mapped_ptes += nr_batch_ptes; 1663 1649 } 1664 1650 1665 1651 if (!pml) 1666 1652 spin_unlock(ptl); 1667 1653 1668 1654 /* step 3: set proper refcount and mm_counters. */ 1669 - if (nr_ptes) { 1670 - folio_ref_sub(folio, nr_ptes); 1671 - add_mm_counter(mm, mm_counter_file(folio), -nr_ptes); 1655 + if (nr_mapped_ptes) { 1656 + folio_ref_sub(folio, nr_mapped_ptes); 1657 + add_mm_counter(mm, mm_counter_file(folio), -nr_mapped_ptes); 1672 1658 } 1673 1659 1674 1660 /* step 4: remove empty page table */ ··· 1704 1684 : SCAN_SUCCEED; 1705 1685 goto drop_folio; 1706 1686 abort: 1707 - if (nr_ptes) { 1687 + if (nr_mapped_ptes) { 1708 1688 flush_tlb_mm(mm); 1709 - folio_ref_sub(folio, nr_ptes); 1710 - add_mm_counter(mm, mm_counter_file(folio), -nr_ptes); 1689 + folio_ref_sub(folio, nr_mapped_ptes); 1690 + add_mm_counter(mm, mm_counter_file(folio), -nr_mapped_ptes); 1711 1691 } 1712 1692 unlock: 1713 1693 if (start_pte)
+70 -1
mm/madvise.c
··· 19 19 #include <linux/sched.h> 20 20 #include <linux/sched/mm.h> 21 21 #include <linux/mm_inline.h> 22 + #include <linux/mmu_context.h> 22 23 #include <linux/string.h> 23 24 #include <linux/uio.h> 24 25 #include <linux/ksm.h> ··· 1257 1256 &guard_remove_walk_ops, NULL); 1258 1257 } 1259 1258 1259 + #ifdef CONFIG_64BIT 1260 + /* Does the madvise operation result in discarding of mapped data? */ 1261 + static bool is_discard(int behavior) 1262 + { 1263 + switch (behavior) { 1264 + case MADV_FREE: 1265 + case MADV_DONTNEED: 1266 + case MADV_DONTNEED_LOCKED: 1267 + case MADV_REMOVE: 1268 + case MADV_DONTFORK: 1269 + case MADV_WIPEONFORK: 1270 + case MADV_GUARD_INSTALL: 1271 + return true; 1272 + } 1273 + 1274 + return false; 1275 + } 1276 + 1277 + /* 1278 + * We are restricted from madvise()'ing mseal()'d VMAs only in very particular 1279 + * circumstances - discarding of data from read-only anonymous SEALED mappings. 1280 + * 1281 + * This is because users cannot trivally discard data from these VMAs, and may 1282 + * only do so via an appropriate madvise() call. 1283 + */ 1284 + static bool can_madvise_modify(struct madvise_behavior *madv_behavior) 1285 + { 1286 + struct vm_area_struct *vma = madv_behavior->vma; 1287 + 1288 + /* If the VMA isn't sealed we're good. */ 1289 + if (!vma_is_sealed(vma)) 1290 + return true; 1291 + 1292 + /* For a sealed VMA, we only care about discard operations. */ 1293 + if (!is_discard(madv_behavior->behavior)) 1294 + return true; 1295 + 1296 + /* 1297 + * We explicitly permit all file-backed mappings, whether MAP_SHARED or 1298 + * MAP_PRIVATE. 1299 + * 1300 + * The latter causes some complications. Because now, one can mmap() 1301 + * read/write a MAP_PRIVATE mapping, write to it, then mprotect() 1302 + * read-only, mseal() and a discard will be permitted. 1303 + * 1304 + * However, in order to avoid issues with potential use of madvise(..., 1305 + * MADV_DONTNEED) of mseal()'d .text mappings we, for the time being, 1306 + * permit this. 1307 + */ 1308 + if (!vma_is_anonymous(vma)) 1309 + return true; 1310 + 1311 + /* If the user could write to the mapping anyway, then this is fine. */ 1312 + if ((vma->vm_flags & VM_WRITE) && 1313 + arch_vma_access_permitted(vma, /* write= */ true, 1314 + /* execute= */ false, /* foreign= */ false)) 1315 + return true; 1316 + 1317 + /* Otherwise, we are not permitted to perform this operation. */ 1318 + return false; 1319 + } 1320 + #else 1321 + static bool can_madvise_modify(struct madvise_behavior *madv_behavior) 1322 + { 1323 + return true; 1324 + } 1325 + #endif 1326 + 1260 1327 /* 1261 1328 * Apply an madvise behavior to a region of a vma. madvise_update_vma 1262 1329 * will handle splitting a vm area into separate areas, each area with its own ··· 1338 1269 struct madvise_behavior_range *range = &madv_behavior->range; 1339 1270 int error; 1340 1271 1341 - if (unlikely(!can_modify_vma_madv(madv_behavior->vma, behavior))) 1272 + if (unlikely(!can_madvise_modify(madv_behavior))) 1342 1273 return -EPERM; 1343 1274 1344 1275 switch (behavior) {
+9 -3
mm/memory-failure.c
··· 837 837 struct mm_walk *walk) 838 838 { 839 839 struct hwpoison_walk *hwp = walk->private; 840 - pte_t pte = huge_ptep_get(walk->mm, addr, ptep); 841 840 struct hstate *h = hstate_vma(walk->vma); 841 + spinlock_t *ptl; 842 + pte_t pte; 843 + int ret; 842 844 843 - return check_hwpoisoned_entry(pte, addr, huge_page_shift(h), 844 - hwp->pfn, &hwp->tk); 845 + ptl = huge_pte_lock(h, walk->mm, ptep); 846 + pte = huge_ptep_get(walk->mm, addr, ptep); 847 + ret = check_hwpoisoned_entry(pte, addr, huge_page_shift(h), 848 + hwp->pfn, &hwp->tk); 849 + spin_unlock(ptl); 850 + return ret; 845 851 } 846 852 #else 847 853 #define hwpoison_hugetlb_range NULL
+10 -14
mm/mempool.c
··· 136 136 137 137 static __always_inline void add_element(mempool_t *pool, void *element) 138 138 { 139 - BUG_ON(pool->curr_nr >= pool->min_nr); 139 + BUG_ON(pool->min_nr != 0 && pool->curr_nr >= pool->min_nr); 140 140 poison_element(pool, element); 141 141 if (kasan_poison_element(pool, element)) 142 142 pool->elements[pool->curr_nr++] = element; ··· 202 202 pool->alloc = alloc_fn; 203 203 pool->free = free_fn; 204 204 init_waitqueue_head(&pool->wait); 205 - 206 - pool->elements = kmalloc_array_node(min_nr, sizeof(void *), 205 + /* 206 + * max() used here to ensure storage for at least 1 element to support 207 + * zero minimum pool 208 + */ 209 + pool->elements = kmalloc_array_node(max(1, min_nr), sizeof(void *), 207 210 gfp_mask, node_id); 208 211 if (!pool->elements) 209 212 return -ENOMEM; 210 213 211 214 /* 212 - * First pre-allocate the guaranteed number of buffers. 215 + * First pre-allocate the guaranteed number of buffers, 216 + * also pre-allocate 1 element for zero minimum pool. 213 217 */ 214 - while (pool->curr_nr < pool->min_nr) { 218 + while (pool->curr_nr < max(1, pool->min_nr)) { 215 219 void *element; 216 220 217 221 element = pool->alloc(gfp_mask, pool->pool_data); ··· 559 555 * wake-up path of previous test. This explicit check ensures the 560 556 * allocation of element when both min_nr and curr_nr are 0, and 561 557 * any active waiters are properly awakened. 562 - * 563 - * Inline the same logic as previous test, add_element() cannot be 564 - * directly used here since it has BUG_ON to deny if min_nr equals 565 - * curr_nr, so here picked rest of add_element() to use without 566 - * BUG_ON check. 567 558 */ 568 559 if (unlikely(pool->min_nr == 0 && 569 560 READ_ONCE(pool->curr_nr) == 0)) { 570 561 spin_lock_irqsave(&pool->lock, flags); 571 562 if (likely(pool->curr_nr == 0)) { 572 - /* Inline the logic of add_element() */ 573 - poison_element(pool, element); 574 - if (kasan_poison_element(pool, element)) 575 - pool->elements[pool->curr_nr++] = element; 563 + add_element(pool, element); 576 564 spin_unlock_irqrestore(&pool->lock, flags); 577 565 if (wq_has_sleeper(&pool->wait)) 578 566 wake_up(&pool->wait);
+3
mm/mincore.c
··· 29 29 #ifdef CONFIG_HUGETLB_PAGE 30 30 unsigned char present; 31 31 unsigned char *vec = walk->private; 32 + spinlock_t *ptl; 32 33 34 + ptl = huge_pte_lock(hstate_vma(walk->vma), walk->mm, pte); 33 35 /* 34 36 * Hugepages under user process are always in RAM and never 35 37 * swapped out, but theoretically it needs to be checked. ··· 40 38 for (; addr != end; vec++, addr += PAGE_SIZE) 41 39 *vec = present; 42 40 walk->private = vec; 41 + spin_unlock(ptl); 43 42 #else 44 43 BUG(); 45 44 #endif
+3 -7
mm/mmap_lock.c
··· 164 164 */ 165 165 166 166 /* Check if the vma we locked is the right one. */ 167 - if (unlikely(vma->vm_mm != mm || 168 - address < vma->vm_start || address >= vma->vm_end)) 167 + if (unlikely(address < vma->vm_start || address >= vma->vm_end)) 169 168 goto inval_end_read; 170 169 171 170 rcu_read_unlock(); ··· 235 236 goto fallback; 236 237 } 237 238 238 - /* 239 - * Verify the vma we locked belongs to the same address space and it's 240 - * not behind of the last search position. 241 - */ 242 - if (unlikely(vma->vm_mm != mm || from_addr >= vma->vm_end)) 239 + /* Verify the vma is not behind the last search position. */ 240 + if (unlikely(from_addr >= vma->vm_end)) 243 241 goto fallback_unlock; 244 242 245 243 /*
+1 -1
mm/mprotect.c
··· 766 766 unsigned long charged = 0; 767 767 int error; 768 768 769 - if (!can_modify_vma(vma)) 769 + if (vma_is_sealed(vma)) 770 770 return -EPERM; 771 771 772 772 if (newflags == oldflags) {
+2 -2
mm/mremap.c
··· 280 280 old_pte, max_nr_ptes); 281 281 force_flush = true; 282 282 } 283 - pte = get_and_clear_full_ptes(mm, old_addr, old_ptep, nr_ptes, 0); 283 + pte = get_and_clear_ptes(mm, old_addr, old_ptep, nr_ptes); 284 284 pte = move_pte(pte, old_addr, new_addr); 285 285 pte = move_soft_dirty_pte(pte); 286 286 ··· 1651 1651 return -EFAULT; 1652 1652 1653 1653 /* If mseal()'d, mremap() is prohibited. */ 1654 - if (!can_modify_vma(vma)) 1654 + if (vma_is_sealed(vma)) 1655 1655 return -EPERM; 1656 1656 1657 1657 /* Align to hugetlb page size, if required. */
+46 -124
mm/mseal.c
··· 11 11 #include <linux/mman.h> 12 12 #include <linux/mm.h> 13 13 #include <linux/mm_inline.h> 14 - #include <linux/mmu_context.h> 15 14 #include <linux/syscalls.h> 16 15 #include <linux/sched.h> 17 16 #include "internal.h" 18 17 19 - static inline void set_vma_sealed(struct vm_area_struct *vma) 20 - { 21 - vm_flags_set(vma, VM_SEALED); 22 - } 23 - 24 - static bool is_madv_discard(int behavior) 25 - { 26 - switch (behavior) { 27 - case MADV_FREE: 28 - case MADV_DONTNEED: 29 - case MADV_DONTNEED_LOCKED: 30 - case MADV_REMOVE: 31 - case MADV_DONTFORK: 32 - case MADV_WIPEONFORK: 33 - case MADV_GUARD_INSTALL: 34 - return true; 35 - } 36 - 37 - return false; 38 - } 39 - 40 - static bool is_ro_anon(struct vm_area_struct *vma) 41 - { 42 - /* check anonymous mapping. */ 43 - if (vma->vm_file || vma->vm_flags & VM_SHARED) 44 - return false; 45 - 46 - /* 47 - * check for non-writable: 48 - * PROT=RO or PKRU is not writeable. 49 - */ 50 - if (!(vma->vm_flags & VM_WRITE) || 51 - !arch_vma_access_permitted(vma, true, false, false)) 52 - return true; 53 - 54 - return false; 55 - } 18 + /* 19 + * mseal() disallows an input range which contain unmapped ranges (VMA holes). 20 + * 21 + * It disallows unmapped regions from start to end whether they exist at the 22 + * start, in the middle, or at the end of the range, or any combination thereof. 23 + * 24 + * This is because after sealng a range, there's nothing to stop memory mapping 25 + * of ranges in the remaining gaps later, meaning that the user might then 26 + * wrongly consider the entirety of the mseal()'d range to be sealed when it 27 + * in fact isn't. 28 + */ 56 29 57 30 /* 58 - * Check if a vma is allowed to be modified by madvise. 31 + * Does the [start, end) range contain any unmapped memory? 32 + * 33 + * We ensure that: 34 + * - start is part of a valid VMA. 35 + * - end is part of a valid VMA. 36 + * - no gap (unallocated memory) exists between start and end. 59 37 */ 60 - bool can_modify_vma_madv(struct vm_area_struct *vma, int behavior) 61 - { 62 - if (!is_madv_discard(behavior)) 63 - return true; 64 - 65 - if (unlikely(!can_modify_vma(vma) && is_ro_anon(vma))) 66 - return false; 67 - 68 - /* Allow by default. */ 69 - return true; 70 - } 71 - 72 - static int mseal_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma, 73 - struct vm_area_struct **prev, unsigned long start, 74 - unsigned long end, vm_flags_t newflags) 75 - { 76 - int ret = 0; 77 - vm_flags_t oldflags = vma->vm_flags; 78 - 79 - if (newflags == oldflags) 80 - goto out; 81 - 82 - vma = vma_modify_flags(vmi, *prev, vma, start, end, newflags); 83 - if (IS_ERR(vma)) { 84 - ret = PTR_ERR(vma); 85 - goto out; 86 - } 87 - 88 - set_vma_sealed(vma); 89 - out: 90 - *prev = vma; 91 - return ret; 92 - } 93 - 94 - /* 95 - * Check for do_mseal: 96 - * 1> start is part of a valid vma. 97 - * 2> end is part of a valid vma. 98 - * 3> No gap (unallocated address) between start and end. 99 - * 4> map is sealable. 100 - */ 101 - static int check_mm_seal(unsigned long start, unsigned long end) 38 + static bool range_contains_unmapped(struct mm_struct *mm, 39 + unsigned long start, unsigned long end) 102 40 { 103 41 struct vm_area_struct *vma; 104 - unsigned long nstart = start; 105 - 42 + unsigned long prev_end = start; 106 43 VMA_ITERATOR(vmi, current->mm, start); 107 44 108 - /* going through each vma to check. */ 109 45 for_each_vma_range(vmi, vma, end) { 110 - if (vma->vm_start > nstart) 111 - /* unallocated memory found. */ 112 - return -ENOMEM; 46 + if (vma->vm_start > prev_end) 47 + return true; 113 48 114 - if (vma->vm_end >= end) 115 - return 0; 116 - 117 - nstart = vma->vm_end; 49 + prev_end = vma->vm_end; 118 50 } 119 51 120 - return -ENOMEM; 52 + return prev_end < end; 121 53 } 122 54 123 - /* 124 - * Apply sealing. 125 - */ 126 - static int apply_mm_seal(unsigned long start, unsigned long end) 55 + static int mseal_apply(struct mm_struct *mm, 56 + unsigned long start, unsigned long end) 127 57 { 128 - unsigned long nstart; 129 58 struct vm_area_struct *vma, *prev; 59 + unsigned long curr_start = start; 60 + VMA_ITERATOR(vmi, mm, start); 130 61 131 - VMA_ITERATOR(vmi, current->mm, start); 132 - 62 + /* We know there are no gaps so this will be non-NULL. */ 133 63 vma = vma_iter_load(&vmi); 134 - /* 135 - * Note: check_mm_seal should already checked ENOMEM case. 136 - * so vma should not be null, same for the other ENOMEM cases. 137 - */ 138 64 prev = vma_prev(&vmi); 139 65 if (start > vma->vm_start) 140 66 prev = vma; 141 67 142 - nstart = start; 143 68 for_each_vma_range(vmi, vma, end) { 144 - int error; 145 - unsigned long tmp; 146 - vm_flags_t newflags; 69 + unsigned long curr_end = MIN(vma->vm_end, end); 147 70 148 - newflags = vma->vm_flags | VM_SEALED; 149 - tmp = vma->vm_end; 150 - if (tmp > end) 151 - tmp = end; 152 - error = mseal_fixup(&vmi, vma, &prev, nstart, tmp, newflags); 153 - if (error) 154 - return error; 155 - nstart = vma_iter_end(&vmi); 71 + if (!(vma->vm_flags & VM_SEALED)) { 72 + vma = vma_modify_flags(&vmi, prev, vma, 73 + curr_start, curr_end, 74 + vma->vm_flags | VM_SEALED); 75 + if (IS_ERR(vma)) 76 + return PTR_ERR(vma); 77 + vm_flags_set(vma, VM_SEALED); 78 + } 79 + 80 + prev = vma; 81 + curr_start = curr_end; 156 82 } 157 83 158 84 return 0; ··· 166 240 if (mmap_write_lock_killable(mm)) 167 241 return -EINTR; 168 242 169 - /* 170 - * First pass, this helps to avoid 171 - * partial sealing in case of error in input address range, 172 - * e.g. ENOMEM error. 173 - */ 174 - ret = check_mm_seal(start, end); 175 - if (ret) 243 + if (range_contains_unmapped(mm, start, end)) { 244 + ret = -ENOMEM; 176 245 goto out; 246 + } 177 247 178 248 /* 179 249 * Second pass, this should success, unless there are errors ··· 177 255 * reaching the max supported VMAs, however, those cases shall 178 256 * be rare. 179 257 */ 180 - ret = apply_mm_seal(start, end); 258 + ret = mseal_apply(mm, start, end); 181 259 182 260 out: 183 - mmap_write_unlock(current->mm); 261 + mmap_write_unlock(mm); 184 262 return ret; 185 263 } 186 264
+1 -1
mm/nommu.c
··· 126 126 127 127 void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align, 128 128 unsigned long start, unsigned long end, gfp_t gfp_mask, 129 - pgprot_t prot, vm_flags_t vm_flags, int node, 129 + pgprot_t prot, unsigned long vm_flags, int node, 130 130 const void *caller) 131 131 { 132 132 return __vmalloc_noprof(size, gfp_mask);
+1 -1
mm/rmap.c
··· 2036 2036 flush_cache_range(vma, address, end_addr); 2037 2037 2038 2038 /* Nuke the page table entry. */ 2039 - pteval = get_and_clear_full_ptes(mm, address, pvmw.pte, nr_pages, 0); 2039 + pteval = get_and_clear_ptes(mm, address, pvmw.pte, nr_pages); 2040 2040 /* 2041 2041 * We clear the PTE but do not flush so potentially 2042 2042 * a remote CPU could still be writing to the folio.
+155 -126
mm/shmem.c
··· 512 512 513 513 /* 514 514 * Sometimes, before we decide whether to proceed or to fail, we must check 515 - * that an entry was not already brought back from swap by a racing thread. 515 + * that an entry was not already brought back or split by a racing thread. 516 516 * 517 517 * Checking folio is not enough: by the time a swapcache folio is locked, it 518 518 * might be reused, and again be swapcache, using the same swap as before. 519 + * Returns the swap entry's order if it still presents, else returns -1. 519 520 */ 520 - static bool shmem_confirm_swap(struct address_space *mapping, 521 - pgoff_t index, swp_entry_t swap) 521 + static int shmem_confirm_swap(struct address_space *mapping, pgoff_t index, 522 + swp_entry_t swap) 522 523 { 523 - return xa_load(&mapping->i_pages, index) == swp_to_radix_entry(swap); 524 + XA_STATE(xas, &mapping->i_pages, index); 525 + int ret = -1; 526 + void *entry; 527 + 528 + rcu_read_lock(); 529 + do { 530 + entry = xas_load(&xas); 531 + if (entry == swp_to_radix_entry(swap)) 532 + ret = xas_get_order(&xas); 533 + } while (xas_retry(&xas, entry)); 534 + rcu_read_unlock(); 535 + return ret; 524 536 } 525 537 526 538 /* ··· 903 891 pgoff_t index, void *expected, gfp_t gfp) 904 892 { 905 893 XA_STATE_ORDER(xas, &mapping->i_pages, index, folio_order(folio)); 906 - long nr = folio_nr_pages(folio); 894 + unsigned long nr = folio_nr_pages(folio); 895 + swp_entry_t iter, swap; 896 + void *entry; 907 897 908 898 VM_BUG_ON_FOLIO(index != round_down(index, nr), folio); 909 899 VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); ··· 917 903 918 904 gfp &= GFP_RECLAIM_MASK; 919 905 folio_throttle_swaprate(folio, gfp); 906 + swap = radix_to_swp_entry(expected); 920 907 921 908 do { 909 + iter = swap; 922 910 xas_lock_irq(&xas); 923 - if (expected != xas_find_conflict(&xas)) { 924 - xas_set_err(&xas, -EEXIST); 925 - goto unlock; 911 + xas_for_each_conflict(&xas, entry) { 912 + /* 913 + * The range must either be empty, or filled with 914 + * expected swap entries. Shmem swap entries are never 915 + * partially freed without split of both entry and 916 + * folio, so there shouldn't be any holes. 917 + */ 918 + if (!expected || entry != swp_to_radix_entry(iter)) { 919 + xas_set_err(&xas, -EEXIST); 920 + goto unlock; 921 + } 922 + iter.val += 1 << xas_get_order(&xas); 926 923 } 927 - if (expected && xas_find_conflict(&xas)) { 924 + if (expected && iter.val - nr != swap.val) { 928 925 xas_set_err(&xas, -EEXIST); 929 926 goto unlock; 930 927 } ··· 2017 1992 swp_entry_t entry, int order, gfp_t gfp) 2018 1993 { 2019 1994 struct shmem_inode_info *info = SHMEM_I(inode); 1995 + int nr_pages = 1 << order; 2020 1996 struct folio *new; 1997 + gfp_t alloc_gfp; 2021 1998 void *shadow; 2022 - int nr_pages; 2023 1999 2024 2000 /* 2025 2001 * We have arrived here because our zones are constrained, so don't 2026 2002 * limit chance of success with further cpuset and node constraints. 2027 2003 */ 2028 2004 gfp &= ~GFP_CONSTRAINT_MASK; 2029 - if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && order > 0) { 2030 - gfp_t huge_gfp = vma_thp_gfp_mask(vma); 2005 + alloc_gfp = gfp; 2006 + if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { 2007 + if (WARN_ON_ONCE(order)) 2008 + return ERR_PTR(-EINVAL); 2009 + } else if (order) { 2010 + /* 2011 + * If uffd is active for the vma, we need per-page fault 2012 + * fidelity to maintain the uffd semantics, then fallback 2013 + * to swapin order-0 folio, as well as for zswap case. 2014 + * Any existing sub folio in the swap cache also blocks 2015 + * mTHP swapin. 2016 + */ 2017 + if ((vma && unlikely(userfaultfd_armed(vma))) || 2018 + !zswap_never_enabled() || 2019 + non_swapcache_batch(entry, nr_pages) != nr_pages) 2020 + goto fallback; 2031 2021 2032 - gfp = limit_gfp_mask(huge_gfp, gfp); 2022 + alloc_gfp = limit_gfp_mask(vma_thp_gfp_mask(vma), gfp); 2023 + } 2024 + retry: 2025 + new = shmem_alloc_folio(alloc_gfp, order, info, index); 2026 + if (!new) { 2027 + new = ERR_PTR(-ENOMEM); 2028 + goto fallback; 2033 2029 } 2034 2030 2035 - new = shmem_alloc_folio(gfp, order, info, index); 2036 - if (!new) 2037 - return ERR_PTR(-ENOMEM); 2038 - 2039 - nr_pages = folio_nr_pages(new); 2040 2031 if (mem_cgroup_swapin_charge_folio(new, vma ? vma->vm_mm : NULL, 2041 - gfp, entry)) { 2032 + alloc_gfp, entry)) { 2042 2033 folio_put(new); 2043 - return ERR_PTR(-ENOMEM); 2034 + new = ERR_PTR(-ENOMEM); 2035 + goto fallback; 2044 2036 } 2045 2037 2046 2038 /* ··· 2072 2030 */ 2073 2031 if (swapcache_prepare(entry, nr_pages)) { 2074 2032 folio_put(new); 2075 - return ERR_PTR(-EEXIST); 2033 + new = ERR_PTR(-EEXIST); 2034 + /* Try smaller folio to avoid cache conflict */ 2035 + goto fallback; 2076 2036 } 2077 2037 2078 2038 __folio_set_locked(new); ··· 2088 2044 folio_add_lru(new); 2089 2045 swap_read_folio(new, NULL); 2090 2046 return new; 2047 + fallback: 2048 + /* Order 0 swapin failed, nothing to fallback to, abort */ 2049 + if (!order) 2050 + return new; 2051 + entry.val += index - round_down(index, nr_pages); 2052 + alloc_gfp = gfp; 2053 + nr_pages = 1; 2054 + order = 0; 2055 + goto retry; 2091 2056 } 2092 2057 2093 2058 /* ··· 2302 2249 if (xas_error(&xas)) 2303 2250 return xas_error(&xas); 2304 2251 2305 - return entry_order; 2252 + return 0; 2306 2253 } 2307 2254 2308 2255 /* ··· 2319 2266 struct address_space *mapping = inode->i_mapping; 2320 2267 struct mm_struct *fault_mm = vma ? vma->vm_mm : NULL; 2321 2268 struct shmem_inode_info *info = SHMEM_I(inode); 2269 + swp_entry_t swap, index_entry; 2322 2270 struct swap_info_struct *si; 2323 2271 struct folio *folio = NULL; 2324 2272 bool skip_swapcache = false; 2325 - swp_entry_t swap; 2326 - int error, nr_pages, order, split_order; 2273 + int error, nr_pages, order; 2274 + pgoff_t offset; 2327 2275 2328 2276 VM_BUG_ON(!*foliop || !xa_is_value(*foliop)); 2329 - swap = radix_to_swp_entry(*foliop); 2277 + index_entry = radix_to_swp_entry(*foliop); 2278 + swap = index_entry; 2330 2279 *foliop = NULL; 2331 2280 2332 - if (is_poisoned_swp_entry(swap)) 2281 + if (is_poisoned_swp_entry(index_entry)) 2333 2282 return -EIO; 2334 2283 2335 - si = get_swap_device(swap); 2336 - if (!si) { 2337 - if (!shmem_confirm_swap(mapping, index, swap)) 2284 + si = get_swap_device(index_entry); 2285 + order = shmem_confirm_swap(mapping, index, index_entry); 2286 + if (unlikely(!si)) { 2287 + if (order < 0) 2338 2288 return -EEXIST; 2339 2289 else 2340 2290 return -EINVAL; 2341 2291 } 2292 + if (unlikely(order < 0)) { 2293 + put_swap_device(si); 2294 + return -EEXIST; 2295 + } 2296 + 2297 + /* index may point to the middle of a large entry, get the sub entry */ 2298 + if (order) { 2299 + offset = index - round_down(index, 1 << order); 2300 + swap = swp_entry(swp_type(swap), swp_offset(swap) + offset); 2301 + } 2342 2302 2343 2303 /* Look it up and read it in.. */ 2344 2304 folio = swap_cache_get_folio(swap, NULL, 0); 2345 - order = xa_get_order(&mapping->i_pages, index); 2346 2305 if (!folio) { 2347 - int nr_pages = 1 << order; 2348 - bool fallback_order0 = false; 2349 - 2350 - /* Or update major stats only when swapin succeeds?? */ 2306 + if (data_race(si->flags & SWP_SYNCHRONOUS_IO)) { 2307 + /* Direct swapin skipping swap cache & readahead */ 2308 + folio = shmem_swap_alloc_folio(inode, vma, index, 2309 + index_entry, order, gfp); 2310 + if (IS_ERR(folio)) { 2311 + error = PTR_ERR(folio); 2312 + folio = NULL; 2313 + goto failed; 2314 + } 2315 + skip_swapcache = true; 2316 + } else { 2317 + /* Cached swapin only supports order 0 folio */ 2318 + folio = shmem_swapin_cluster(swap, gfp, info, index); 2319 + if (!folio) { 2320 + error = -ENOMEM; 2321 + goto failed; 2322 + } 2323 + } 2351 2324 if (fault_type) { 2352 2325 *fault_type |= VM_FAULT_MAJOR; 2353 2326 count_vm_event(PGMAJFAULT); 2354 2327 count_memcg_event_mm(fault_mm, PGMAJFAULT); 2355 2328 } 2329 + } 2356 2330 2331 + if (order > folio_order(folio)) { 2357 2332 /* 2358 - * If uffd is active for the vma, we need per-page fault 2359 - * fidelity to maintain the uffd semantics, then fallback 2360 - * to swapin order-0 folio, as well as for zswap case. 2361 - * Any existing sub folio in the swap cache also blocks 2362 - * mTHP swapin. 2363 - */ 2364 - if (order > 0 && ((vma && unlikely(userfaultfd_armed(vma))) || 2365 - !zswap_never_enabled() || 2366 - non_swapcache_batch(swap, nr_pages) != nr_pages)) 2367 - fallback_order0 = true; 2368 - 2369 - /* Skip swapcache for synchronous device. */ 2370 - if (!fallback_order0 && data_race(si->flags & SWP_SYNCHRONOUS_IO)) { 2371 - folio = shmem_swap_alloc_folio(inode, vma, index, swap, order, gfp); 2372 - if (!IS_ERR(folio)) { 2373 - skip_swapcache = true; 2374 - goto alloced; 2375 - } 2376 - 2377 - /* 2378 - * Fallback to swapin order-0 folio unless the swap entry 2379 - * already exists. 2380 - */ 2381 - error = PTR_ERR(folio); 2382 - folio = NULL; 2383 - if (error == -EEXIST) 2384 - goto failed; 2385 - } 2386 - 2387 - /* 2388 - * Now swap device can only swap in order 0 folio, then we 2389 - * should split the large swap entry stored in the pagecache 2390 - * if necessary. 2391 - */ 2392 - split_order = shmem_split_large_entry(inode, index, swap, gfp); 2393 - if (split_order < 0) { 2394 - error = split_order; 2395 - goto failed; 2396 - } 2397 - 2398 - /* 2399 - * If the large swap entry has already been split, it is 2400 - * necessary to recalculate the new swap entry based on 2401 - * the old order alignment. 2402 - */ 2403 - if (split_order > 0) { 2404 - pgoff_t offset = index - round_down(index, 1 << split_order); 2405 - 2406 - swap = swp_entry(swp_type(swap), swp_offset(swap) + offset); 2407 - } 2408 - 2409 - /* Here we actually start the io */ 2410 - folio = shmem_swapin_cluster(swap, gfp, info, index); 2411 - if (!folio) { 2412 - error = -ENOMEM; 2413 - goto failed; 2414 - } 2415 - } else if (order != folio_order(folio)) { 2416 - /* 2417 - * Swap readahead may swap in order 0 folios into swapcache 2333 + * Swapin may get smaller folios due to various reasons: 2334 + * It may fallback to order 0 due to memory pressure or race, 2335 + * swap readahead may swap in order 0 folios into swapcache 2418 2336 * asynchronously, while the shmem mapping can still stores 2419 2337 * large swap entries. In such cases, we should split the 2420 2338 * large swap entry to prevent possible data corruption. 2421 2339 */ 2422 - split_order = shmem_split_large_entry(inode, index, swap, gfp); 2423 - if (split_order < 0) { 2424 - folio_put(folio); 2425 - folio = NULL; 2426 - error = split_order; 2427 - goto failed; 2428 - } 2429 - 2430 - /* 2431 - * If the large swap entry has already been split, it is 2432 - * necessary to recalculate the new swap entry based on 2433 - * the old order alignment. 2434 - */ 2435 - if (split_order > 0) { 2436 - pgoff_t offset = index - round_down(index, 1 << split_order); 2437 - 2438 - swap = swp_entry(swp_type(swap), swp_offset(swap) + offset); 2439 - } 2340 + error = shmem_split_large_entry(inode, index, index_entry, gfp); 2341 + if (error) 2342 + goto failed_nolock; 2440 2343 } 2441 2344 2442 - alloced: 2443 - /* We have to do this with folio locked to prevent races */ 2345 + /* 2346 + * If the folio is large, round down swap and index by folio size. 2347 + * No matter what race occurs, the swap layer ensures we either get 2348 + * a valid folio that has its swap entry aligned by size, or a 2349 + * temporarily invalid one which we'll abort very soon and retry. 2350 + * 2351 + * shmem_add_to_page_cache ensures the whole range contains expected 2352 + * entries and prevents any corruption, so any race split is fine 2353 + * too, it will succeed as long as the entries are still there. 2354 + */ 2355 + nr_pages = folio_nr_pages(folio); 2356 + if (nr_pages > 1) { 2357 + swap.val = round_down(swap.val, nr_pages); 2358 + index = round_down(index, nr_pages); 2359 + } 2360 + 2361 + /* 2362 + * We have to do this with the folio locked to prevent races. 2363 + * The shmem_confirm_swap below only checks if the first swap 2364 + * entry matches the folio, that's enough to ensure the folio 2365 + * is not used outside of shmem, as shmem swap entries 2366 + * and swap cache folios are never partially freed. 2367 + */ 2444 2368 folio_lock(folio); 2445 2369 if ((!skip_swapcache && !folio_test_swapcache(folio)) || 2446 - folio->swap.val != swap.val || 2447 - !shmem_confirm_swap(mapping, index, swap) || 2448 - xa_get_order(&mapping->i_pages, index) != folio_order(folio)) { 2370 + shmem_confirm_swap(mapping, index, swap) < 0 || 2371 + folio->swap.val != swap.val) { 2449 2372 error = -EEXIST; 2450 2373 goto unlock; 2451 2374 } ··· 2444 2415 goto failed; 2445 2416 } 2446 2417 2447 - error = shmem_add_to_page_cache(folio, mapping, 2448 - round_down(index, nr_pages), 2418 + error = shmem_add_to_page_cache(folio, mapping, index, 2449 2419 swp_to_radix_entry(swap), gfp); 2450 2420 if (error) 2451 2421 goto failed; ··· 2467 2439 *foliop = folio; 2468 2440 return 0; 2469 2441 failed: 2470 - if (!shmem_confirm_swap(mapping, index, swap)) 2442 + if (shmem_confirm_swap(mapping, index, swap) < 0) 2471 2443 error = -EEXIST; 2472 2444 if (error == -EIO) 2473 2445 shmem_set_folio_swapin_error(inode, index, folio, swap, 2474 2446 skip_swapcache); 2475 2447 unlock: 2476 - if (skip_swapcache) 2477 - swapcache_clear(si, swap, folio_nr_pages(folio)); 2478 - if (folio) { 2448 + if (folio) 2479 2449 folio_unlock(folio); 2450 + failed_nolock: 2451 + if (skip_swapcache) 2452 + swapcache_clear(si, folio->swap, folio_nr_pages(folio)); 2453 + if (folio) 2480 2454 folio_put(folio); 2481 - } 2482 2455 put_swap_device(si); 2483 2456 2484 2457 return error; ··· 5989 5960 struct folio *folio; 5990 5961 int error; 5991 5962 5992 - error = shmem_get_folio_gfp(inode, index, 0, &folio, SGP_CACHE, 5993 - gfp, NULL, NULL); 5963 + error = shmem_get_folio_gfp(inode, index, i_size_read(inode), 5964 + &folio, SGP_CACHE, gfp, NULL, NULL); 5994 5965 if (error) 5995 5966 return ERR_PTR(error); 5996 5967
+2 -3
mm/slub.c
··· 6312 6312 if (debug_guardpage_minorder()) 6313 6313 slub_max_order = 0; 6314 6314 6315 - /* Print slub debugging pointers without hashing */ 6316 - if (__slub_debug_enabled()) 6317 - no_hash_pointers_enable(NULL); 6315 + /* Inform pointer hashing choice about slub debugging state. */ 6316 + hash_pointers_finalize(__slub_debug_enabled()); 6318 6317 6319 6318 kmem_cache_node = &boot_kmem_cache_node; 6320 6319 kmem_cache = &boot_kmem_cache;
+2 -2
mm/vma.c
··· 1351 1351 } 1352 1352 1353 1353 /* Don't bother splitting the VMA if we can't unmap it anyway */ 1354 - if (!can_modify_vma(vms->vma)) { 1354 + if (vma_is_sealed(vms->vma)) { 1355 1355 error = -EPERM; 1356 1356 goto start_split_failed; 1357 1357 } ··· 1371 1371 for_each_vma_range(*(vms->vmi), next, vms->end) { 1372 1372 long nrpages; 1373 1373 1374 - if (!can_modify_vma(next)) { 1374 + if (vma_is_sealed(next)) { 1375 1375 error = -EPERM; 1376 1376 goto modify_vma_failed; 1377 1377 }
+2 -25
mm/vma.h
··· 559 559 } 560 560 561 561 #ifdef CONFIG_64BIT 562 - 563 562 static inline bool vma_is_sealed(struct vm_area_struct *vma) 564 563 { 565 564 return (vma->vm_flags & VM_SEALED); 566 565 } 567 - 568 - /* 569 - * check if a vma is sealed for modification. 570 - * return true, if modification is allowed. 571 - */ 572 - static inline bool can_modify_vma(struct vm_area_struct *vma) 573 - { 574 - if (unlikely(vma_is_sealed(vma))) 575 - return false; 576 - 577 - return true; 578 - } 579 - 580 - bool can_modify_vma_madv(struct vm_area_struct *vma, int behavior); 581 - 582 566 #else 583 - 584 - static inline bool can_modify_vma(struct vm_area_struct *vma) 567 + static inline bool vma_is_sealed(struct vm_area_struct *vma) 585 568 { 586 - return true; 569 + return false; 587 570 } 588 - 589 - static inline bool can_modify_vma_madv(struct vm_area_struct *vma, int behavior) 590 - { 591 - return true; 592 - } 593 - 594 571 #endif 595 572 596 573 #if defined(CONFIG_STACK_GROWSUP)
+8
rust/Makefile
··· 34 34 obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o 35 35 36 36 always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs 37 + ifndef CONFIG_UML 38 + always-$(subst y,$(CONFIG_RUST),$(CONFIG_BUG)) += kernel/generated_arch_warn_asm.rs kernel/generated_arch_reachable_asm.rs 39 + endif 37 40 38 41 # Avoids running `$(RUSTC)` when it may not be available. 39 42 ifdef CONFIG_RUST ··· 543 540 544 541 ifdef CONFIG_JUMP_LABEL 545 542 $(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs 543 + endif 544 + ifndef CONFIG_UML 545 + ifdef CONFIG_BUG 546 + $(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generated_arch_reachable_asm.rs 547 + endif 546 548 endif 547 549 548 550 endif # CONFIG_RUST
+3
rust/bindings/lib.rs
··· 25 25 )] 26 26 27 27 #[allow(dead_code)] 28 + #[allow(clippy::cast_lossless)] 29 + #[allow(clippy::ptr_as_ptr)] 30 + #[allow(clippy::ref_as_ptr)] 28 31 #[allow(clippy::undocumented_unsafe_blocks)] 29 32 #[cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))] 30 33 mod bindings_raw {
+5
rust/helpers/bug.c
··· 6 6 { 7 7 BUG(); 8 8 } 9 + 10 + bool rust_helper_WARN_ON(bool cond) 11 + { 12 + return WARN_ON(cond); 13 + }
+3 -2
rust/helpers/helpers.c
··· 30 30 #include "mutex.c" 31 31 #include "of.c" 32 32 #include "page.c" 33 - #include "platform.c" 34 33 #include "pci.c" 35 34 #include "pid_namespace.c" 35 + #include "platform.c" 36 36 #include "poll.c" 37 37 #include "property.c" 38 38 #include "rbtree.c" 39 - #include "regulator.c" 40 39 #include "rcu.c" 41 40 #include "refcount.c" 41 + #include "regulator.c" 42 42 #include "security.c" 43 43 #include "signal.c" 44 44 #include "slab.c" 45 45 #include "spinlock.c" 46 46 #include "sync.c" 47 47 #include "task.c" 48 + #include "time.c" 48 49 #include "uaccess.c" 49 50 #include "vmalloc.c" 50 51 #include "wait.c"
+35
rust/helpers/time.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/delay.h> 4 + #include <linux/ktime.h> 5 + #include <linux/timekeeping.h> 6 + 7 + void rust_helper_fsleep(unsigned long usecs) 8 + { 9 + fsleep(usecs); 10 + } 11 + 12 + ktime_t rust_helper_ktime_get_real(void) 13 + { 14 + return ktime_get_real(); 15 + } 16 + 17 + ktime_t rust_helper_ktime_get_boottime(void) 18 + { 19 + return ktime_get_boottime(); 20 + } 21 + 22 + ktime_t rust_helper_ktime_get_clocktai(void) 23 + { 24 + return ktime_get_clocktai(); 25 + } 26 + 27 + s64 rust_helper_ktime_to_us(const ktime_t kt) 28 + { 29 + return ktime_to_us(kt); 30 + } 31 + 32 + s64 rust_helper_ktime_to_ms(const ktime_t kt) 33 + { 34 + return ktime_to_ms(kt); 35 + }
+2
rust/kernel/.gitignore
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 /generated_arch_static_branch_asm.rs 4 + /generated_arch_warn_asm.rs 5 + /generated_arch_reachable_asm.rs
+1 -1
rust/kernel/alloc/allocator_test.rs
··· 82 82 83 83 // SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or 84 84 // exceeds the given size and alignment requirements. 85 - let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8; 85 + let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) }.cast::<u8>(); 86 86 let dst = NonNull::new(dst).ok_or(AllocError)?; 87 87 88 88 if flags.contains(__GFP_ZERO) {
+80 -18
rust/kernel/alloc/kbox.rs
··· 6 6 use super::allocator::{KVmalloc, Kmalloc, Vmalloc}; 7 7 use super::{AllocError, Allocator, Flags}; 8 8 use core::alloc::Layout; 9 + use core::borrow::{Borrow, BorrowMut}; 9 10 use core::fmt; 10 11 use core::marker::PhantomData; 11 12 use core::mem::ManuallyDrop; ··· 16 15 use core::ptr::NonNull; 17 16 use core::result::Result; 18 17 18 + use crate::ffi::c_void; 19 19 use crate::init::InPlaceInit; 20 20 use crate::types::ForeignOwnable; 21 21 use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption}; ··· 400 398 } 401 399 } 402 400 403 - // SAFETY: The `into_foreign` function returns a pointer that is well-aligned. 401 + // SAFETY: The pointer returned by `into_foreign` comes from a well aligned 402 + // pointer to `T`. 404 403 unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> 405 404 where 406 405 A: Allocator, 407 406 { 408 - type PointedTo = T; 407 + const FOREIGN_ALIGN: usize = core::mem::align_of::<T>(); 409 408 type Borrowed<'a> = &'a T; 410 409 type BorrowedMut<'a> = &'a mut T; 411 410 412 - fn into_foreign(self) -> *mut Self::PointedTo { 413 - Box::into_raw(self) 411 + fn into_foreign(self) -> *mut c_void { 412 + Box::into_raw(self).cast() 414 413 } 415 414 416 - unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { 415 + unsafe fn from_foreign(ptr: *mut c_void) -> Self { 417 416 // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous 418 417 // call to `Self::into_foreign`. 419 - unsafe { Box::from_raw(ptr) } 418 + unsafe { Box::from_raw(ptr.cast()) } 420 419 } 421 420 422 - unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T { 421 + unsafe fn borrow<'a>(ptr: *mut c_void) -> &'a T { 423 422 // SAFETY: The safety requirements of this method ensure that the object remains alive and 424 423 // immutable for the duration of 'a. 425 - unsafe { &*ptr } 424 + unsafe { &*ptr.cast() } 426 425 } 427 426 428 - unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T { 427 + unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a mut T { 428 + let ptr = ptr.cast(); 429 429 // SAFETY: The safety requirements of this method ensure that the pointer is valid and that 430 430 // nothing else will access the value for the duration of 'a. 431 431 unsafe { &mut *ptr } 432 432 } 433 433 } 434 434 435 - // SAFETY: The `into_foreign` function returns a pointer that is well-aligned. 435 + // SAFETY: The pointer returned by `into_foreign` comes from a well aligned 436 + // pointer to `T`. 436 437 unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> 437 438 where 438 439 A: Allocator, 439 440 { 440 - type PointedTo = T; 441 + const FOREIGN_ALIGN: usize = core::mem::align_of::<T>(); 441 442 type Borrowed<'a> = Pin<&'a T>; 442 443 type BorrowedMut<'a> = Pin<&'a mut T>; 443 444 444 - fn into_foreign(self) -> *mut Self::PointedTo { 445 + fn into_foreign(self) -> *mut c_void { 445 446 // SAFETY: We are still treating the box as pinned. 446 - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) 447 + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() 447 448 } 448 449 449 - unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { 450 + unsafe fn from_foreign(ptr: *mut c_void) -> Self { 450 451 // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous 451 452 // call to `Self::into_foreign`. 452 - unsafe { Pin::new_unchecked(Box::from_raw(ptr)) } 453 + unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) } 453 454 } 454 455 455 - unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> { 456 + unsafe fn borrow<'a>(ptr: *mut c_void) -> Pin<&'a T> { 456 457 // SAFETY: The safety requirements for this function ensure that the object is still alive, 457 458 // so it is safe to dereference the raw pointer. 458 459 // The safety requirements of `from_foreign` also ensure that the object remains alive for 459 460 // the lifetime of the returned value. 460 - let r = unsafe { &*ptr }; 461 + let r = unsafe { &*ptr.cast() }; 461 462 462 463 // SAFETY: This pointer originates from a `Pin<Box<T>>`. 463 464 unsafe { Pin::new_unchecked(r) } 464 465 } 465 466 466 - unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> { 467 + unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Pin<&'a mut T> { 468 + let ptr = ptr.cast(); 467 469 // SAFETY: The safety requirements for this function ensure that the object is still alive, 468 470 // so it is safe to dereference the raw pointer. 469 471 // The safety requirements of `from_foreign` also ensure that the object remains alive for ··· 502 496 // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized 503 497 // instance of `T`. 504 498 unsafe { self.0.as_mut() } 499 + } 500 + } 501 + 502 + /// # Examples 503 + /// 504 + /// ``` 505 + /// # use core::borrow::Borrow; 506 + /// # use kernel::alloc::KBox; 507 + /// struct Foo<B: Borrow<u32>>(B); 508 + /// 509 + /// // Owned instance. 510 + /// let owned = Foo(1); 511 + /// 512 + /// // Owned instance using `KBox`. 513 + /// let owned_kbox = Foo(KBox::new(1, GFP_KERNEL)?); 514 + /// 515 + /// let i = 1; 516 + /// // Borrowed from `i`. 517 + /// let borrowed = Foo(&i); 518 + /// # Ok::<(), Error>(()) 519 + /// ``` 520 + impl<T, A> Borrow<T> for Box<T, A> 521 + where 522 + T: ?Sized, 523 + A: Allocator, 524 + { 525 + fn borrow(&self) -> &T { 526 + self.deref() 527 + } 528 + } 529 + 530 + /// # Examples 531 + /// 532 + /// ``` 533 + /// # use core::borrow::BorrowMut; 534 + /// # use kernel::alloc::KBox; 535 + /// struct Foo<B: BorrowMut<u32>>(B); 536 + /// 537 + /// // Owned instance. 538 + /// let owned = Foo(1); 539 + /// 540 + /// // Owned instance using `KBox`. 541 + /// let owned_kbox = Foo(KBox::new(1, GFP_KERNEL)?); 542 + /// 543 + /// let mut i = 1; 544 + /// // Borrowed from `i`. 545 + /// let borrowed = Foo(&mut i); 546 + /// # Ok::<(), Error>(()) 547 + /// ``` 548 + impl<T, A> BorrowMut<T> for Box<T, A> 549 + where 550 + T: ?Sized, 551 + A: Allocator, 552 + { 553 + fn borrow_mut(&mut self) -> &mut T { 554 + self.deref_mut() 505 555 } 506 556 } 507 557
+56 -3
rust/kernel/alloc/kvec.rs
··· 8 8 AllocError, Allocator, Box, Flags, 9 9 }; 10 10 use core::{ 11 + borrow::{Borrow, BorrowMut}, 11 12 fmt, 12 13 marker::PhantomData, 13 14 mem::{ManuallyDrop, MaybeUninit}, ··· 289 288 // - `self.len` is smaller than `self.capacity` by the type invariant and hence, the 290 289 // resulting pointer is guaranteed to be part of the same allocated object. 291 290 // - `self.len` can not overflow `isize`. 292 - let ptr = unsafe { self.as_mut_ptr().add(self.len) } as *mut MaybeUninit<T>; 291 + let ptr = unsafe { self.as_mut_ptr().add(self.len) }.cast::<MaybeUninit<T>>(); 293 292 294 293 // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated 295 294 // and valid, but uninitialized. ··· 848 847 // - `ptr` points to memory with at least a size of `size_of::<T>() * len`, 849 848 // - all elements within `b` are initialized values of `T`, 850 849 // - `len` does not exceed `isize::MAX`. 851 - unsafe { Vec::from_raw_parts(ptr as _, len, len) } 850 + unsafe { Vec::from_raw_parts(ptr.cast(), len, len) } 852 851 } 853 852 } 854 853 855 - impl<T> Default for KVec<T> { 854 + impl<T, A: Allocator> Default for Vec<T, A> { 856 855 #[inline] 857 856 fn default() -> Self { 858 857 Self::new() ··· 888 887 // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len` 889 888 // initialized elements of type `T`. 890 889 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } 890 + } 891 + } 892 + 893 + /// # Examples 894 + /// 895 + /// ``` 896 + /// # use core::borrow::Borrow; 897 + /// struct Foo<B: Borrow<[u32]>>(B); 898 + /// 899 + /// // Owned array. 900 + /// let owned_array = Foo([1, 2, 3]); 901 + /// 902 + /// // Owned vector. 903 + /// let owned_vec = Foo(KVec::from_elem(0, 3, GFP_KERNEL)?); 904 + /// 905 + /// let arr = [1, 2, 3]; 906 + /// // Borrowed slice from `arr`. 907 + /// let borrowed_slice = Foo(&arr[..]); 908 + /// # Ok::<(), Error>(()) 909 + /// ``` 910 + impl<T, A> Borrow<[T]> for Vec<T, A> 911 + where 912 + A: Allocator, 913 + { 914 + fn borrow(&self) -> &[T] { 915 + self.as_slice() 916 + } 917 + } 918 + 919 + /// # Examples 920 + /// 921 + /// ``` 922 + /// # use core::borrow::BorrowMut; 923 + /// struct Foo<B: BorrowMut<[u32]>>(B); 924 + /// 925 + /// // Owned array. 926 + /// let owned_array = Foo([1, 2, 3]); 927 + /// 928 + /// // Owned vector. 929 + /// let owned_vec = Foo(KVec::from_elem(0, 3, GFP_KERNEL)?); 930 + /// 931 + /// let mut arr = [1, 2, 3]; 932 + /// // Borrowed slice from `arr`. 933 + /// let borrowed_slice = Foo(&mut arr[..]); 934 + /// # Ok::<(), Error>(()) 935 + /// ``` 936 + impl<T, A> BorrowMut<[T]> for Vec<T, A> 937 + where 938 + A: Allocator, 939 + { 940 + fn borrow_mut(&mut self) -> &mut [T] { 941 + self.as_mut_slice() 891 942 } 892 943 } 893 944
+203
rust/kernel/bits.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Bit manipulation macros. 4 + //! 5 + //! C header: [`include/linux/bits.h`](srctree/include/linux/bits.h) 6 + 7 + use crate::prelude::*; 8 + use core::ops::RangeInclusive; 9 + use macros::paste; 10 + 11 + macro_rules! impl_bit_fn { 12 + ( 13 + $ty:ty 14 + ) => { 15 + paste! { 16 + /// Computes `1 << n` if `n` is in bounds, i.e.: if `n` is smaller than 17 + /// the maximum number of bits supported by the type. 18 + /// 19 + /// Returns [`None`] otherwise. 20 + #[inline] 21 + pub fn [<checked_bit_ $ty>](n: u32) -> Option<$ty> { 22 + (1 as $ty).checked_shl(n) 23 + } 24 + 25 + /// Computes `1 << n` by performing a compile-time assertion that `n` is 26 + /// in bounds. 27 + /// 28 + /// This version is the default and should be used if `n` is known at 29 + /// compile time. 30 + #[inline] 31 + pub const fn [<bit_ $ty>](n: u32) -> $ty { 32 + build_assert!(n < <$ty>::BITS); 33 + (1 as $ty) << n 34 + } 35 + } 36 + }; 37 + } 38 + 39 + impl_bit_fn!(u64); 40 + impl_bit_fn!(u32); 41 + impl_bit_fn!(u16); 42 + impl_bit_fn!(u8); 43 + 44 + macro_rules! impl_genmask_fn { 45 + ( 46 + $ty:ty, 47 + $(#[$genmask_checked_ex:meta])*, 48 + $(#[$genmask_ex:meta])* 49 + ) => { 50 + paste! { 51 + /// Creates a contiguous bitmask for the given range by validating 52 + /// the range at runtime. 53 + /// 54 + /// Returns [`None`] if the range is invalid, i.e.: if the start is 55 + /// greater than the end or if the range is outside of the 56 + /// representable range for the type. 57 + $(#[$genmask_checked_ex])* 58 + #[inline] 59 + pub fn [<genmask_checked_ $ty>](range: RangeInclusive<u32>) -> Option<$ty> { 60 + let start = *range.start(); 61 + let end = *range.end(); 62 + 63 + if start > end { 64 + return None; 65 + } 66 + 67 + let high = [<checked_bit_ $ty>](end)?; 68 + let low = [<checked_bit_ $ty>](start)?; 69 + Some((high | (high - 1)) & !(low - 1)) 70 + } 71 + 72 + /// Creates a compile-time contiguous bitmask for the given range by 73 + /// performing a compile-time assertion that the range is valid. 74 + /// 75 + /// This version is the default and should be used if the range is known 76 + /// at compile time. 77 + $(#[$genmask_ex])* 78 + #[inline] 79 + pub const fn [<genmask_ $ty>](range: RangeInclusive<u32>) -> $ty { 80 + let start = *range.start(); 81 + let end = *range.end(); 82 + 83 + build_assert!(start <= end); 84 + 85 + let high = [<bit_ $ty>](end); 86 + let low = [<bit_ $ty>](start); 87 + (high | (high - 1)) & !(low - 1) 88 + } 89 + } 90 + }; 91 + } 92 + 93 + impl_genmask_fn!( 94 + u64, 95 + /// # Examples 96 + /// 97 + /// ``` 98 + /// # #![expect(clippy::reversed_empty_ranges)] 99 + /// # use kernel::bits::genmask_checked_u64; 100 + /// assert_eq!(genmask_checked_u64(0..=0), Some(0b1)); 101 + /// assert_eq!(genmask_checked_u64(0..=63), Some(u64::MAX)); 102 + /// assert_eq!(genmask_checked_u64(21..=39), Some(0x0000_00ff_ffe0_0000)); 103 + /// 104 + /// // `80` is out of the supported bit range. 105 + /// assert_eq!(genmask_checked_u64(21..=80), None); 106 + /// 107 + /// // Invalid range where the start is bigger than the end. 108 + /// assert_eq!(genmask_checked_u64(15..=8), None); 109 + /// ``` 110 + , 111 + /// # Examples 112 + /// 113 + /// ``` 114 + /// # use kernel::bits::genmask_u64; 115 + /// assert_eq!(genmask_u64(21..=39), 0x0000_00ff_ffe0_0000); 116 + /// assert_eq!(genmask_u64(0..=0), 0b1); 117 + /// assert_eq!(genmask_u64(0..=63), u64::MAX); 118 + /// ``` 119 + ); 120 + 121 + impl_genmask_fn!( 122 + u32, 123 + /// # Examples 124 + /// 125 + /// ``` 126 + /// # #![expect(clippy::reversed_empty_ranges)] 127 + /// # use kernel::bits::genmask_checked_u32; 128 + /// assert_eq!(genmask_checked_u32(0..=0), Some(0b1)); 129 + /// assert_eq!(genmask_checked_u32(0..=31), Some(u32::MAX)); 130 + /// assert_eq!(genmask_checked_u32(21..=31), Some(0xffe0_0000)); 131 + /// 132 + /// // `40` is out of the supported bit range. 133 + /// assert_eq!(genmask_checked_u32(21..=40), None); 134 + /// 135 + /// // Invalid range where the start is bigger than the end. 136 + /// assert_eq!(genmask_checked_u32(15..=8), None); 137 + /// ``` 138 + , 139 + /// # Examples 140 + /// 141 + /// ``` 142 + /// # use kernel::bits::genmask_u32; 143 + /// assert_eq!(genmask_u32(21..=31), 0xffe0_0000); 144 + /// assert_eq!(genmask_u32(0..=0), 0b1); 145 + /// assert_eq!(genmask_u32(0..=31), u32::MAX); 146 + /// ``` 147 + ); 148 + 149 + impl_genmask_fn!( 150 + u16, 151 + /// # Examples 152 + /// 153 + /// ``` 154 + /// # #![expect(clippy::reversed_empty_ranges)] 155 + /// # use kernel::bits::genmask_checked_u16; 156 + /// assert_eq!(genmask_checked_u16(0..=0), Some(0b1)); 157 + /// assert_eq!(genmask_checked_u16(0..=15), Some(u16::MAX)); 158 + /// assert_eq!(genmask_checked_u16(6..=15), Some(0xffc0)); 159 + /// 160 + /// // `20` is out of the supported bit range. 161 + /// assert_eq!(genmask_checked_u16(6..=20), None); 162 + /// 163 + /// // Invalid range where the start is bigger than the end. 164 + /// assert_eq!(genmask_checked_u16(10..=5), None); 165 + /// ``` 166 + , 167 + /// # Examples 168 + /// 169 + /// ``` 170 + /// # use kernel::bits::genmask_u16; 171 + /// assert_eq!(genmask_u16(6..=15), 0xffc0); 172 + /// assert_eq!(genmask_u16(0..=0), 0b1); 173 + /// assert_eq!(genmask_u16(0..=15), u16::MAX); 174 + /// ``` 175 + ); 176 + 177 + impl_genmask_fn!( 178 + u8, 179 + /// # Examples 180 + /// 181 + /// ``` 182 + /// # #![expect(clippy::reversed_empty_ranges)] 183 + /// # use kernel::bits::genmask_checked_u8; 184 + /// assert_eq!(genmask_checked_u8(0..=0), Some(0b1)); 185 + /// assert_eq!(genmask_checked_u8(0..=7), Some(u8::MAX)); 186 + /// assert_eq!(genmask_checked_u8(6..=7), Some(0xc0)); 187 + /// 188 + /// // `10` is out of the supported bit range. 189 + /// assert_eq!(genmask_checked_u8(6..=10), None); 190 + /// 191 + /// // Invalid range where the start is bigger than the end. 192 + /// assert_eq!(genmask_checked_u8(5..=2), None); 193 + /// ``` 194 + , 195 + /// # Examples 196 + /// 197 + /// ``` 198 + /// # use kernel::bits::genmask_u8; 199 + /// assert_eq!(genmask_u8(6..=7), 0xc0); 200 + /// assert_eq!(genmask_u8(0..=0), 0b1); 201 + /// assert_eq!(genmask_u8(0..=7), u8::MAX); 202 + /// ``` 203 + );
+1 -1
rust/kernel/block/mq.rs
··· 53 53 //! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder 54 54 //! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build 55 55 //! 56 - //! # Example 56 + //! # Examples 57 57 //! 58 58 //! ```rust 59 59 //! use kernel::{
+1 -1
rust/kernel/block/mq/operations.rs
··· 101 101 if let Err(e) = ret { 102 102 e.to_blk_status() 103 103 } else { 104 - bindings::BLK_STS_OK as _ 104 + bindings::BLK_STS_OK as bindings::blk_status_t 105 105 } 106 106 } 107 107
+8 -3
rust/kernel/block/mq/request.rs
··· 69 69 // INVARIANT: By the safety requirements of this function, invariants are upheld. 70 70 // SAFETY: By the safety requirement of this function, we own a 71 71 // reference count that we can pass to `ARef`. 72 - unsafe { ARef::from_raw(NonNull::new_unchecked(ptr as *const Self as *mut Self)) } 72 + unsafe { ARef::from_raw(NonNull::new_unchecked(ptr.cast())) } 73 73 } 74 74 75 75 /// Notify the block layer that a request is going to be processed now. ··· 125 125 // success of the call to `try_set_end` guarantees that there are no 126 126 // `ARef`s pointing to this request. Therefore it is safe to hand it 127 127 // back to the block layer. 128 - unsafe { bindings::blk_mq_end_request(request_ptr, bindings::BLK_STS_OK as _) }; 128 + unsafe { 129 + bindings::blk_mq_end_request( 130 + request_ptr, 131 + bindings::BLK_STS_OK as bindings::blk_status_t, 132 + ) 133 + }; 129 134 130 135 Ok(()) 131 136 } ··· 160 155 // the private data associated with this request is initialized and 161 156 // valid. The existence of `&self` guarantees that the private data is 162 157 // valid as a shared reference. 163 - unsafe { Self::wrapper_ptr(self as *const Self as *mut Self).as_ref() } 158 + unsafe { Self::wrapper_ptr(core::ptr::from_ref(self).cast_mut()).as_ref() } 164 159 } 165 160 } 166 161
+126
rust/kernel/bug.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + // Copyright (C) 2024, 2025 FUJITA Tomonori <fujita.tomonori@gmail.com> 4 + 5 + //! Support for BUG and WARN functionality. 6 + //! 7 + //! C header: [`include/asm-generic/bug.h`](srctree/include/asm-generic/bug.h) 8 + 9 + #[macro_export] 10 + #[doc(hidden)] 11 + #[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))] 12 + #[cfg(CONFIG_DEBUG_BUGVERBOSE)] 13 + macro_rules! warn_flags { 14 + ($flags:expr) => { 15 + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; 16 + const _FILE: &[u8] = file!().as_bytes(); 17 + // Plus one for null-terminator. 18 + static FILE: [u8; _FILE.len() + 1] = { 19 + let mut bytes = [0; _FILE.len() + 1]; 20 + let mut i = 0; 21 + while i < _FILE.len() { 22 + bytes[i] = _FILE[i]; 23 + i += 1; 24 + } 25 + bytes 26 + }; 27 + 28 + // SAFETY: 29 + // - `file`, `line`, `flags`, and `size` are all compile-time constants or 30 + // symbols, preventing any invalid memory access. 31 + // - The asm block has no side effects and does not modify any registers 32 + // or memory. It is purely for embedding metadata into the ELF section. 33 + unsafe { 34 + $crate::asm!( 35 + concat!( 36 + "/* {size} */", 37 + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), 38 + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); 39 + file = sym FILE, 40 + line = const line!(), 41 + flags = const FLAGS, 42 + size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), 43 + ); 44 + } 45 + } 46 + } 47 + 48 + #[macro_export] 49 + #[doc(hidden)] 50 + #[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))] 51 + #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] 52 + macro_rules! warn_flags { 53 + ($flags:expr) => { 54 + const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; 55 + 56 + // SAFETY: 57 + // - `flags` and `size` are all compile-time constants, preventing 58 + // any invalid memory access. 59 + // - The asm block has no side effects and does not modify any registers 60 + // or memory. It is purely for embedding metadata into the ELF section. 61 + unsafe { 62 + $crate::asm!( 63 + concat!( 64 + "/* {size} */", 65 + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), 66 + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); 67 + flags = const FLAGS, 68 + size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), 69 + ); 70 + } 71 + } 72 + } 73 + 74 + #[macro_export] 75 + #[doc(hidden)] 76 + #[cfg(all(CONFIG_BUG, CONFIG_UML))] 77 + macro_rules! warn_flags { 78 + ($flags:expr) => { 79 + // SAFETY: It is always safe to call `warn_slowpath_fmt()` 80 + // with a valid null-terminated string. 81 + unsafe { 82 + $crate::bindings::warn_slowpath_fmt( 83 + $crate::c_str!(::core::file!()).as_char_ptr(), 84 + line!() as $crate::ffi::c_int, 85 + $flags as $crate::ffi::c_uint, 86 + ::core::ptr::null(), 87 + ); 88 + } 89 + }; 90 + } 91 + 92 + #[macro_export] 93 + #[doc(hidden)] 94 + #[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))] 95 + macro_rules! warn_flags { 96 + ($flags:expr) => { 97 + // SAFETY: It is always safe to call `WARN_ON()`. 98 + unsafe { $crate::bindings::WARN_ON(true) } 99 + }; 100 + } 101 + 102 + #[macro_export] 103 + #[doc(hidden)] 104 + #[cfg(not(CONFIG_BUG))] 105 + macro_rules! warn_flags { 106 + ($flags:expr) => {}; 107 + } 108 + 109 + #[doc(hidden)] 110 + pub const fn bugflag_taint(value: u32) -> u32 { 111 + value << 8 112 + } 113 + 114 + /// Report a warning if `cond` is true and return the condition's evaluation result. 115 + #[macro_export] 116 + macro_rules! warn_on { 117 + ($cond:expr) => {{ 118 + let cond = $cond; 119 + if cond { 120 + const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN); 121 + 122 + $crate::warn_flags!(WARN_ON_FLAGS); 123 + } 124 + cond 125 + }}; 126 + }
+3 -3
rust/kernel/clk.rs
··· 12 12 /// 13 13 /// Represents a frequency in hertz, wrapping a [`c_ulong`] value. 14 14 /// 15 - /// ## Examples 15 + /// # Examples 16 16 /// 17 17 /// ``` 18 18 /// use kernel::clk::Hertz; ··· 99 99 /// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the 100 100 /// allocation remains valid for the lifetime of the [`Clk`]. 101 101 /// 102 - /// ## Examples 102 + /// # Examples 103 103 /// 104 104 /// The following example demonstrates how to obtain and configure a clock for a device. 105 105 /// ··· 266 266 /// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the 267 267 /// allocation remains valid for the lifetime of the [`OptionalClk`]. 268 268 /// 269 - /// ## Examples 269 + /// # Examples 270 270 /// 271 271 /// The following example demonstrates how to obtain and configure an optional clock for a 272 272 /// device. The code functions correctly whether or not the clock is available.
+11 -19
rust/kernel/configfs.rs
··· 17 17 //! 18 18 //! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h) 19 19 //! 20 - //! # Example 20 + //! # Examples 21 21 //! 22 22 //! ```ignore 23 23 //! use kernel::alloc::flags; ··· 151 151 data: impl PinInit<Data, Error>, 152 152 ) -> impl PinInit<Self, Error> { 153 153 try_pin_init!(Self { 154 - subsystem <- pin_init::zeroed().chain( 154 + subsystem <- pin_init::init_zeroed().chain( 155 155 |place: &mut Opaque<bindings::configfs_subsystem>| { 156 156 // SAFETY: We initialized the required fields of `place.group` above. 157 157 unsafe { ··· 261 261 data: impl PinInit<Data, Error>, 262 262 ) -> impl PinInit<Self, Error> { 263 263 try_pin_init!(Self { 264 - group <- pin_init::zeroed().chain(|v: &mut Opaque<bindings::config_group>| { 264 + group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| { 265 265 let place = v.get(); 266 266 let name = name.as_bytes_with_nul().as_ptr(); 267 267 // SAFETY: It is safe to initialize a group once it has been zeroed. ··· 279 279 // within the `group` field. 280 280 unsafe impl<Data> HasGroup<Data> for Group<Data> { 281 281 unsafe fn group(this: *const Self) -> *const bindings::config_group { 282 - Opaque::raw_get( 282 + Opaque::cast_into( 283 283 // SAFETY: By impl and function safety requirements this field 284 284 // projection is within bounds of the allocation. 285 285 unsafe { &raw const (*this).group }, ··· 426 426 }; 427 427 428 428 const fn vtable_ptr() -> *const bindings::configfs_group_operations { 429 - &Self::VTABLE as *const bindings::configfs_group_operations 429 + &Self::VTABLE 430 430 } 431 431 } 432 432 ··· 464 464 }; 465 465 466 466 const fn vtable_ptr() -> *const bindings::configfs_item_operations { 467 - &Self::VTABLE as *const bindings::configfs_item_operations 467 + &Self::VTABLE 468 468 } 469 469 } 470 470 ··· 476 476 }; 477 477 478 478 const fn vtable_ptr() -> *const bindings::configfs_item_operations { 479 - &Self::VTABLE as *const bindings::configfs_item_operations 479 + &Self::VTABLE 480 480 } 481 481 } 482 482 ··· 561 561 let data: &Data = unsafe { get_group_data(c_group) }; 562 562 563 563 // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`. 564 - let ret = O::show(data, unsafe { &mut *(page as *mut [u8; PAGE_SIZE]) }); 564 + let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) }); 565 565 566 566 match ret { 567 567 Ok(size) => size as isize, ··· 717 717 718 718 // SAFETY: By function safety requirements, we have exclusive access to 719 719 // `self` and the reference created below will be exclusive. 720 - unsafe { 721 - (&mut *self.0.get())[I] = (attribute as *const Attribute<ID, O, Data>) 722 - .cast_mut() 723 - .cast() 724 - }; 720 + unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() }; 725 721 } 726 722 } 727 723 ··· 757 761 ct_owner: owner.as_ptr(), 758 762 ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(), 759 763 ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(), 760 - ct_attrs: (attributes as *const AttributeList<N, Data>) 761 - .cast_mut() 762 - .cast(), 764 + ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(), 763 765 ct_bin_attrs: core::ptr::null_mut(), 764 766 }), 765 767 _p: PhantomData, ··· 774 780 ct_owner: owner.as_ptr(), 775 781 ct_group_ops: core::ptr::null_mut(), 776 782 ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(), 777 - ct_attrs: (attributes as *const AttributeList<N, Data>) 778 - .cast_mut() 779 - .cast(), 783 + ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(), 780 784 ct_bin_attrs: core::ptr::null_mut(), 781 785 }), 782 786 _p: PhantomData,
+5 -5
rust/kernel/cpufreq.rs
··· 202 202 /// The callers must ensure that the `struct cpufreq_frequency_table` is valid for access and 203 203 /// remains valid for the lifetime of the returned reference. 204 204 /// 205 - /// ## Examples 205 + /// # Examples 206 206 /// 207 207 /// The following example demonstrates how to read a frequency value from [`Table`]. 208 208 /// ··· 318 318 /// 319 319 /// This is used by the CPU frequency drivers to build a frequency table dynamically. 320 320 /// 321 - /// ## Examples 321 + /// # Examples 322 322 /// 323 323 /// The following example demonstrates how to create a CPU frequency table. 324 324 /// ··· 395 395 /// The callers must ensure that the `struct cpufreq_policy` is valid for access and remains valid 396 396 /// for the lifetime of the returned reference. 397 397 /// 398 - /// ## Examples 398 + /// # Examples 399 399 /// 400 400 /// The following example demonstrates how to create a CPU frequency table. 401 401 /// ··· 649 649 fn set_data<T: ForeignOwnable>(&mut self, data: T) -> Result { 650 650 if self.as_ref().driver_data.is_null() { 651 651 // Transfer the ownership of the data to the foreign interface. 652 - self.as_mut_ref().driver_data = <T as ForeignOwnable>::into_foreign(data) as _; 652 + self.as_mut_ref().driver_data = <T as ForeignOwnable>::into_foreign(data).cast(); 653 653 Ok(()) 654 654 } else { 655 655 Err(EBUSY) ··· 834 834 835 835 /// CPU frequency driver Registration. 836 836 /// 837 - /// ## Examples 837 + /// # Examples 838 838 /// 839 839 /// The following example demonstrates how to register a cpufreq driver. 840 840 ///
+2 -2
rust/kernel/cpumask.rs
··· 27 27 /// The callers must ensure that the `struct cpumask` is valid for access and 28 28 /// remains valid for the lifetime of the returned reference. 29 29 /// 30 - /// ## Examples 30 + /// # Examples 31 31 /// 32 32 /// The following example demonstrates how to update a [`Cpumask`]. 33 33 /// ··· 172 172 /// The callers must ensure that the `struct cpumask_var_t` is valid for access and remains valid 173 173 /// for the lifetime of [`CpumaskVar`]. 174 174 /// 175 - /// ## Examples 175 + /// # Examples 176 176 /// 177 177 /// The following example demonstrates how to create and update a [`CpumaskVar`]. 178 178 ///
+2 -2
rust/kernel/device.rs
··· 262 262 #[cfg(CONFIG_PRINTK)] 263 263 unsafe { 264 264 bindings::_dev_printk( 265 - klevel as *const _ as *const crate::ffi::c_char, 265 + klevel.as_ptr().cast::<crate::ffi::c_char>(), 266 266 self.as_raw(), 267 267 c_str!("%pA").as_char_ptr(), 268 - &msg as *const _ as *const crate::ffi::c_void, 268 + core::ptr::from_ref(&msg).cast::<crate::ffi::c_void>(), 269 269 ) 270 270 }; 271 271 }
+2 -2
rust/kernel/device_id.rs
··· 100 100 unsafe { 101 101 raw_ids[i] 102 102 .as_mut_ptr() 103 - .byte_offset(data_offset as _) 103 + .byte_add(data_offset) 104 104 .cast::<usize>() 105 105 .write(i); 106 106 } ··· 177 177 fn as_ptr(&self) -> *const T::RawType { 178 178 // This cannot be `self.ids.as_ptr()`, as the return pointer must have correct provenance 179 179 // to access the sentinel. 180 - (self as *const Self).cast() 180 + core::ptr::from_ref(self).cast() 181 181 } 182 182 183 183 fn id(&self, index: usize) -> &T::RawType {
+5 -5
rust/kernel/devres.rs
··· 49 49 /// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s 50 50 /// [`Drop`] implementation. 51 51 /// 52 - /// # Example 52 + /// # Examples 53 53 /// 54 54 /// ```no_run 55 55 /// # use kernel::{bindings, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}}; ··· 66 66 /// unsafe fn new(paddr: usize) -> Result<Self>{ 67 67 /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is 68 68 /// // valid for `ioremap`. 69 - /// let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) }; 69 + /// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) }; 70 70 /// if addr.is_null() { 71 71 /// return Err(ENOMEM); 72 72 /// } 73 73 /// 74 - /// Ok(IoMem(IoRaw::new(addr as _, SIZE)?)) 74 + /// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?)) 75 75 /// } 76 76 /// } 77 77 /// 78 78 /// impl<const SIZE: usize> Drop for IoMem<SIZE> { 79 79 /// fn drop(&mut self) { 80 80 /// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`. 81 - /// unsafe { bindings::iounmap(self.0.addr() as _); }; 81 + /// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); }; 82 82 /// } 83 83 /// } 84 84 /// ··· 219 219 /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance 220 220 /// has been created with. 221 221 /// 222 - /// # Example 222 + /// # Examples 223 223 /// 224 224 /// ```no_run 225 225 /// # #![cfg(CONFIG_PCI)]
+5 -5
rust/kernel/dma.rs
··· 180 180 impl Attrs { 181 181 /// Get the raw representation of this attribute. 182 182 pub(crate) fn as_raw(self) -> crate::ffi::c_ulong { 183 - self.0 as _ 183 + self.0 as crate::ffi::c_ulong 184 184 } 185 185 186 186 /// Check whether `flags` is contained in `self`. ··· 333 333 dev: dev.into(), 334 334 dma_handle, 335 335 count, 336 - cpu_addr: ret as *mut T, 336 + cpu_addr: ret.cast::<T>(), 337 337 dma_attrs, 338 338 }) 339 339 } ··· 436 436 /// slice is live. 437 437 /// * Callers must ensure that this call does not race with a read or write to the same region 438 438 /// while the returned slice is live. 439 - pub unsafe fn as_slice_mut(&self, offset: usize, count: usize) -> Result<&mut [T]> { 439 + pub unsafe fn as_slice_mut(&mut self, offset: usize, count: usize) -> Result<&mut [T]> { 440 440 self.validate_range(offset, count)?; 441 441 // SAFETY: 442 442 // - The pointer is valid due to type invariant on `CoherentAllocation`, ··· 468 468 /// unsafe { alloc.write(buf, 0)?; } 469 469 /// # Ok::<(), Error>(()) } 470 470 /// ``` 471 - pub unsafe fn write(&self, src: &[T], offset: usize) -> Result { 471 + pub unsafe fn write(&mut self, src: &[T], offset: usize) -> Result { 472 472 self.validate_range(offset, src.len())?; 473 473 // SAFETY: 474 474 // - The pointer is valid due to type invariant on `CoherentAllocation` ··· 556 556 bindings::dma_free_attrs( 557 557 self.dev.as_raw(), 558 558 size, 559 - self.cpu_addr as _, 559 + self.cpu_addr.cast(), 560 560 self.dma_handle, 561 561 self.dma_attrs.as_raw(), 562 562 )
+4 -6
rust/kernel/drm/device.rs
··· 83 83 major: T::INFO.major, 84 84 minor: T::INFO.minor, 85 85 patchlevel: T::INFO.patchlevel, 86 - name: T::INFO.name.as_char_ptr() as *mut _, 87 - desc: T::INFO.desc.as_char_ptr() as *mut _, 86 + name: T::INFO.name.as_char_ptr().cast_mut(), 87 + desc: T::INFO.desc.as_char_ptr().cast_mut(), 88 88 89 89 driver_features: drm::driver::FEAT_GEM, 90 90 ioctls: T::IOCTLS.as_ptr(), 91 91 num_ioctls: T::IOCTLS.len() as i32, 92 - fops: &Self::GEM_FOPS as _, 92 + fops: &Self::GEM_FOPS, 93 93 }; 94 94 95 95 const GEM_FOPS: bindings::file_operations = drm::gem::create_fops(); ··· 135 135 /// 136 136 /// `ptr` must be a valid pointer to a `struct device` embedded in `Self`. 137 137 unsafe fn from_drm_device(ptr: *const bindings::drm_device) -> *mut Self { 138 - let ptr: *const Opaque<bindings::drm_device> = ptr.cast(); 139 - 140 138 // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a 141 139 // `struct drm_device` embedded in `Self`. 142 - unsafe { crate::container_of!(ptr, Self, dev) }.cast_mut() 140 + unsafe { crate::container_of!(Opaque::cast_from(ptr), Self, dev) }.cast_mut() 143 141 } 144 142 145 143 /// Not intended to be called externally, except via declare_drm_ioctls!()
+1 -3
rust/kernel/drm/gem/mod.rs
··· 125 125 } 126 126 127 127 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self { 128 - let self_ptr: *mut Opaque<bindings::drm_gem_object> = self_ptr.cast(); 129 - 130 128 // SAFETY: `obj` is guaranteed to be in an `Object<T>` via the safety contract of this 131 129 // function 132 - unsafe { &*crate::container_of!(self_ptr, Object<T>, obj) } 130 + unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T>, obj) } 133 131 } 134 132 } 135 133
+5 -5
rust/kernel/error.rs
··· 6 6 7 7 use crate::{ 8 8 alloc::{layout::LayoutError, AllocError}, 9 + fmt, 9 10 str::CStr, 10 11 }; 11 12 12 - use core::fmt; 13 13 use core::num::NonZeroI32; 14 14 use core::num::TryFromIntError; 15 15 use core::str::Utf8Error; ··· 154 154 /// Returns the error encoded as a pointer. 155 155 pub fn to_ptr<T>(self) -> *mut T { 156 156 // SAFETY: `self.0` is a valid error due to its invariant. 157 - unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ } 157 + unsafe { bindings::ERR_PTR(self.0.get() as crate::ffi::c_long).cast() } 158 158 } 159 159 160 160 /// Returns a string representing the error, if one exists. ··· 189 189 Some(name) => f 190 190 .debug_tuple( 191 191 // SAFETY: These strings are ASCII-only. 192 - unsafe { core::str::from_utf8_unchecked(name) }, 192 + unsafe { core::str::from_utf8_unchecked(name.to_bytes()) }, 193 193 ) 194 194 .finish(), 195 195 } ··· 220 220 } 221 221 } 222 222 223 - impl From<core::fmt::Error> for Error { 224 - fn from(_: core::fmt::Error) -> Error { 223 + impl From<fmt::Error> for Error { 224 + fn from(_: fmt::Error) -> Error { 225 225 code::EINVAL 226 226 } 227 227 }
+5 -4
rust/kernel/firmware.rs
··· 62 62 fn request_internal(name: &CStr, dev: &Device, func: FwFunc) -> Result<Self> { 63 63 let mut fw: *mut bindings::firmware = core::ptr::null_mut(); 64 64 let pfw: *mut *mut bindings::firmware = &mut fw; 65 + let pfw: *mut *const bindings::firmware = pfw.cast(); 65 66 66 67 // SAFETY: `pfw` is a valid pointer to a NULL initialized `bindings::firmware` pointer. 67 68 // `name` and `dev` are valid as by their type invariants. 68 - let ret = unsafe { func.0(pfw as _, name.as_char_ptr(), dev.as_raw()) }; 69 + let ret = unsafe { func.0(pfw, name.as_char_ptr(), dev.as_raw()) }; 69 70 if ret != 0 { 70 71 return Err(Error::from_errno(ret)); 71 72 } ··· 140 139 /// Typically, such contracts would be enforced by a trait, however traits do not (yet) support 141 140 /// const functions. 142 141 /// 143 - /// # Example 142 + /// # Examples 144 143 /// 145 144 /// ``` 146 145 /// # mod module_firmware_test { ··· 182 181 /// module! { 183 182 /// type: MyModule, 184 183 /// name: "module_firmware_test", 185 - /// author: "Rust for Linux", 184 + /// authors: ["Rust for Linux"], 186 185 /// description: "module_firmware! test module", 187 186 /// license: "GPL", 188 187 /// } ··· 262 261 /// Append path components to the [`ModInfoBuilder`] instance. Paths need to be separated 263 262 /// with [`ModInfoBuilder::new_entry`]. 264 263 /// 265 - /// # Example 264 + /// # Examples 266 265 /// 267 266 /// ``` 268 267 /// use kernel::firmware::ModInfoBuilder;
+7
rust/kernel/fmt.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Formatting utilities. 4 + //! 5 + //! This module is intended to be used in place of `core::fmt` in kernel code. 6 + 7 + pub use core::fmt::{Arguments, Debug, Display, Error, Formatter, Result, Write};
+1 -1
rust/kernel/fs/file.rs
··· 366 366 // 367 367 // By the type invariants, there are no `fdget_pos` calls that did not take the 368 368 // `f_pos_lock` mutex. 369 - unsafe { LocalFile::from_raw_file(self as *const File as *const bindings::file) } 369 + unsafe { LocalFile::from_raw_file(core::ptr::from_ref(self).cast()) } 370 370 } 371 371 } 372 372
+7
rust/kernel/generated_arch_reachable_asm.rs.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #include <linux/bug.h> 4 + 5 + // Cut here. 6 + 7 + ::kernel::concat_literals!(ARCH_WARN_REACHABLE)
+7
rust/kernel/generated_arch_warn_asm.rs.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #include <linux/bug.h> 4 + 5 + // Cut here. 6 + 7 + ::kernel::concat_literals!(ARCH_WARN_ASM("{file}", "{line}", "{flags}", "{size}"))
+13 -21
rust/kernel/init.rs
··· 29 29 //! 30 30 //! ## General Examples 31 31 //! 32 - //! ```rust,ignore 33 - //! # #![allow(clippy::disallowed_names)] 32 + //! ```rust 33 + //! # #![expect(clippy::disallowed_names, clippy::undocumented_unsafe_blocks)] 34 34 //! use kernel::types::Opaque; 35 35 //! use pin_init::pin_init_from_closure; 36 36 //! 37 37 //! // assume we have some `raw_foo` type in C: 38 38 //! #[repr(C)] 39 39 //! struct RawFoo([u8; 16]); 40 - //! extern { 40 + //! extern "C" { 41 41 //! fn init_foo(_: *mut RawFoo); 42 42 //! } 43 43 //! ··· 66 66 //! }); 67 67 //! ``` 68 68 //! 69 - //! ```rust,ignore 70 - //! # #![allow(unreachable_pub, clippy::disallowed_names)] 69 + //! ```rust 70 + //! # #![expect(unreachable_pub, clippy::disallowed_names)] 71 71 //! use kernel::{prelude::*, types::Opaque}; 72 72 //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; 73 73 //! # mod bindings { 74 - //! # #![allow(non_camel_case_types)] 74 + //! # #![expect(non_camel_case_types, clippy::missing_safety_doc)] 75 75 //! # pub struct foo; 76 76 //! # pub unsafe fn init_foo(_ptr: *mut foo) {} 77 77 //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} 78 78 //! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 } 79 79 //! # } 80 - //! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround. 81 - //! # trait FromErrno { 82 - //! # fn from_errno(errno: core::ffi::c_int) -> Error { 83 - //! # // Dummy error that can be constructed outside the `kernel` crate. 84 - //! # Error::from(core::fmt::Error) 85 - //! # } 86 - //! # } 87 - //! # impl FromErrno for Error {} 88 80 //! /// # Invariants 89 81 //! /// 90 82 //! /// `foo` is always initialized ··· 100 108 //! let foo = addr_of_mut!((*slot).foo); 101 109 //! 102 110 //! // Initialize the `foo` 103 - //! bindings::init_foo(Opaque::raw_get(foo)); 111 + //! bindings::init_foo(Opaque::cast_into(foo)); 104 112 //! 105 113 //! // Try to enable it. 106 - //! let err = bindings::enable_foo(Opaque::raw_get(foo), flags); 114 + //! let err = bindings::enable_foo(Opaque::cast_into(foo), flags); 107 115 //! if err != 0 { 108 116 //! // Enabling has failed, first clean up the foo and then return the error. 109 - //! bindings::destroy_foo(Opaque::raw_get(foo)); 117 + //! bindings::destroy_foo(Opaque::cast_into(foo)); 110 118 //! return Err(Error::from_errno(err)); 111 119 //! } 112 120 //! ··· 198 206 /// 199 207 /// ```rust 200 208 /// use kernel::error::Error; 201 - /// use pin_init::zeroed; 209 + /// use pin_init::init_zeroed; 202 210 /// struct BigBuf { 203 211 /// big: KBox<[u8; 1024 * 1024 * 1024]>, 204 212 /// small: [u8; 1024 * 1024], ··· 207 215 /// impl BigBuf { 208 216 /// fn new() -> impl Init<Self, Error> { 209 217 /// try_init!(Self { 210 - /// big: KBox::init(zeroed(), GFP_KERNEL)?, 218 + /// big: KBox::init(init_zeroed(), GFP_KERNEL)?, 211 219 /// small: [0; 1024 * 1024], 212 220 /// }? Error) 213 221 /// } ··· 256 264 /// ```rust 257 265 /// # #![feature(new_uninit)] 258 266 /// use kernel::error::Error; 259 - /// use pin_init::zeroed; 267 + /// use pin_init::init_zeroed; 260 268 /// #[pin_data] 261 269 /// struct BigBuf { 262 270 /// big: KBox<[u8; 1024 * 1024 * 1024]>, ··· 267 275 /// impl BigBuf { 268 276 /// fn new() -> impl PinInit<Self, Error> { 269 277 /// try_pin_init!(Self { 270 - /// big: KBox::init(zeroed(), GFP_KERNEL)?, 278 + /// big: KBox::init(init_zeroed(), GFP_KERNEL)?, 271 279 /// small: [0; 1024 * 1024], 272 280 /// ptr: core::ptr::null_mut(), 273 281 /// }? Error)
+10 -10
rust/kernel/io.rs
··· 5 5 //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h) 6 6 7 7 use crate::error::{code::EINVAL, Result}; 8 - use crate::{bindings, build_assert}; 8 + use crate::{bindings, build_assert, ffi::c_void}; 9 9 10 10 pub mod mem; 11 11 pub mod resource; ··· 48 48 } 49 49 } 50 50 51 - /// IO-mapped memory, starting at the base address @addr and spanning @maxlen bytes. 51 + /// IO-mapped memory region. 52 52 /// 53 53 /// The creator (usually a subsystem / bus such as PCI) is responsible for creating the 54 54 /// mapping, performing an additional region request etc. ··· 61 61 /// # Examples 62 62 /// 63 63 /// ```no_run 64 - /// # use kernel::{bindings, io::{Io, IoRaw}}; 64 + /// # use kernel::{bindings, ffi::c_void, io::{Io, IoRaw}}; 65 65 /// # use core::ops::Deref; 66 66 /// 67 67 /// // See also [`pci::Bar`] for a real example. ··· 75 75 /// unsafe fn new(paddr: usize) -> Result<Self>{ 76 76 /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is 77 77 /// // valid for `ioremap`. 78 - /// let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) }; 78 + /// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) }; 79 79 /// if addr.is_null() { 80 80 /// return Err(ENOMEM); 81 81 /// } 82 82 /// 83 - /// Ok(IoMem(IoRaw::new(addr as _, SIZE)?)) 83 + /// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?)) 84 84 /// } 85 85 /// } 86 86 /// 87 87 /// impl<const SIZE: usize> Drop for IoMem<SIZE> { 88 88 /// fn drop(&mut self) { 89 89 /// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`. 90 - /// unsafe { bindings::iounmap(self.0.addr() as _); }; 90 + /// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); }; 91 91 /// } 92 92 /// } 93 93 /// ··· 124 124 let addr = self.io_addr_assert::<$type_name>(offset); 125 125 126 126 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 127 - unsafe { bindings::$c_fn(addr as _) } 127 + unsafe { bindings::$c_fn(addr as *const c_void) } 128 128 } 129 129 130 130 /// Read IO data from a given offset. ··· 136 136 let addr = self.io_addr::<$type_name>(offset)?; 137 137 138 138 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 139 - Ok(unsafe { bindings::$c_fn(addr as _) }) 139 + Ok(unsafe { bindings::$c_fn(addr as *const c_void) }) 140 140 } 141 141 }; 142 142 } ··· 153 153 let addr = self.io_addr_assert::<$type_name>(offset); 154 154 155 155 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 156 - unsafe { bindings::$c_fn(value, addr as _, ) } 156 + unsafe { bindings::$c_fn(value, addr as *mut c_void) } 157 157 } 158 158 159 159 /// Write IO data from a given offset. ··· 165 165 let addr = self.io_addr::<$type_name>(offset)?; 166 166 167 167 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 168 - unsafe { bindings::$c_fn(value, addr as _) } 168 + unsafe { bindings::$c_fn(value, addr as *mut c_void) } 169 169 Ok(()) 170 170 } 171 171 };
+8 -5
rust/kernel/kunit.rs
··· 7 7 //! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html> 8 8 9 9 use crate::prelude::*; 10 - use core::{ffi::c_void, fmt}; 10 + use core::fmt; 11 + 12 + #[cfg(CONFIG_PRINTK)] 13 + use crate::c_str; 11 14 12 15 /// Prints a KUnit error-level message. 13 16 /// ··· 22 19 #[cfg(CONFIG_PRINTK)] 23 20 unsafe { 24 21 bindings::_printk( 25 - c"\x013%pA".as_ptr() as _, 26 - &args as *const _ as *const c_void, 22 + c_str!("\x013%pA").as_char_ptr(), 23 + core::ptr::from_ref(&args).cast::<c_void>(), 27 24 ); 28 25 } 29 26 } ··· 38 35 #[cfg(CONFIG_PRINTK)] 39 36 unsafe { 40 37 bindings::_printk( 41 - c"\x016%pA".as_ptr() as _, 42 - &args as *const _ as *const c_void, 38 + c_str!("\x016%pA").as_char_ptr(), 39 + core::ptr::from_ref(&args).cast::<c_void>(), 43 40 ); 44 41 } 45 42 }
+10
rust/kernel/lib.rs
··· 62 62 pub mod alloc; 63 63 #[cfg(CONFIG_AUXILIARY_BUS)] 64 64 pub mod auxiliary; 65 + pub mod bits; 65 66 #[cfg(CONFIG_BLOCK)] 66 67 pub mod block; 68 + pub mod bug; 67 69 #[doc(hidden)] 68 70 pub mod build_assert; 69 71 pub mod clk; ··· 87 85 pub mod faux; 88 86 #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] 89 87 pub mod firmware; 88 + pub mod fmt; 90 89 pub mod fs; 91 90 pub mod init; 92 91 pub mod io; ··· 215 212 } 216 213 217 214 /// Produces a pointer to an object from a pointer to one of its fields. 215 + /// 216 + /// If you encounter a type mismatch due to the [`Opaque`] type, then use [`Opaque::cast_into`] or 217 + /// [`Opaque::cast_from`] to resolve the mismatch. 218 + /// 219 + /// [`Opaque`]: crate::types::Opaque 220 + /// [`Opaque::cast_into`]: crate::types::Opaque::cast_into 221 + /// [`Opaque::cast_from`]: crate::types::Opaque::cast_from 218 222 /// 219 223 /// # Safety 220 224 ///
+32 -31
rust/kernel/list.rs
··· 57 57 /// } 58 58 /// } 59 59 /// 60 - /// impl_has_list_links! { 61 - /// impl HasListLinks<0> for BasicItem { self.links } 62 - /// } 63 60 /// impl_list_arc_safe! { 64 61 /// impl ListArcSafe<0> for BasicItem { untracked; } 65 62 /// } 66 63 /// impl_list_item! { 67 - /// impl ListItem<0> for BasicItem { using ListLinks; } 64 + /// impl ListItem<0> for BasicItem { using ListLinks { self.links }; } 68 65 /// } 69 66 /// 70 67 /// // Create a new empty list. ··· 79 82 /// // [15, 10, 30] 80 83 /// { 81 84 /// let mut iter = list.iter(); 82 - /// assert_eq!(iter.next().unwrap().value, 15); 83 - /// assert_eq!(iter.next().unwrap().value, 10); 84 - /// assert_eq!(iter.next().unwrap().value, 30); 85 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 15); 86 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 10); 87 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 30); 85 88 /// assert!(iter.next().is_none()); 86 89 /// 87 90 /// // Verify the length of the list. ··· 90 93 /// 91 94 /// // Pop the items from the list using `pop_back()` and verify the content. 92 95 /// { 93 - /// assert_eq!(list.pop_back().unwrap().value, 30); 94 - /// assert_eq!(list.pop_back().unwrap().value, 10); 95 - /// assert_eq!(list.pop_back().unwrap().value, 15); 96 + /// assert_eq!(list.pop_back().ok_or(EINVAL)?.value, 30); 97 + /// assert_eq!(list.pop_back().ok_or(EINVAL)?.value, 10); 98 + /// assert_eq!(list.pop_back().ok_or(EINVAL)?.value, 15); 96 99 /// } 97 100 /// 98 101 /// // Insert 3 elements using `push_front()`. ··· 104 107 /// // [30, 10, 15] 105 108 /// { 106 109 /// let mut iter = list.iter(); 107 - /// assert_eq!(iter.next().unwrap().value, 30); 108 - /// assert_eq!(iter.next().unwrap().value, 10); 109 - /// assert_eq!(iter.next().unwrap().value, 15); 110 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 30); 111 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 10); 112 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 15); 110 113 /// assert!(iter.next().is_none()); 111 114 /// 112 115 /// // Verify the length of the list. ··· 115 118 /// 116 119 /// // Pop the items from the list using `pop_front()` and verify the content. 117 120 /// { 118 - /// assert_eq!(list.pop_front().unwrap().value, 30); 119 - /// assert_eq!(list.pop_front().unwrap().value, 10); 121 + /// assert_eq!(list.pop_front().ok_or(EINVAL)?.value, 30); 122 + /// assert_eq!(list.pop_front().ok_or(EINVAL)?.value, 10); 120 123 /// } 121 124 /// 122 125 /// // Push `list2` to `list` through `push_all_back()`. ··· 132 135 /// // list: [15, 25, 35] 133 136 /// // list2: [] 134 137 /// let mut iter = list.iter(); 135 - /// assert_eq!(iter.next().unwrap().value, 15); 136 - /// assert_eq!(iter.next().unwrap().value, 25); 137 - /// assert_eq!(iter.next().unwrap().value, 35); 138 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 15); 139 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 25); 140 + /// assert_eq!(iter.next().ok_or(EINVAL)?.value, 35); 138 141 /// assert!(iter.next().is_none()); 139 142 /// assert!(list2.is_empty()); 140 143 /// } ··· 281 284 #[inline] 282 285 unsafe fn fields(me: *mut Self) -> *mut ListLinksFields { 283 286 // SAFETY: The caller promises that the pointer is valid. 284 - unsafe { Opaque::raw_get(ptr::addr_of!((*me).inner)) } 287 + unsafe { Opaque::cast_into(ptr::addr_of!((*me).inner)) } 285 288 } 286 289 287 290 /// # Safety ··· 317 320 unsafe impl<T: ?Sized + Sync, const ID: u64> Sync for ListLinksSelfPtr<T, ID> {} 318 321 319 322 impl<T: ?Sized, const ID: u64> ListLinksSelfPtr<T, ID> { 320 - /// The offset from the [`ListLinks`] to the self pointer field. 321 - pub const LIST_LINKS_SELF_PTR_OFFSET: usize = core::mem::offset_of!(Self, self_ptr); 322 - 323 323 /// Creates a new initializer for this type. 324 324 pub fn new() -> impl PinInit<Self> { 325 325 // INVARIANT: Pin-init initializers can't be used on an existing `Arc`, so this value will ··· 330 336 }, 331 337 self_ptr: Opaque::uninit(), 332 338 } 339 + } 340 + 341 + /// Returns a pointer to the self pointer. 342 + /// 343 + /// # Safety 344 + /// 345 + /// The provided pointer must point at a valid struct of type `Self`. 346 + pub unsafe fn raw_get_self_ptr(me: *const Self) -> *const Opaque<*const T> { 347 + // SAFETY: The caller promises that the pointer is valid. 348 + unsafe { ptr::addr_of!((*me).self_ptr) } 333 349 } 334 350 } 335 351 ··· 715 711 /// } 716 712 /// } 717 713 /// 718 - /// kernel::list::impl_has_list_links! { 719 - /// impl HasListLinks<0> for ListItem { self.links } 720 - /// } 721 714 /// kernel::list::impl_list_arc_safe! { 722 715 /// impl ListArcSafe<0> for ListItem { untracked; } 723 716 /// } 724 717 /// kernel::list::impl_list_item! { 725 - /// impl ListItem<0> for ListItem { using ListLinks; } 718 + /// impl ListItem<0> for ListItem { using ListLinks { self.links }; } 726 719 /// } 727 720 /// 728 721 /// // Use a cursor to remove the first element with the given value. ··· 810 809 /// merge_sorted(&mut list, list2); 811 810 /// 812 811 /// let mut items = list.into_iter(); 813 - /// assert_eq!(items.next().unwrap().value, 10); 814 - /// assert_eq!(items.next().unwrap().value, 11); 815 - /// assert_eq!(items.next().unwrap().value, 12); 816 - /// assert_eq!(items.next().unwrap().value, 13); 817 - /// assert_eq!(items.next().unwrap().value, 14); 812 + /// assert_eq!(items.next().ok_or(EINVAL)?.value, 10); 813 + /// assert_eq!(items.next().ok_or(EINVAL)?.value, 11); 814 + /// assert_eq!(items.next().ok_or(EINVAL)?.value, 12); 815 + /// assert_eq!(items.next().ok_or(EINVAL)?.value, 13); 816 + /// assert_eq!(items.next().ok_or(EINVAL)?.value, 14); 818 817 /// assert!(items.next().is_none()); 819 818 /// # Result::<(), Error>::Ok(()) 820 819 /// ```
+158 -81
rust/kernel/list/impl_list_item_mod.rs
··· 4 4 5 5 //! Helpers for implementing list traits safely. 6 6 7 - use crate::list::ListLinks; 8 - 9 - /// Declares that this type has a `ListLinks<ID>` field at a fixed offset. 7 + /// Declares that this type has a [`ListLinks<ID>`] field. 10 8 /// 11 - /// This trait is only used to help implement `ListItem` safely. If `ListItem` is implemented 9 + /// This trait is only used to help implement [`ListItem`] safely. If [`ListItem`] is implemented 12 10 /// manually, then this trait is not needed. Use the [`impl_has_list_links!`] macro to implement 13 11 /// this trait. 14 12 /// 15 13 /// # Safety 16 14 /// 17 - /// All values of this type must have a `ListLinks<ID>` field at the given offset. 15 + /// The methods on this trait must have exactly the behavior that the definitions given below have. 18 16 /// 19 - /// The behavior of `raw_get_list_links` must not be changed. 17 + /// [`ListLinks<ID>`]: crate::list::ListLinks 18 + /// [`ListItem`]: crate::list::ListItem 20 19 pub unsafe trait HasListLinks<const ID: u64 = 0> { 21 - /// The offset of the `ListLinks` field. 22 - const OFFSET: usize; 23 - 24 - /// Returns a pointer to the [`ListLinks<T, ID>`] field. 20 + /// Returns a pointer to the [`ListLinks<ID>`] field. 25 21 /// 26 22 /// # Safety 27 23 /// 28 24 /// The provided pointer must point at a valid struct of type `Self`. 29 25 /// 30 - /// [`ListLinks<T, ID>`]: ListLinks 31 - // We don't really need this method, but it's necessary for the implementation of 32 - // `impl_has_list_links!` to be correct. 33 - #[inline] 34 - unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut ListLinks<ID> { 35 - // SAFETY: The caller promises that the pointer is valid. The implementer promises that the 36 - // `OFFSET` constant is correct. 37 - unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut ListLinks<ID> } 38 - } 26 + /// [`ListLinks<ID>`]: crate::list::ListLinks 27 + unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut crate::list::ListLinks<ID>; 39 28 } 40 29 41 30 /// Implements the [`HasListLinks`] trait for the given type. 42 31 #[macro_export] 43 32 macro_rules! impl_has_list_links { 44 - ($(impl$(<$($implarg:ident),*>)? 33 + ($(impl$({$($generics:tt)*})? 45 34 HasListLinks$(<$id:tt>)? 46 - for $self:ident $(<$($selfarg:ty),*>)? 35 + for $self:ty 47 36 { self$(.$field:ident)* } 48 37 )*) => {$( 49 38 // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the 50 39 // right type. 51 - // 52 - // The behavior of `raw_get_list_links` is not changed since the `addr_of_mut!` macro is 53 - // equivalent to the pointer offset operation in the trait definition. 54 - unsafe impl$(<$($implarg),*>)? $crate::list::HasListLinks$(<$id>)? for 55 - $self $(<$($selfarg),*>)? 56 - { 57 - const OFFSET: usize = ::core::mem::offset_of!(Self, $($field).*) as usize; 58 - 40 + unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self { 59 41 #[inline] 60 42 unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? { 43 + // Statically ensure that `$(.field)*` doesn't follow any pointers. 44 + // 45 + // Cannot be `const` because `$self` may contain generics and E0401 says constants 46 + // "can't use {`Self`,generic parameters} from outer item". 47 + if false { let _: usize = ::core::mem::offset_of!(Self, $($field).*); } 48 + 61 49 // SAFETY: The caller promises that the pointer is not dangling. We know that this 62 50 // expression doesn't follow any pointers, as the `offset_of!` invocation above 63 51 // would otherwise not compile. ··· 56 68 } 57 69 pub use impl_has_list_links; 58 70 59 - /// Declares that the `ListLinks<ID>` field in this struct is inside a `ListLinksSelfPtr<T, ID>`. 71 + /// Declares that the [`ListLinks<ID>`] field in this struct is inside a 72 + /// [`ListLinksSelfPtr<T, ID>`]. 60 73 /// 61 74 /// # Safety 62 75 /// 63 - /// The `ListLinks<ID>` field of this struct at the offset `HasListLinks<ID>::OFFSET` must be 64 - /// inside a `ListLinksSelfPtr<T, ID>`. 76 + /// The [`ListLinks<ID>`] field of this struct at [`HasListLinks<ID>::raw_get_list_links`] must be 77 + /// inside a [`ListLinksSelfPtr<T, ID>`]. 78 + /// 79 + /// [`ListLinks<ID>`]: crate::list::ListLinks 80 + /// [`ListLinksSelfPtr<T, ID>`]: crate::list::ListLinksSelfPtr 65 81 pub unsafe trait HasSelfPtr<T: ?Sized, const ID: u64 = 0> 66 82 where 67 83 Self: HasListLinks<ID>, ··· 75 83 /// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type. 76 84 #[macro_export] 77 85 macro_rules! impl_has_list_links_self_ptr { 78 - ($(impl$({$($implarg:tt)*})? 86 + ($(impl$({$($generics:tt)*})? 79 87 HasSelfPtr<$item_type:ty $(, $id:tt)?> 80 - for $self:ident $(<$($selfarg:ty),*>)? 81 - { self.$field:ident } 88 + for $self:ty 89 + { self$(.$field:ident)* } 82 90 )*) => {$( 83 91 // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the 84 92 // right type. 85 - unsafe impl$(<$($implarg)*>)? $crate::list::HasSelfPtr<$item_type $(, $id)?> for 86 - $self $(<$($selfarg),*>)? 87 - {} 93 + unsafe impl$(<$($generics)*>)? $crate::list::HasSelfPtr<$item_type $(, $id)?> for $self {} 88 94 89 - unsafe impl$(<$($implarg)*>)? $crate::list::HasListLinks$(<$id>)? for 90 - $self $(<$($selfarg),*>)? 91 - { 92 - const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize; 93 - 95 + unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self { 94 96 #[inline] 95 97 unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? { 96 98 // SAFETY: The caller promises that the pointer is not dangling. 97 99 let ptr: *mut $crate::list::ListLinksSelfPtr<$item_type $(, $id)?> = 98 - unsafe { ::core::ptr::addr_of_mut!((*ptr).$field) }; 100 + unsafe { ::core::ptr::addr_of_mut!((*ptr)$(.$field)*) }; 99 101 ptr.cast() 100 102 } 101 103 } ··· 103 117 /// implement that trait. 104 118 /// 105 119 /// [`ListItem`]: crate::list::ListItem 120 + /// 121 + /// # Examples 122 + /// 123 + /// ``` 124 + /// #[pin_data] 125 + /// struct SimpleListItem { 126 + /// value: u32, 127 + /// #[pin] 128 + /// links: kernel::list::ListLinks, 129 + /// } 130 + /// 131 + /// kernel::list::impl_list_arc_safe! { 132 + /// impl ListArcSafe<0> for SimpleListItem { untracked; } 133 + /// } 134 + /// 135 + /// kernel::list::impl_list_item! { 136 + /// impl ListItem<0> for SimpleListItem { using ListLinks { self.links }; } 137 + /// } 138 + /// 139 + /// struct ListLinksHolder { 140 + /// inner: kernel::list::ListLinks, 141 + /// } 142 + /// 143 + /// #[pin_data] 144 + /// struct ComplexListItem<T, U> { 145 + /// value: Result<T, U>, 146 + /// #[pin] 147 + /// links: ListLinksHolder, 148 + /// } 149 + /// 150 + /// kernel::list::impl_list_arc_safe! { 151 + /// impl{T, U} ListArcSafe<0> for ComplexListItem<T, U> { untracked; } 152 + /// } 153 + /// 154 + /// kernel::list::impl_list_item! { 155 + /// impl{T, U} ListItem<0> for ComplexListItem<T, U> { using ListLinks { self.links.inner }; } 156 + /// } 157 + /// ``` 158 + /// 159 + /// ``` 160 + /// #[pin_data] 161 + /// struct SimpleListItem { 162 + /// value: u32, 163 + /// #[pin] 164 + /// links: kernel::list::ListLinksSelfPtr<SimpleListItem>, 165 + /// } 166 + /// 167 + /// kernel::list::impl_list_arc_safe! { 168 + /// impl ListArcSafe<0> for SimpleListItem { untracked; } 169 + /// } 170 + /// 171 + /// kernel::list::impl_list_item! { 172 + /// impl ListItem<0> for SimpleListItem { using ListLinksSelfPtr { self.links }; } 173 + /// } 174 + /// 175 + /// struct ListLinksSelfPtrHolder<T, U> { 176 + /// inner: kernel::list::ListLinksSelfPtr<ComplexListItem<T, U>>, 177 + /// } 178 + /// 179 + /// #[pin_data] 180 + /// struct ComplexListItem<T, U> { 181 + /// value: Result<T, U>, 182 + /// #[pin] 183 + /// links: ListLinksSelfPtrHolder<T, U>, 184 + /// } 185 + /// 186 + /// kernel::list::impl_list_arc_safe! { 187 + /// impl{T, U} ListArcSafe<0> for ComplexListItem<T, U> { untracked; } 188 + /// } 189 + /// 190 + /// kernel::list::impl_list_item! { 191 + /// impl{T, U} ListItem<0> for ComplexListItem<T, U> { 192 + /// using ListLinksSelfPtr { self.links.inner }; 193 + /// } 194 + /// } 195 + /// ``` 106 196 #[macro_export] 107 197 macro_rules! impl_list_item { 108 198 ( 109 - $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $t:ty { 110 - using ListLinks; 199 + $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty { 200 + using ListLinks { self$(.$field:ident)* }; 111 201 })* 112 202 ) => {$( 203 + $crate::list::impl_has_list_links! { 204 + impl$({$($generics)*})? HasListLinks<$num> for $self { self$(.$field)* } 205 + } 206 + 113 207 // SAFETY: See GUARANTEES comment on each method. 114 - unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $t { 208 + unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $self { 115 209 // GUARANTEES: 116 210 // * This returns the same pointer as `prepare_to_insert` because `prepare_to_insert` 117 211 // is implemented in terms of `view_links`. ··· 205 139 } 206 140 207 141 // GUARANTEES: 208 - // * `me` originates from the most recent call to `prepare_to_insert`, which just added 209 - // `offset` to the pointer passed to `prepare_to_insert`. This method subtracts 210 - // `offset` from `me` so it returns the pointer originally passed to 211 - // `prepare_to_insert`. 142 + // * `me` originates from the most recent call to `prepare_to_insert`, which calls 143 + // `raw_get_list_link`, which is implemented using `addr_of_mut!((*self)$(.$field)*)`. 144 + // This method uses `container_of` to perform the inverse operation, so it returns the 145 + // pointer originally passed to `prepare_to_insert`. 212 146 // * The pointer remains valid until the next call to `post_remove` because the caller 213 147 // of the most recent call to `prepare_to_insert` promised to retain ownership of the 214 148 // `ListArc` containing `Self` until the next call to `post_remove`. The value cannot 215 149 // be destroyed while a `ListArc` reference exists. 216 150 unsafe fn view_value(me: *mut $crate::list::ListLinks<$num>) -> *const Self { 217 - let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET; 218 151 // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it 219 - // points at the field at offset `offset` in a value of type `Self`. Thus, 220 - // subtracting `offset` from `me` is still in-bounds of the allocation. 221 - unsafe { (me as *const u8).sub(offset) as *const Self } 152 + // points at the field `$field` in a value of type `Self`. Thus, reversing that 153 + // operation is still in-bounds of the allocation. 154 + $crate::container_of!(me, Self, $($field).*) 222 155 } 223 156 224 157 // GUARANTEES: ··· 234 169 } 235 170 236 171 // GUARANTEES: 237 - // * `me` originates from the most recent call to `prepare_to_insert`, which just added 238 - // `offset` to the pointer passed to `prepare_to_insert`. This method subtracts 239 - // `offset` from `me` so it returns the pointer originally passed to 240 - // `prepare_to_insert`. 172 + // * `me` originates from the most recent call to `prepare_to_insert`, which calls 173 + // `raw_get_list_link`, which is implemented using `addr_of_mut!((*self)$(.$field)*)`. 174 + // This method uses `container_of` to perform the inverse operation, so it returns the 175 + // pointer originally passed to `prepare_to_insert`. 241 176 unsafe fn post_remove(me: *mut $crate::list::ListLinks<$num>) -> *const Self { 242 - let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET; 243 177 // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it 244 - // points at the field at offset `offset` in a value of type `Self`. Thus, 245 - // subtracting `offset` from `me` is still in-bounds of the allocation. 246 - unsafe { (me as *const u8).sub(offset) as *const Self } 178 + // points at the field `$field` in a value of type `Self`. Thus, reversing that 179 + // operation is still in-bounds of the allocation. 180 + $crate::container_of!(me, Self, $($field).*) 247 181 } 248 182 } 249 183 )*}; 250 184 251 185 ( 252 - $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $t:ty { 253 - using ListLinksSelfPtr; 186 + $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty { 187 + using ListLinksSelfPtr { self$(.$field:ident)* }; 254 188 })* 255 189 ) => {$( 190 + $crate::list::impl_has_list_links_self_ptr! { 191 + impl$({$($generics)*})? HasSelfPtr<$self> for $self { self$(.$field)* } 192 + } 193 + 256 194 // SAFETY: See GUARANTEES comment on each method. 257 - unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $t { 195 + unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $self { 258 196 // GUARANTEES: 259 197 // This implementation of `ListItem` will not give out exclusive access to the same 260 198 // `ListLinks` several times because calls to `prepare_to_insert` and `post_remove` ··· 270 202 // SAFETY: The caller promises that `me` points at a valid value of type `Self`. 271 203 let links_field = unsafe { <Self as $crate::list::ListItem<$num>>::view_links(me) }; 272 204 273 - let spoff = $crate::list::ListLinksSelfPtr::<Self, $num>::LIST_LINKS_SELF_PTR_OFFSET; 274 - // Goes via the offset as the field is private. 275 - // 276 - // SAFETY: The constant is equal to `offset_of!(ListLinksSelfPtr, self_ptr)`, so 277 - // the pointer stays in bounds of the allocation. 278 - let self_ptr = unsafe { (links_field as *const u8).add(spoff) } 279 - as *const $crate::types::Opaque<*const Self>; 280 - let cell_inner = $crate::types::Opaque::raw_get(self_ptr); 205 + let container = $crate::container_of!( 206 + links_field, $crate::list::ListLinksSelfPtr<Self, $num>, inner 207 + ); 208 + 209 + // SAFETY: By the same reasoning above, `links_field` is a valid pointer. 210 + let self_ptr = unsafe { 211 + $crate::list::ListLinksSelfPtr::raw_get_self_ptr(container) 212 + }; 213 + 214 + let cell_inner = $crate::types::Opaque::cast_into(self_ptr); 281 215 282 216 // SAFETY: This value is not accessed in any other places than `prepare_to_insert`, 283 217 // `post_remove`, or `view_value`. By the safety requirements of those methods, ··· 298 228 // this value is not in a list. 299 229 unsafe fn view_links(me: *const Self) -> *mut $crate::list::ListLinks<$num> { 300 230 // SAFETY: The caller promises that `me` points at a valid value of type `Self`. 301 - unsafe { <Self as HasListLinks<$num>>::raw_get_list_links(me.cast_mut()) } 231 + unsafe { 232 + <Self as $crate::list::HasListLinks<$num>>::raw_get_list_links(me.cast_mut()) 233 + } 302 234 } 303 235 304 236 // This function is also used as the implementation of `post_remove`, so the caller ··· 319 247 // `ListArc` containing `Self` until the next call to `post_remove`. The value cannot 320 248 // be destroyed while a `ListArc` reference exists. 321 249 unsafe fn view_value(links_field: *mut $crate::list::ListLinks<$num>) -> *const Self { 322 - let spoff = $crate::list::ListLinksSelfPtr::<Self, $num>::LIST_LINKS_SELF_PTR_OFFSET; 323 - // SAFETY: The constant is equal to `offset_of!(ListLinksSelfPtr, self_ptr)`, so 324 - // the pointer stays in bounds of the allocation. 325 - let self_ptr = unsafe { (links_field as *const u8).add(spoff) } 326 - as *const ::core::cell::UnsafeCell<*const Self>; 327 - let cell_inner = ::core::cell::UnsafeCell::raw_get(self_ptr); 250 + let container = $crate::container_of!( 251 + links_field, $crate::list::ListLinksSelfPtr<Self, $num>, inner 252 + ); 253 + 254 + // SAFETY: By the same reasoning above, `links_field` is a valid pointer. 255 + let self_ptr = unsafe { 256 + $crate::list::ListLinksSelfPtr::raw_get_self_ptr(container) 257 + }; 258 + 259 + let cell_inner = $crate::types::Opaque::cast_into(self_ptr); 260 + 328 261 // SAFETY: This is not a data race, because the only function that writes to this 329 262 // value is `prepare_to_insert`, but by the safety requirements the 330 263 // `prepare_to_insert` method may not be called in parallel with `view_value` or
+6 -6
rust/kernel/miscdevice.rs
··· 33 33 pub const fn into_raw<T: MiscDevice>(self) -> bindings::miscdevice { 34 34 // SAFETY: All zeros is valid for this C type. 35 35 let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() }; 36 - result.minor = bindings::MISC_DYNAMIC_MINOR as _; 36 + result.minor = bindings::MISC_DYNAMIC_MINOR as ffi::c_int; 37 37 result.name = self.name.as_char_ptr(); 38 38 result.fops = MiscdeviceVTable::<T>::build(); 39 39 result ··· 222 222 // type. 223 223 // 224 224 // SAFETY: The open call of a file can access the private data. 225 - unsafe { (*raw_file).private_data = ptr.into_foreign().cast() }; 225 + unsafe { (*raw_file).private_data = ptr.into_foreign() }; 226 226 227 227 0 228 228 } ··· 233 233 /// must be associated with a `MiscDeviceRegistration<T>`. 234 234 unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int { 235 235 // SAFETY: The release call of a file owns the private data. 236 - let private = unsafe { (*file).private_data }.cast(); 236 + let private = unsafe { (*file).private_data }; 237 237 // SAFETY: The release call of a file owns the private data. 238 238 let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; 239 239 ··· 277 277 /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. 278 278 unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long { 279 279 // SAFETY: The ioctl call of a file can access the private data. 280 - let private = unsafe { (*file).private_data }.cast(); 280 + let private = unsafe { (*file).private_data }; 281 281 // SAFETY: Ioctl calls can borrow the private data of the file. 282 282 let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; 283 283 ··· 302 302 arg: c_ulong, 303 303 ) -> c_long { 304 304 // SAFETY: The compat ioctl call of a file can access the private data. 305 - let private = unsafe { (*file).private_data }.cast(); 305 + let private = unsafe { (*file).private_data }; 306 306 // SAFETY: Ioctl calls can borrow the private data of the file. 307 307 let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; 308 308 ··· 323 323 /// - `seq_file` must be a valid `struct seq_file` that we can write to. 324 324 unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) { 325 325 // SAFETY: The release call of a file owns the private data. 326 - let private = unsafe { (*file).private_data }.cast(); 326 + let private = unsafe { (*file).private_data }; 327 327 // SAFETY: Ioctl calls can borrow the private data of the file. 328 328 let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; 329 329 // SAFETY:
+26 -26
rust/kernel/mm/virt.rs
··· 392 392 use crate::bindings; 393 393 394 394 /// No flags are set. 395 - pub const NONE: vm_flags_t = bindings::VM_NONE as _; 395 + pub const NONE: vm_flags_t = bindings::VM_NONE as vm_flags_t; 396 396 397 397 /// Mapping allows reads. 398 - pub const READ: vm_flags_t = bindings::VM_READ as _; 398 + pub const READ: vm_flags_t = bindings::VM_READ as vm_flags_t; 399 399 400 400 /// Mapping allows writes. 401 - pub const WRITE: vm_flags_t = bindings::VM_WRITE as _; 401 + pub const WRITE: vm_flags_t = bindings::VM_WRITE as vm_flags_t; 402 402 403 403 /// Mapping allows execution. 404 - pub const EXEC: vm_flags_t = bindings::VM_EXEC as _; 404 + pub const EXEC: vm_flags_t = bindings::VM_EXEC as vm_flags_t; 405 405 406 406 /// Mapping is shared. 407 - pub const SHARED: vm_flags_t = bindings::VM_SHARED as _; 407 + pub const SHARED: vm_flags_t = bindings::VM_SHARED as vm_flags_t; 408 408 409 409 /// Mapping may be updated to allow reads. 410 - pub const MAYREAD: vm_flags_t = bindings::VM_MAYREAD as _; 410 + pub const MAYREAD: vm_flags_t = bindings::VM_MAYREAD as vm_flags_t; 411 411 412 412 /// Mapping may be updated to allow writes. 413 - pub const MAYWRITE: vm_flags_t = bindings::VM_MAYWRITE as _; 413 + pub const MAYWRITE: vm_flags_t = bindings::VM_MAYWRITE as vm_flags_t; 414 414 415 415 /// Mapping may be updated to allow execution. 416 - pub const MAYEXEC: vm_flags_t = bindings::VM_MAYEXEC as _; 416 + pub const MAYEXEC: vm_flags_t = bindings::VM_MAYEXEC as vm_flags_t; 417 417 418 418 /// Mapping may be updated to be shared. 419 - pub const MAYSHARE: vm_flags_t = bindings::VM_MAYSHARE as _; 419 + pub const MAYSHARE: vm_flags_t = bindings::VM_MAYSHARE as vm_flags_t; 420 420 421 421 /// Page-ranges managed without `struct page`, just pure PFN. 422 - pub const PFNMAP: vm_flags_t = bindings::VM_PFNMAP as _; 422 + pub const PFNMAP: vm_flags_t = bindings::VM_PFNMAP as vm_flags_t; 423 423 424 424 /// Memory mapped I/O or similar. 425 - pub const IO: vm_flags_t = bindings::VM_IO as _; 425 + pub const IO: vm_flags_t = bindings::VM_IO as vm_flags_t; 426 426 427 427 /// Do not copy this vma on fork. 428 - pub const DONTCOPY: vm_flags_t = bindings::VM_DONTCOPY as _; 428 + pub const DONTCOPY: vm_flags_t = bindings::VM_DONTCOPY as vm_flags_t; 429 429 430 430 /// Cannot expand with mremap(). 431 - pub const DONTEXPAND: vm_flags_t = bindings::VM_DONTEXPAND as _; 431 + pub const DONTEXPAND: vm_flags_t = bindings::VM_DONTEXPAND as vm_flags_t; 432 432 433 433 /// Lock the pages covered when they are faulted in. 434 - pub const LOCKONFAULT: vm_flags_t = bindings::VM_LOCKONFAULT as _; 434 + pub const LOCKONFAULT: vm_flags_t = bindings::VM_LOCKONFAULT as vm_flags_t; 435 435 436 436 /// Is a VM accounted object. 437 - pub const ACCOUNT: vm_flags_t = bindings::VM_ACCOUNT as _; 437 + pub const ACCOUNT: vm_flags_t = bindings::VM_ACCOUNT as vm_flags_t; 438 438 439 439 /// Should the VM suppress accounting. 440 - pub const NORESERVE: vm_flags_t = bindings::VM_NORESERVE as _; 440 + pub const NORESERVE: vm_flags_t = bindings::VM_NORESERVE as vm_flags_t; 441 441 442 442 /// Huge TLB Page VM. 443 - pub const HUGETLB: vm_flags_t = bindings::VM_HUGETLB as _; 443 + pub const HUGETLB: vm_flags_t = bindings::VM_HUGETLB as vm_flags_t; 444 444 445 445 /// Synchronous page faults. (DAX-specific) 446 - pub const SYNC: vm_flags_t = bindings::VM_SYNC as _; 446 + pub const SYNC: vm_flags_t = bindings::VM_SYNC as vm_flags_t; 447 447 448 448 /// Architecture-specific flag. 449 - pub const ARCH_1: vm_flags_t = bindings::VM_ARCH_1 as _; 449 + pub const ARCH_1: vm_flags_t = bindings::VM_ARCH_1 as vm_flags_t; 450 450 451 451 /// Wipe VMA contents in child on fork. 452 - pub const WIPEONFORK: vm_flags_t = bindings::VM_WIPEONFORK as _; 452 + pub const WIPEONFORK: vm_flags_t = bindings::VM_WIPEONFORK as vm_flags_t; 453 453 454 454 /// Do not include in the core dump. 455 - pub const DONTDUMP: vm_flags_t = bindings::VM_DONTDUMP as _; 455 + pub const DONTDUMP: vm_flags_t = bindings::VM_DONTDUMP as vm_flags_t; 456 456 457 457 /// Not soft dirty clean area. 458 - pub const SOFTDIRTY: vm_flags_t = bindings::VM_SOFTDIRTY as _; 458 + pub const SOFTDIRTY: vm_flags_t = bindings::VM_SOFTDIRTY as vm_flags_t; 459 459 460 460 /// Can contain `struct page` and pure PFN pages. 461 - pub const MIXEDMAP: vm_flags_t = bindings::VM_MIXEDMAP as _; 461 + pub const MIXEDMAP: vm_flags_t = bindings::VM_MIXEDMAP as vm_flags_t; 462 462 463 463 /// MADV_HUGEPAGE marked this vma. 464 - pub const HUGEPAGE: vm_flags_t = bindings::VM_HUGEPAGE as _; 464 + pub const HUGEPAGE: vm_flags_t = bindings::VM_HUGEPAGE as vm_flags_t; 465 465 466 466 /// MADV_NOHUGEPAGE marked this vma. 467 - pub const NOHUGEPAGE: vm_flags_t = bindings::VM_NOHUGEPAGE as _; 467 + pub const NOHUGEPAGE: vm_flags_t = bindings::VM_NOHUGEPAGE as vm_flags_t; 468 468 469 469 /// KSM may merge identical pages. 470 - pub const MERGEABLE: vm_flags_t = bindings::VM_MERGEABLE as _; 470 + pub const MERGEABLE: vm_flags_t = bindings::VM_MERGEABLE as vm_flags_t; 471 471 }
+2 -2
rust/kernel/net/phy.rs
··· 142 142 // SAFETY: The struct invariant ensures that we may access 143 143 // this field without additional synchronization. 144 144 let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; 145 - bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64 145 + bit_field.get(13, 1) == u64::from(bindings::AUTONEG_ENABLE) 146 146 } 147 147 148 148 /// Gets the current auto-negotiation state. ··· 419 419 // where we hold `phy_device->lock`, so the accessors on 420 420 // `Device` are okay to call. 421 421 let dev = unsafe { Device::from_raw(phydev) }; 422 - T::match_phy_device(dev) as i32 422 + T::match_phy_device(dev).into() 423 423 } 424 424 425 425 /// # Safety
+3 -3
rust/kernel/of.rs
··· 27 27 const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data); 28 28 29 29 fn index(&self) -> usize { 30 - self.0.data as _ 30 + self.0.data as usize 31 31 } 32 32 } 33 33 ··· 39 39 // SAFETY: FFI type is valid to be zero-initialized. 40 40 let mut of: bindings::of_device_id = unsafe { core::mem::zeroed() }; 41 41 42 - // TODO: Use `clone_from_slice` once the corresponding types do match. 42 + // TODO: Use `copy_from_slice` once stabilized for `const`. 43 43 let mut i = 0; 44 44 while i < src.len() { 45 - of.compatible[i] = src[i] as _; 45 + of.compatible[i] = src[i]; 46 46 i += 1; 47 47 } 48 48
+10 -10
rust/kernel/opp.rs
··· 92 92 let mut list = KVec::with_capacity(names.len() + 1, GFP_KERNEL)?; 93 93 94 94 for name in names.iter() { 95 - list.push(name.as_ptr() as _, GFP_KERNEL)?; 95 + list.push(name.as_ptr().cast(), GFP_KERNEL)?; 96 96 } 97 97 98 98 list.push(ptr::null(), GFP_KERNEL)?; ··· 103 103 /// 104 104 /// Represents voltage in microvolts, wrapping a [`c_ulong`] value. 105 105 /// 106 - /// ## Examples 106 + /// # Examples 107 107 /// 108 108 /// ``` 109 109 /// use kernel::opp::MicroVolt; ··· 128 128 /// 129 129 /// Represents power in microwatts, wrapping a [`c_ulong`] value. 130 130 /// 131 - /// ## Examples 131 + /// # Examples 132 132 /// 133 133 /// ``` 134 134 /// use kernel::opp::MicroWatt; ··· 153 153 /// 154 154 /// The associated [`OPP`] is automatically removed when the [`Token`] is dropped. 155 155 /// 156 - /// ## Examples 156 + /// # Examples 157 157 /// 158 158 /// The following example demonstrates how to create an [`OPP`] dynamically. 159 159 /// ··· 202 202 /// Rust abstraction for the C `struct dev_pm_opp_data`, used to define operating performance 203 203 /// points (OPPs) dynamically. 204 204 /// 205 - /// ## Examples 205 + /// # Examples 206 206 /// 207 207 /// The following example demonstrates how to create an [`OPP`] with [`Data`]. 208 208 /// ··· 254 254 255 255 /// [`OPP`] search options. 256 256 /// 257 - /// ## Examples 257 + /// # Examples 258 258 /// 259 259 /// Defines how to search for an [`OPP`] in a [`Table`] relative to a frequency. 260 260 /// ··· 326 326 /// 327 327 /// Rust abstraction for the C `struct dev_pm_opp_config`. 328 328 /// 329 - /// ## Examples 329 + /// # Examples 330 330 /// 331 331 /// The following example demonstrates how to set OPP property-name configuration for a [`Device`]. 332 332 /// ··· 345 345 /// impl ConfigOps for Driver {} 346 346 /// 347 347 /// fn configure(dev: &ARef<Device>) -> Result<ConfigToken> { 348 - /// let name = CString::try_from_fmt(fmt!("{}", "slow"))?; 348 + /// let name = CString::try_from_fmt(fmt!("slow"))?; 349 349 /// 350 350 /// // The OPP configuration is cleared once the [`ConfigToken`] goes out of scope. 351 351 /// Config::<Driver>::new() ··· 569 569 /// 570 570 /// Instances of this type are reference-counted. 571 571 /// 572 - /// ## Examples 572 + /// # Examples 573 573 /// 574 574 /// The following example demonstrates how to get OPP [`Table`] for a [`Cpumask`] and set its 575 575 /// frequency. ··· 1011 1011 /// 1012 1012 /// A reference to the [`OPP`], &[`OPP`], isn't refcounted by the Rust code. 1013 1013 /// 1014 - /// ## Examples 1014 + /// # Examples 1015 1015 /// 1016 1016 /// The following example demonstrates how to get [`OPP`] corresponding to a frequency value and 1017 1017 /// configure the device with it.
+8 -5
rust/kernel/pci.rs
··· 98 98 99 99 /// Declares a kernel module that exposes a single PCI driver. 100 100 /// 101 - /// # Example 101 + /// # Examples 102 102 /// 103 103 ///```ignore 104 104 /// kernel::module_pci_driver! { ··· 170 170 const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data); 171 171 172 172 fn index(&self) -> usize { 173 - self.0.driver_data as _ 173 + self.0.driver_data 174 174 } 175 175 } 176 176 ··· 193 193 194 194 /// The PCI driver trait. 195 195 /// 196 - /// # Example 196 + /// # Examples 197 197 /// 198 198 ///``` 199 199 /// # use kernel::{bindings, device::Core, pci}; ··· 205 205 /// MODULE_PCI_TABLE, 206 206 /// <MyDriver as pci::Driver>::IdInfo, 207 207 /// [ 208 - /// (pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as _), ()) 208 + /// ( 209 + /// pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as u32), 210 + /// (), 211 + /// ) 209 212 /// ] 210 213 /// ); 211 214 /// ··· 347 344 // `ioptr` is valid by the safety requirements. 348 345 // `num` is valid by the safety requirements. 349 346 unsafe { 350 - bindings::pci_iounmap(pdev.as_raw(), ioptr as _); 347 + bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut kernel::ffi::c_void); 351 348 bindings::pci_release_region(pdev.as_raw(), num); 352 349 } 353 350 }
+1 -1
rust/kernel/platform.rs
··· 132 132 /// 133 133 /// Drivers must implement this trait in order to get a platform driver registered. 134 134 /// 135 - /// # Example 135 + /// # Examples 136 136 /// 137 137 ///``` 138 138 /// # use kernel::{acpi, bindings, c_str, device::Core, of, platform};
+3 -1
rust/kernel/prelude.rs
··· 31 31 // `super::std_vendor` is hidden, which makes the macro inline for some reason. 32 32 #[doc(no_inline)] 33 33 pub use super::dbg; 34 - pub use super::fmt; 35 34 pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn}; 36 35 pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; 36 + pub use core::format_args as fmt; 37 37 38 38 pub use super::{try_init, try_pin_init}; 39 39 ··· 46 46 pub use super::init::InPlaceInit; 47 47 48 48 pub use super::current; 49 + 50 + pub use super::uaccess::UserPtr;
+6 -6
rust/kernel/print.rs
··· 8 8 9 9 use crate::{ 10 10 ffi::{c_char, c_void}, 11 + fmt, 11 12 prelude::*, 12 13 str::RawFormatter, 13 14 }; 14 - use core::fmt; 15 15 16 16 // Called from `vsprintf` with format specifier `%pA`. 17 17 #[expect(clippy::missing_safety_doc)] ··· 25 25 // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`. 26 26 let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) }; 27 27 // SAFETY: TODO. 28 - let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) }); 28 + let _ = w.write_fmt(unsafe { *ptr.cast::<fmt::Arguments<'_>>() }); 29 29 w.pos().cast() 30 30 } 31 31 ··· 109 109 bindings::_printk( 110 110 format_string.as_ptr(), 111 111 module_name.as_ptr(), 112 - &args as *const _ as *const c_void, 112 + core::ptr::from_ref(&args).cast::<c_void>(), 113 113 ); 114 114 } 115 115 } ··· 129 129 unsafe { 130 130 bindings::_printk( 131 131 format_strings::CONT.as_ptr(), 132 - &args as *const _ as *const c_void, 132 + core::ptr::from_ref(&args).cast::<c_void>(), 133 133 ); 134 134 } 135 135 } ··· 149 149 // takes borrows on the arguments, but does not extend the scope of temporaries. 150 150 // Therefore, a `match` expression is used to keep them around, since 151 151 // the scrutinee is kept until the end of the `match`. 152 - match format_args!($($arg)+) { 152 + match $crate::prelude::fmt!($($arg)+) { 153 153 // SAFETY: This hidden macro should only be called by the documented 154 154 // printing macros which ensure the format string is one of the fixed 155 155 // ones. All `__LOG_PREFIX`s are null-terminated as they are generated ··· 168 168 // The `CONT` case. 169 169 ($format_string:path, true, $($arg:tt)+) => ( 170 170 $crate::print::call_printk_cont( 171 - format_args!($($arg)+), 171 + $crate::prelude::fmt!($($arg)+), 172 172 ); 173 173 ); 174 174 );
+13 -16
rust/kernel/rbtree.rs
··· 191 191 } 192 192 } 193 193 194 + /// Returns true if this tree is empty. 195 + #[inline] 196 + pub fn is_empty(&self) -> bool { 197 + self.root.rb_node.is_null() 198 + } 199 + 194 200 /// Returns an iterator over the tree nodes, sorted by key. 195 201 pub fn iter(&self) -> Iter<'_, K, V> { 196 202 Iter { ··· 775 769 // the tree cannot change. By the tree invariant, all nodes are valid. 776 770 unsafe { bindings::rb_erase(&mut (*this).links, addr_of_mut!(self.tree.root)) }; 777 771 778 - let current = match (prev, next) { 779 - (_, Some(next)) => next, 780 - (Some(prev), None) => prev, 781 - (None, None) => { 782 - return (None, node); 783 - } 784 - }; 772 + // INVARIANT: 773 + // - `current` is a valid node in the [`RBTree`] pointed to by `self.tree`. 774 + let cursor = next.or(prev).map(|current| Self { 775 + current, 776 + tree: self.tree, 777 + }); 785 778 786 - ( 787 - // INVARIANT: 788 - // - `current` is a valid node in the [`RBTree`] pointed to by `self.tree`. 789 - Some(Self { 790 - current, 791 - tree: self.tree, 792 - }), 793 - node, 794 - ) 779 + (cursor, node) 795 780 } 796 781 797 782 /// Remove the previous node, returning it if it exists.
+4
rust/kernel/revocable.rs
··· 233 233 /// 234 234 /// The RCU read-side lock is held while the guard is alive. 235 235 pub struct RevocableGuard<'a, T> { 236 + // This can't use the `&'a T` type because references that appear in function arguments must 237 + // not become dangling during the execution of the function, which can happen if the 238 + // `RevocableGuard` is passed as a function argument and then dropped during execution of the 239 + // function. 236 240 data_ref: *const T, 237 241 _rcu_guard: rcu::Guard, 238 242 _p: PhantomData<&'a ()>,
+1 -1
rust/kernel/seq_file.rs
··· 37 37 bindings::seq_printf( 38 38 self.inner.get(), 39 39 c_str!("%pA").as_char_ptr(), 40 - &args as *const _ as *const crate::ffi::c_void, 40 + core::ptr::from_ref(&args).cast::<crate::ffi::c_void>(), 41 41 ); 42 42 } 43 43 }
+68 -43
rust/kernel/str.rs
··· 3 3 //! String representations. 4 4 5 5 use crate::alloc::{flags::*, AllocError, KVec}; 6 - use core::fmt::{self, Write}; 6 + use crate::fmt::{self, Write}; 7 7 use core::ops::{self, Deref, DerefMut, Index}; 8 8 9 9 use crate::prelude::*; ··· 29 29 #[inline] 30 30 pub const fn from_bytes(bytes: &[u8]) -> &Self { 31 31 // SAFETY: `BStr` is transparent to `[u8]`. 32 - unsafe { &*(bytes as *const [u8] as *const BStr) } 32 + unsafe { &*(core::ptr::from_ref(bytes) as *const BStr) } 33 33 } 34 34 35 35 /// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`]. ··· 54 54 /// Formats printable ASCII characters, escaping the rest. 55 55 /// 56 56 /// ``` 57 - /// # use kernel::{fmt, b_str, str::{BStr, CString}}; 57 + /// # use kernel::{prelude::fmt, b_str, str::{BStr, CString}}; 58 58 /// let ascii = b_str!("Hello, BStr!"); 59 - /// let s = CString::try_from_fmt(fmt!("{}", ascii))?; 60 - /// assert_eq!(s.as_bytes(), "Hello, BStr!".as_bytes()); 59 + /// let s = CString::try_from_fmt(fmt!("{ascii}"))?; 60 + /// assert_eq!(s.to_bytes(), "Hello, BStr!".as_bytes()); 61 61 /// 62 62 /// let non_ascii = b_str!("🦀"); 63 - /// let s = CString::try_from_fmt(fmt!("{}", non_ascii))?; 64 - /// assert_eq!(s.as_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes()); 63 + /// let s = CString::try_from_fmt(fmt!("{non_ascii}"))?; 64 + /// assert_eq!(s.to_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes()); 65 65 /// # Ok::<(), kernel::error::Error>(()) 66 66 /// ``` 67 67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ··· 85 85 /// escaping the rest. 86 86 /// 87 87 /// ``` 88 - /// # use kernel::{fmt, b_str, str::{BStr, CString}}; 88 + /// # use kernel::{prelude::fmt, b_str, str::{BStr, CString}}; 89 89 /// // Embedded double quotes are escaped. 90 90 /// let ascii = b_str!("Hello, \"BStr\"!"); 91 - /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?; 92 - /// assert_eq!(s.as_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes()); 91 + /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?; 92 + /// assert_eq!(s.to_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes()); 93 93 /// 94 94 /// let non_ascii = b_str!("😺"); 95 - /// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii))?; 96 - /// assert_eq!(s.as_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes()); 95 + /// let s = CString::try_from_fmt(fmt!("{non_ascii:?}"))?; 96 + /// assert_eq!(s.to_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes()); 97 97 /// # Ok::<(), kernel::error::Error>(()) 98 98 /// ``` 99 99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ··· 175 175 }}; 176 176 } 177 177 178 + /// Returns a C pointer to the string. 179 + // It is a free function rather than a method on an extension trait because: 180 + // 181 + // - error[E0379]: functions in trait impls cannot be declared const 182 + #[inline] 183 + pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char { 184 + c_str.0.as_ptr() 185 + } 186 + 178 187 /// Possible errors when using conversion functions in [`CStr`]. 179 188 #[derive(Debug, Clone, Copy)] 180 189 pub enum CStrConvertError { ··· 241 232 /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` 242 233 /// must not be mutated. 243 234 #[inline] 244 - pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self { 235 + pub unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self { 245 236 // SAFETY: The safety precondition guarantees `ptr` is a valid pointer 246 237 // to a `NUL`-terminated C string. 247 238 let len = unsafe { bindings::strlen(ptr) } + 1; 248 239 // SAFETY: Lifetime guaranteed by the safety precondition. 249 - let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len) }; 240 + let bytes = unsafe { core::slice::from_raw_parts(ptr.cast(), len) }; 250 241 // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. 251 242 // As we have added 1 to `len`, the last byte is known to be `NUL`. 252 243 unsafe { Self::from_bytes_with_nul_unchecked(bytes) } ··· 299 290 #[inline] 300 291 pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { 301 292 // SAFETY: Properties of `bytes` guaranteed by the safety precondition. 302 - unsafe { &mut *(bytes as *mut [u8] as *mut CStr) } 293 + unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) } 303 294 } 304 295 305 296 /// Returns a C pointer to the string. 297 + /// 298 + /// Using this function in a const context is deprecated in favor of 299 + /// [`as_char_ptr_in_const_context`] in preparation for replacing `CStr` with `core::ffi::CStr` 300 + /// which does not have this method. 306 301 #[inline] 307 - pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char { 308 - self.0.as_ptr() 302 + pub const fn as_char_ptr(&self) -> *const c_char { 303 + as_char_ptr_in_const_context(self) 309 304 } 310 305 311 306 /// Convert the string to a byte slice without the trailing `NUL` byte. 312 307 #[inline] 313 - pub fn as_bytes(&self) -> &[u8] { 308 + pub fn to_bytes(&self) -> &[u8] { 314 309 &self.0[..self.len()] 310 + } 311 + 312 + /// Convert the string to a byte slice without the trailing `NUL` byte. 313 + /// 314 + /// This function is deprecated in favor of [`Self::to_bytes`] in preparation for replacing 315 + /// `CStr` with `core::ffi::CStr` which does not have this method. 316 + #[inline] 317 + pub fn as_bytes(&self) -> &[u8] { 318 + self.to_bytes() 315 319 } 316 320 317 321 /// Convert the string to a byte slice containing the trailing `NUL` byte. 318 322 #[inline] 319 - pub const fn as_bytes_with_nul(&self) -> &[u8] { 323 + pub const fn to_bytes_with_nul(&self) -> &[u8] { 320 324 &self.0 325 + } 326 + 327 + /// Convert the string to a byte slice containing the trailing `NUL` byte. 328 + /// 329 + /// This function is deprecated in favor of [`Self::to_bytes_with_nul`] in preparation for 330 + /// replacing `CStr` with `core::ffi::CStr` which does not have this method. 331 + #[inline] 332 + pub const fn as_bytes_with_nul(&self) -> &[u8] { 333 + self.to_bytes_with_nul() 321 334 } 322 335 323 336 /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8. ··· 460 429 /// 461 430 /// ``` 462 431 /// # use kernel::c_str; 463 - /// # use kernel::fmt; 432 + /// # use kernel::prelude::fmt; 464 433 /// # use kernel::str::CStr; 465 434 /// # use kernel::str::CString; 466 435 /// let penguin = c_str!("🐧"); 467 - /// let s = CString::try_from_fmt(fmt!("{}", penguin))?; 468 - /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 436 + /// let s = CString::try_from_fmt(fmt!("{penguin}"))?; 437 + /// assert_eq!(s.to_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 469 438 /// 470 439 /// let ascii = c_str!("so \"cool\""); 471 - /// let s = CString::try_from_fmt(fmt!("{}", ascii))?; 472 - /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 440 + /// let s = CString::try_from_fmt(fmt!("{ascii}"))?; 441 + /// assert_eq!(s.to_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 473 442 /// # Ok::<(), kernel::error::Error>(()) 474 443 /// ``` 475 444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 476 - for &c in self.as_bytes() { 445 + for &c in self.to_bytes() { 477 446 if (0x20..0x7f).contains(&c) { 478 447 // Printable character. 479 448 f.write_char(c as char)?; ··· 490 459 /// 491 460 /// ``` 492 461 /// # use kernel::c_str; 493 - /// # use kernel::fmt; 462 + /// # use kernel::prelude::fmt; 494 463 /// # use kernel::str::CStr; 495 464 /// # use kernel::str::CString; 496 465 /// let penguin = c_str!("🐧"); 497 - /// let s = CString::try_from_fmt(fmt!("{:?}", penguin))?; 466 + /// let s = CString::try_from_fmt(fmt!("{penguin:?}"))?; 498 467 /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 499 468 /// 500 469 /// // Embedded double quotes are escaped. 501 470 /// let ascii = c_str!("so \"cool\""); 502 - /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?; 471 + /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?; 503 472 /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 504 473 /// # Ok::<(), kernel::error::Error>(()) 505 474 /// ``` ··· 609 578 610 579 macro_rules! format { 611 580 ($($f:tt)*) => ({ 612 - CString::try_from_fmt(::kernel::fmt!($($f)*))?.to_str()? 581 + CString::try_from_fmt(fmt!($($f)*))?.to_str()? 613 582 }) 614 583 } 615 584 ··· 759 728 pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self { 760 729 // INVARIANT: The safety requirements guarantee the type invariants. 761 730 Self { 762 - beg: pos as _, 763 - pos: pos as _, 764 - end: end as _, 731 + beg: pos as usize, 732 + pos: pos as usize, 733 + end: end as usize, 765 734 } 766 735 } 767 736 ··· 786 755 /// 787 756 /// N.B. It may point to invalid memory. 788 757 pub(crate) fn pos(&self) -> *mut u8 { 789 - self.pos as _ 758 + self.pos as *mut u8 790 759 } 791 760 792 761 /// Returns the number of bytes written to the formatter. ··· 871 840 /// # Examples 872 841 /// 873 842 /// ``` 874 - /// use kernel::{str::CString, fmt}; 843 + /// use kernel::{str::CString, prelude::fmt}; 875 844 /// 876 845 /// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20))?; 877 - /// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes()); 846 + /// assert_eq!(s.to_bytes_with_nul(), "abc1020\0".as_bytes()); 878 847 /// 879 848 /// let tmp = "testing"; 880 849 /// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123))?; 881 - /// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes()); 850 + /// assert_eq!(s.to_bytes_with_nul(), "testing123\0".as_bytes()); 882 851 /// 883 852 /// // This fails because it has an embedded `NUL` byte. 884 853 /// let s = CString::try_from_fmt(fmt!("a\0b{}", 123)); ··· 948 917 fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> { 949 918 let mut buf = KVec::new(); 950 919 951 - buf.extend_from_slice(cstr.as_bytes_with_nul(), GFP_KERNEL)?; 920 + buf.extend_from_slice(cstr.to_bytes_with_nul(), GFP_KERNEL)?; 952 921 953 922 // INVARIANT: The `CStr` and `CString` types have the same invariants for 954 923 // the string data, and we copied it over without changes. ··· 960 929 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 961 930 fmt::Debug::fmt(&**self, f) 962 931 } 963 - } 964 - 965 - /// A convenience alias for [`core::format_args`]. 966 - #[macro_export] 967 - macro_rules! fmt { 968 - ($($f:tt)*) => ( ::core::format_args!($($f)*) ) 969 932 }
+7 -3
rust/kernel/sync.rs
··· 10 10 use pin_init; 11 11 12 12 mod arc; 13 + pub mod aref; 13 14 pub mod completion; 14 15 mod condvar; 15 16 pub mod lock; ··· 42 41 /// Initializes a dynamically allocated lock class key. In the common case of using a 43 42 /// statically allocated lock class key, the static_lock_class! macro should be used instead. 44 43 /// 45 - /// # Example 44 + /// # Examples 46 45 /// ``` 47 46 /// # use kernel::c_str; 48 47 /// # use kernel::alloc::KBox; ··· 96 95 macro_rules! static_lock_class { 97 96 () => {{ 98 97 static CLASS: $crate::sync::LockClassKey = 99 - // SAFETY: lockdep expects uninitialized memory when it's handed a statically allocated 100 - // lock_class_key 98 + // Lockdep expects uninitialized memory when it's handed a statically allocated `struct 99 + // lock_class_key`. 100 + // 101 + // SAFETY: `LockClassKey` transparently wraps `Opaque` which permits uninitialized 102 + // memory. 101 103 unsafe { ::core::mem::MaybeUninit::uninit().assume_init() }; 102 104 $crate::prelude::Pin::static_ref(&CLASS) 103 105 }};
+90 -12
rust/kernel/sync/arc.rs
··· 19 19 use crate::{ 20 20 alloc::{AllocError, Flags, KBox}, 21 21 bindings, 22 + ffi::c_void, 22 23 init::InPlaceInit, 23 24 try_init, 24 25 types::{ForeignOwnable, Opaque}, 25 26 }; 26 27 use core::{ 27 28 alloc::Layout, 29 + borrow::{Borrow, BorrowMut}, 28 30 fmt, 29 31 marker::PhantomData, 30 32 mem::{ManuallyDrop, MaybeUninit}, ··· 142 140 _p: PhantomData<ArcInner<T>>, 143 141 } 144 142 145 - #[doc(hidden)] 146 143 #[pin_data] 147 144 #[repr(C)] 148 - pub struct ArcInner<T: ?Sized> { 145 + struct ArcInner<T: ?Sized> { 149 146 refcount: Opaque<bindings::refcount_t>, 150 147 data: T, 151 148 } ··· 373 372 } 374 373 } 375 374 376 - // SAFETY: The `into_foreign` function returns a pointer that is well-aligned. 375 + // SAFETY: The pointer returned by `into_foreign` comes from a well aligned 376 + // pointer to `ArcInner<T>`. 377 377 unsafe impl<T: 'static> ForeignOwnable for Arc<T> { 378 - type PointedTo = ArcInner<T>; 378 + const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>(); 379 + 379 380 type Borrowed<'a> = ArcBorrow<'a, T>; 380 381 type BorrowedMut<'a> = Self::Borrowed<'a>; 381 382 382 - fn into_foreign(self) -> *mut Self::PointedTo { 383 - ManuallyDrop::new(self).ptr.as_ptr() 383 + fn into_foreign(self) -> *mut c_void { 384 + ManuallyDrop::new(self).ptr.as_ptr().cast() 384 385 } 385 386 386 - unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { 387 + unsafe fn from_foreign(ptr: *mut c_void) -> Self { 387 388 // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous 388 389 // call to `Self::into_foreign`. 389 - let inner = unsafe { NonNull::new_unchecked(ptr) }; 390 + let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) }; 390 391 391 392 // SAFETY: By the safety requirement of this function, we know that `ptr` came from 392 393 // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and ··· 396 393 unsafe { Self::from_inner(inner) } 397 394 } 398 395 399 - unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { 396 + unsafe fn borrow<'a>(ptr: *mut c_void) -> ArcBorrow<'a, T> { 400 397 // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous 401 398 // call to `Self::into_foreign`. 402 - let inner = unsafe { NonNull::new_unchecked(ptr) }; 399 + let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) }; 403 400 404 401 // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive 405 402 // for the lifetime of the returned value. 406 403 unsafe { ArcBorrow::new(inner) } 407 404 } 408 405 409 - unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { 406 + unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> ArcBorrow<'a, T> { 410 407 // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety 411 408 // requirements for `borrow`. 412 - unsafe { Self::borrow(ptr) } 409 + unsafe { <Self as ForeignOwnable>::borrow(ptr) } 413 410 } 414 411 } 415 412 ··· 425 422 426 423 impl<T: ?Sized> AsRef<T> for Arc<T> { 427 424 fn as_ref(&self) -> &T { 425 + self.deref() 426 + } 427 + } 428 + 429 + /// # Examples 430 + /// 431 + /// ``` 432 + /// # use core::borrow::Borrow; 433 + /// # use kernel::sync::Arc; 434 + /// struct Foo<B: Borrow<u32>>(B); 435 + /// 436 + /// // Owned instance. 437 + /// let owned = Foo(1); 438 + /// 439 + /// // Shared instance. 440 + /// let arc = Arc::new(1, GFP_KERNEL)?; 441 + /// let shared = Foo(arc.clone()); 442 + /// 443 + /// let i = 1; 444 + /// // Borrowed from `i`. 445 + /// let borrowed = Foo(&i); 446 + /// # Ok::<(), Error>(()) 447 + /// ``` 448 + impl<T: ?Sized> Borrow<T> for Arc<T> { 449 + fn borrow(&self) -> &T { 428 450 self.deref() 429 451 } 430 452 } ··· 859 831 // it is safe to dereference it. Additionally, we know there is only one reference when 860 832 // it's inside a `UniqueArc`, so it is safe to get a mutable reference. 861 833 unsafe { &mut self.inner.ptr.as_mut().data } 834 + } 835 + } 836 + 837 + /// # Examples 838 + /// 839 + /// ``` 840 + /// # use core::borrow::Borrow; 841 + /// # use kernel::sync::UniqueArc; 842 + /// struct Foo<B: Borrow<u32>>(B); 843 + /// 844 + /// // Owned instance. 845 + /// let owned = Foo(1); 846 + /// 847 + /// // Owned instance using `UniqueArc`. 848 + /// let arc = UniqueArc::new(1, GFP_KERNEL)?; 849 + /// let shared = Foo(arc); 850 + /// 851 + /// let i = 1; 852 + /// // Borrowed from `i`. 853 + /// let borrowed = Foo(&i); 854 + /// # Ok::<(), Error>(()) 855 + /// ``` 856 + impl<T: ?Sized> Borrow<T> for UniqueArc<T> { 857 + fn borrow(&self) -> &T { 858 + self.deref() 859 + } 860 + } 861 + 862 + /// # Examples 863 + /// 864 + /// ``` 865 + /// # use core::borrow::BorrowMut; 866 + /// # use kernel::sync::UniqueArc; 867 + /// struct Foo<B: BorrowMut<u32>>(B); 868 + /// 869 + /// // Owned instance. 870 + /// let owned = Foo(1); 871 + /// 872 + /// // Owned instance using `UniqueArc`. 873 + /// let arc = UniqueArc::new(1, GFP_KERNEL)?; 874 + /// let shared = Foo(arc); 875 + /// 876 + /// let mut i = 1; 877 + /// // Borrowed from `i`. 878 + /// let borrowed = Foo(&mut i); 879 + /// # Ok::<(), Error>(()) 880 + /// ``` 881 + impl<T: ?Sized> BorrowMut<T> for UniqueArc<T> { 882 + fn borrow_mut(&mut self) -> &mut T { 883 + self.deref_mut() 862 884 } 863 885 } 864 886
+154
rust/kernel/sync/aref.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Internal reference counting support. 4 + 5 + use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull}; 6 + 7 + /// Types that are _always_ reference counted. 8 + /// 9 + /// It allows such types to define their own custom ref increment and decrement functions. 10 + /// Additionally, it allows users to convert from a shared reference `&T` to an owned reference 11 + /// [`ARef<T>`]. 12 + /// 13 + /// This is usually implemented by wrappers to existing structures on the C side of the code. For 14 + /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted 15 + /// instances of a type. 16 + /// 17 + /// # Safety 18 + /// 19 + /// Implementers must ensure that increments to the reference count keep the object alive in memory 20 + /// at least until matching decrements are performed. 21 + /// 22 + /// Implementers must also ensure that all instances are reference-counted. (Otherwise they 23 + /// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object 24 + /// alive.) 25 + pub unsafe trait AlwaysRefCounted { 26 + /// Increments the reference count on the object. 27 + fn inc_ref(&self); 28 + 29 + /// Decrements the reference count on the object. 30 + /// 31 + /// Frees the object when the count reaches zero. 32 + /// 33 + /// # Safety 34 + /// 35 + /// Callers must ensure that there was a previous matching increment to the reference count, 36 + /// and that the object is no longer used after its reference count is decremented (as it may 37 + /// result in the object being freed), unless the caller owns another increment on the refcount 38 + /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls 39 + /// [`AlwaysRefCounted::dec_ref`] once). 40 + unsafe fn dec_ref(obj: NonNull<Self>); 41 + } 42 + 43 + /// An owned reference to an always-reference-counted object. 44 + /// 45 + /// The object's reference count is automatically decremented when an instance of [`ARef`] is 46 + /// dropped. It is also automatically incremented when a new instance is created via 47 + /// [`ARef::clone`]. 48 + /// 49 + /// # Invariants 50 + /// 51 + /// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In 52 + /// particular, the [`ARef`] instance owns an increment on the underlying object's reference count. 53 + pub struct ARef<T: AlwaysRefCounted> { 54 + ptr: NonNull<T>, 55 + _p: PhantomData<T>, 56 + } 57 + 58 + // SAFETY: It is safe to send `ARef<T>` to another thread when the underlying `T` is `Sync` because 59 + // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs 60 + // `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a 61 + // mutable reference, for example, when the reference count reaches zero and `T` is dropped. 62 + unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {} 63 + 64 + // SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync` 65 + // because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, 66 + // it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an 67 + // `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for 68 + // example, when the reference count reaches zero and `T` is dropped. 69 + unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {} 70 + 71 + impl<T: AlwaysRefCounted> ARef<T> { 72 + /// Creates a new instance of [`ARef`]. 73 + /// 74 + /// It takes over an increment of the reference count on the underlying object. 75 + /// 76 + /// # Safety 77 + /// 78 + /// Callers must ensure that the reference count was incremented at least once, and that they 79 + /// are properly relinquishing one increment. That is, if there is only one increment, callers 80 + /// must not use the underlying object anymore -- it is only safe to do so via the newly 81 + /// created [`ARef`]. 82 + pub unsafe fn from_raw(ptr: NonNull<T>) -> Self { 83 + // INVARIANT: The safety requirements guarantee that the new instance now owns the 84 + // increment on the refcount. 85 + Self { 86 + ptr, 87 + _p: PhantomData, 88 + } 89 + } 90 + 91 + /// Consumes the `ARef`, returning a raw pointer. 92 + /// 93 + /// This function does not change the refcount. After calling this function, the caller is 94 + /// responsible for the refcount previously managed by the `ARef`. 95 + /// 96 + /// # Examples 97 + /// 98 + /// ``` 99 + /// use core::ptr::NonNull; 100 + /// use kernel::types::{ARef, AlwaysRefCounted}; 101 + /// 102 + /// struct Empty {} 103 + /// 104 + /// # // SAFETY: TODO. 105 + /// unsafe impl AlwaysRefCounted for Empty { 106 + /// fn inc_ref(&self) {} 107 + /// unsafe fn dec_ref(_obj: NonNull<Self>) {} 108 + /// } 109 + /// 110 + /// let mut data = Empty {}; 111 + /// let ptr = NonNull::<Empty>::new(&mut data).unwrap(); 112 + /// # // SAFETY: TODO. 113 + /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) }; 114 + /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref); 115 + /// 116 + /// assert_eq!(ptr, raw_ptr); 117 + /// ``` 118 + pub fn into_raw(me: Self) -> NonNull<T> { 119 + ManuallyDrop::new(me).ptr 120 + } 121 + } 122 + 123 + impl<T: AlwaysRefCounted> Clone for ARef<T> { 124 + fn clone(&self) -> Self { 125 + self.inc_ref(); 126 + // SAFETY: We just incremented the refcount above. 127 + unsafe { Self::from_raw(self.ptr) } 128 + } 129 + } 130 + 131 + impl<T: AlwaysRefCounted> Deref for ARef<T> { 132 + type Target = T; 133 + 134 + fn deref(&self) -> &Self::Target { 135 + // SAFETY: The type invariants guarantee that the object is valid. 136 + unsafe { self.ptr.as_ref() } 137 + } 138 + } 139 + 140 + impl<T: AlwaysRefCounted> From<&T> for ARef<T> { 141 + fn from(b: &T) -> Self { 142 + b.inc_ref(); 143 + // SAFETY: We just incremented the refcount above. 144 + unsafe { Self::from_raw(NonNull::from(b)) } 145 + } 146 + } 147 + 148 + impl<T: AlwaysRefCounted> Drop for ARef<T> { 149 + fn drop(&mut self) { 150 + // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to 151 + // decrement. 152 + unsafe { T::dec_ref(self.ptr) }; 153 + } 154 + }
+154 -79
rust/kernel/time.rs
··· 24 24 //! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h). 25 25 //! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h). 26 26 27 + use core::marker::PhantomData; 28 + 29 + pub mod delay; 27 30 pub mod hrtimer; 28 31 29 32 /// The number of nanoseconds per microsecond. ··· 52 49 unsafe { bindings::__msecs_to_jiffies(msecs) } 53 50 } 54 51 52 + /// Trait for clock sources. 53 + /// 54 + /// Selection of the clock source depends on the use case. In some cases the usage of a 55 + /// particular clock is mandatory, e.g. in network protocols, filesystems. In other 56 + /// cases the user of the clock has to decide which clock is best suited for the 57 + /// purpose. In most scenarios clock [`Monotonic`] is the best choice as it 58 + /// provides a accurate monotonic notion of time (leap second smearing ignored). 59 + pub trait ClockSource { 60 + /// The kernel clock ID associated with this clock source. 61 + /// 62 + /// This constant corresponds to the C side `clockid_t` value. 63 + const ID: bindings::clockid_t; 64 + 65 + /// Get the current time from the clock source. 66 + /// 67 + /// The function must return a value in the range from 0 to `KTIME_MAX`. 68 + fn ktime_get() -> bindings::ktime_t; 69 + } 70 + 71 + /// A monotonically increasing clock. 72 + /// 73 + /// A nonsettable system-wide clock that represents monotonic time since as 74 + /// described by POSIX, "some unspecified point in the past". On Linux, that 75 + /// point corresponds to the number of seconds that the system has been 76 + /// running since it was booted. 77 + /// 78 + /// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the 79 + /// CLOCK_REAL (e.g., if the system administrator manually changes the 80 + /// clock), but is affected by frequency adjustments. This clock does not 81 + /// count time that the system is suspended. 82 + pub struct Monotonic; 83 + 84 + impl ClockSource for Monotonic { 85 + const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t; 86 + 87 + fn ktime_get() -> bindings::ktime_t { 88 + // SAFETY: It is always safe to call `ktime_get()` outside of NMI context. 89 + unsafe { bindings::ktime_get() } 90 + } 91 + } 92 + 93 + /// A settable system-wide clock that measures real (i.e., wall-clock) time. 94 + /// 95 + /// Setting this clock requires appropriate privileges. This clock is 96 + /// affected by discontinuous jumps in the system time (e.g., if the system 97 + /// administrator manually changes the clock), and by frequency adjustments 98 + /// performed by NTP and similar applications via adjtime(3), adjtimex(2), 99 + /// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the 100 + /// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time 101 + /// (UTC) except that it ignores leap seconds; near a leap second it may be 102 + /// adjusted by leap second smearing to stay roughly in sync with UTC. Leap 103 + /// second smearing applies frequency adjustments to the clock to speed up 104 + /// or slow down the clock to account for the leap second without 105 + /// discontinuities in the clock. If leap second smearing is not applied, 106 + /// the clock will experience discontinuity around leap second adjustment. 107 + pub struct RealTime; 108 + 109 + impl ClockSource for RealTime { 110 + const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t; 111 + 112 + fn ktime_get() -> bindings::ktime_t { 113 + // SAFETY: It is always safe to call `ktime_get_real()` outside of NMI context. 114 + unsafe { bindings::ktime_get_real() } 115 + } 116 + } 117 + 118 + /// A monotonic that ticks while system is suspended. 119 + /// 120 + /// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC, 121 + /// except that it also includes any time that the system is suspended. This 122 + /// allows applications to get a suspend-aware monotonic clock without 123 + /// having to deal with the complications of CLOCK_REALTIME, which may have 124 + /// discontinuities if the time is changed using settimeofday(2) or similar. 125 + pub struct BootTime; 126 + 127 + impl ClockSource for BootTime { 128 + const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t; 129 + 130 + fn ktime_get() -> bindings::ktime_t { 131 + // SAFETY: It is always safe to call `ktime_get_boottime()` outside of NMI context. 132 + unsafe { bindings::ktime_get_boottime() } 133 + } 134 + } 135 + 136 + /// International Atomic Time. 137 + /// 138 + /// A system-wide clock derived from wall-clock time but counting leap seconds. 139 + /// 140 + /// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is 141 + /// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This 142 + /// usually happens during boot and **should** not happen during normal operations. 143 + /// However, if NTP or another application adjusts CLOCK_REALTIME by leap second 144 + /// smearing, this clock will not be precise during leap second smearing. 145 + /// 146 + /// The acronym TAI refers to International Atomic Time. 147 + pub struct Tai; 148 + 149 + impl ClockSource for Tai { 150 + const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t; 151 + 152 + fn ktime_get() -> bindings::ktime_t { 153 + // SAFETY: It is always safe to call `ktime_get_tai()` outside of NMI context. 154 + unsafe { bindings::ktime_get_clocktai() } 155 + } 156 + } 157 + 55 158 /// A specific point in time. 56 159 /// 57 160 /// # Invariants 58 161 /// 59 162 /// The `inner` value is in the range from 0 to `KTIME_MAX`. 60 163 #[repr(transparent)] 61 - #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] 62 - pub struct Instant { 164 + #[derive(PartialEq, PartialOrd, Eq, Ord)] 165 + pub struct Instant<C: ClockSource> { 63 166 inner: bindings::ktime_t, 167 + _c: PhantomData<C>, 64 168 } 65 169 66 - impl Instant { 67 - /// Get the current time using `CLOCK_MONOTONIC`. 170 + impl<C: ClockSource> Clone for Instant<C> { 171 + fn clone(&self) -> Self { 172 + *self 173 + } 174 + } 175 + 176 + impl<C: ClockSource> Copy for Instant<C> {} 177 + 178 + impl<C: ClockSource> Instant<C> { 179 + /// Get the current time from the clock source. 68 180 #[inline] 69 181 pub fn now() -> Self { 70 - // INVARIANT: The `ktime_get()` function returns a value in the range 182 + // INVARIANT: The `ClockSource::ktime_get()` function returns a value in the range 71 183 // from 0 to `KTIME_MAX`. 72 184 Self { 73 - // SAFETY: It is always safe to call `ktime_get()` outside of NMI context. 74 - inner: unsafe { bindings::ktime_get() }, 185 + inner: C::ktime_get(), 186 + _c: PhantomData, 75 187 } 76 188 } 77 189 ··· 195 77 pub fn elapsed(&self) -> Delta { 196 78 Self::now() - *self 197 79 } 80 + 81 + #[inline] 82 + pub(crate) fn as_nanos(&self) -> i64 { 83 + self.inner 84 + } 198 85 } 199 86 200 - impl core::ops::Sub for Instant { 87 + impl<C: ClockSource> core::ops::Sub for Instant<C> { 201 88 type Output = Delta; 202 89 203 90 // By the type invariant, it never overflows. 204 91 #[inline] 205 - fn sub(self, other: Instant) -> Delta { 92 + fn sub(self, other: Instant<C>) -> Delta { 206 93 Delta { 207 94 nanos: self.inner - other.inner, 208 95 } 209 - } 210 - } 211 - 212 - /// An identifier for a clock. Used when specifying clock sources. 213 - /// 214 - /// 215 - /// Selection of the clock depends on the use case. In some cases the usage of a 216 - /// particular clock is mandatory, e.g. in network protocols, filesystems.In other 217 - /// cases the user of the clock has to decide which clock is best suited for the 218 - /// purpose. In most scenarios clock [`ClockId::Monotonic`] is the best choice as it 219 - /// provides a accurate monotonic notion of time (leap second smearing ignored). 220 - #[derive(Clone, Copy, PartialEq, Eq, Debug)] 221 - #[repr(u32)] 222 - pub enum ClockId { 223 - /// A settable system-wide clock that measures real (i.e., wall-clock) time. 224 - /// 225 - /// Setting this clock requires appropriate privileges. This clock is 226 - /// affected by discontinuous jumps in the system time (e.g., if the system 227 - /// administrator manually changes the clock), and by frequency adjustments 228 - /// performed by NTP and similar applications via adjtime(3), adjtimex(2), 229 - /// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the 230 - /// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time 231 - /// (UTC) except that it ignores leap seconds; near a leap second it may be 232 - /// adjusted by leap second smearing to stay roughly in sync with UTC. Leap 233 - /// second smearing applies frequency adjustments to the clock to speed up 234 - /// or slow down the clock to account for the leap second without 235 - /// discontinuities in the clock. If leap second smearing is not applied, 236 - /// the clock will experience discontinuity around leap second adjustment. 237 - RealTime = bindings::CLOCK_REALTIME, 238 - /// A monotonically increasing clock. 239 - /// 240 - /// A nonsettable system-wide clock that represents monotonic time since—as 241 - /// described by POSIX—"some unspecified point in the past". On Linux, that 242 - /// point corresponds to the number of seconds that the system has been 243 - /// running since it was booted. 244 - /// 245 - /// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the 246 - /// CLOCK_REAL (e.g., if the system administrator manually changes the 247 - /// clock), but is affected by frequency adjustments. This clock does not 248 - /// count time that the system is suspended. 249 - Monotonic = bindings::CLOCK_MONOTONIC, 250 - /// A monotonic that ticks while system is suspended. 251 - /// 252 - /// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC, 253 - /// except that it also includes any time that the system is suspended. This 254 - /// allows applications to get a suspend-aware monotonic clock without 255 - /// having to deal with the complications of CLOCK_REALTIME, which may have 256 - /// discontinuities if the time is changed using settimeofday(2) or similar. 257 - BootTime = bindings::CLOCK_BOOTTIME, 258 - /// International Atomic Time. 259 - /// 260 - /// A system-wide clock derived from wall-clock time but counting leap seconds. 261 - /// 262 - /// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is 263 - /// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This 264 - /// usually happens during boot and **should** not happen during normal operations. 265 - /// However, if NTP or another application adjusts CLOCK_REALTIME by leap second 266 - /// smearing, this clock will not be precise during leap second smearing. 267 - /// 268 - /// The acronym TAI refers to International Atomic Time. 269 - TAI = bindings::CLOCK_TAI, 270 - } 271 - 272 - impl ClockId { 273 - fn into_c(self) -> bindings::clockid_t { 274 - self as bindings::clockid_t 275 96 } 276 97 } 277 98 ··· 285 228 /// Return the smallest number of microseconds greater than or equal 286 229 /// to the value in the [`Delta`]. 287 230 #[inline] 288 - pub const fn as_micros_ceil(self) -> i64 { 289 - self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC 231 + pub fn as_micros_ceil(self) -> i64 { 232 + #[cfg(CONFIG_64BIT)] 233 + { 234 + self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC 235 + } 236 + 237 + #[cfg(not(CONFIG_64BIT))] 238 + // SAFETY: It is always safe to call `ktime_to_us()` with any value. 239 + unsafe { 240 + bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1)) 241 + } 290 242 } 291 243 292 244 /// Return the number of milliseconds in the [`Delta`]. 293 245 #[inline] 294 - pub const fn as_millis(self) -> i64 { 295 - self.as_nanos() / NSEC_PER_MSEC 246 + pub fn as_millis(self) -> i64 { 247 + #[cfg(CONFIG_64BIT)] 248 + { 249 + self.as_nanos() / NSEC_PER_MSEC 250 + } 251 + 252 + #[cfg(not(CONFIG_64BIT))] 253 + // SAFETY: It is always safe to call `ktime_to_ms()` with any value. 254 + unsafe { 255 + bindings::ktime_to_ms(self.as_nanos()) 256 + } 296 257 } 297 258 }
+49
rust/kernel/time/delay.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Delay and sleep primitives. 4 + //! 5 + //! This module contains the kernel APIs related to delay and sleep that 6 + //! have been ported or wrapped for usage by Rust code in the kernel. 7 + //! 8 + //! C header: [`include/linux/delay.h`](srctree/include/linux/delay.h). 9 + 10 + use super::Delta; 11 + use crate::prelude::*; 12 + 13 + /// Sleeps for a given duration at least. 14 + /// 15 + /// Equivalent to the C side [`fsleep()`], flexible sleep function, 16 + /// which automatically chooses the best sleep method based on a duration. 17 + /// 18 + /// `delta` must be within `[0, i32::MAX]` microseconds; 19 + /// otherwise, it is erroneous behavior. That is, it is considered a bug 20 + /// to call this function with an out-of-range value, in which case the function 21 + /// will sleep for at least the maximum value in the range and may warn 22 + /// in the future. 23 + /// 24 + /// The behavior above differs from the C side [`fsleep()`] for which out-of-range 25 + /// values mean "infinite timeout" instead. 26 + /// 27 + /// This function can only be used in a nonatomic context. 28 + /// 29 + /// [`fsleep()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.fsleep 30 + pub fn fsleep(delta: Delta) { 31 + // The maximum value is set to `i32::MAX` microseconds to prevent integer 32 + // overflow inside fsleep, which could lead to unintentional infinite sleep. 33 + const MAX_DELTA: Delta = Delta::from_micros(i32::MAX as i64); 34 + 35 + let delta = if (Delta::ZERO..=MAX_DELTA).contains(&delta) { 36 + delta 37 + } else { 38 + // TODO: Add WARN_ONCE() when it's supported. 39 + MAX_DELTA 40 + }; 41 + 42 + // SAFETY: It is always safe to call `fsleep()` with any duration. 43 + unsafe { 44 + // Convert the duration to microseconds and round up to preserve 45 + // the guarantee; `fsleep()` sleeps for at least the provided duration, 46 + // but that it may sleep for longer under some circumstances. 47 + bindings::fsleep(delta.as_micros_ceil() as c_ulong) 48 + } 49 + }
+204 -100
rust/kernel/time/hrtimer.rs
··· 67 67 //! A `restart` operation on a timer in the **stopped** state is equivalent to a 68 68 //! `start` operation. 69 69 70 - use super::ClockId; 70 + use super::{ClockSource, Delta, Instant}; 71 71 use crate::{prelude::*, types::Opaque}; 72 72 use core::marker::PhantomData; 73 73 use pin_init::PinInit; 74 - 75 - /// A Rust wrapper around a `ktime_t`. 76 - // NOTE: Ktime is going to be removed when hrtimer is converted to Instant/Delta. 77 - #[repr(transparent)] 78 - #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] 79 - pub struct Ktime { 80 - inner: bindings::ktime_t, 81 - } 82 - 83 - impl Ktime { 84 - /// Returns the number of nanoseconds. 85 - #[inline] 86 - pub fn to_ns(self) -> i64 { 87 - self.inner 88 - } 89 - } 90 74 91 75 /// A timer backed by a C `struct hrtimer`. 92 76 /// ··· 82 98 pub struct HrTimer<T> { 83 99 #[pin] 84 100 timer: Opaque<bindings::hrtimer>, 85 - mode: HrTimerMode, 86 101 _t: PhantomData<T>, 87 102 } 88 103 ··· 95 112 96 113 impl<T> HrTimer<T> { 97 114 /// Return an initializer for a new timer instance. 98 - pub fn new(mode: HrTimerMode, clock: ClockId) -> impl PinInit<Self> 115 + pub fn new() -> impl PinInit<Self> 99 116 where 100 117 T: HrTimerCallback, 118 + T: HasHrTimer<T>, 101 119 { 102 120 pin_init!(Self { 103 121 // INVARIANT: We initialize `timer` with `hrtimer_setup` below. ··· 110 126 bindings::hrtimer_setup( 111 127 place, 112 128 Some(T::Pointer::run), 113 - clock.into_c(), 114 - mode.into_c(), 129 + <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock::ID, 130 + <T as HasHrTimer<T>>::TimerMode::C_MODE, 115 131 ); 116 132 } 117 133 }), 118 - mode: mode, 119 134 _t: PhantomData, 120 135 }) 121 136 } ··· 131 148 // SAFETY: The field projection to `timer` does not go out of bounds, 132 149 // because the caller of this function promises that `this` points to an 133 150 // allocation of at least the size of `Self`. 134 - unsafe { Opaque::raw_get(core::ptr::addr_of!((*this).timer)) } 151 + unsafe { Opaque::cast_into(core::ptr::addr_of!((*this).timer)) } 135 152 } 136 153 137 154 /// Cancel an initialized and potentially running timer. ··· 176 193 /// exist. A timer can be manipulated through any of the handles, and a handle 177 194 /// may represent a cancelled timer. 178 195 pub trait HrTimerPointer: Sync + Sized { 196 + /// The operational mode associated with this timer. 197 + /// 198 + /// This defines how the expiration value is interpreted. 199 + type TimerMode: HrTimerMode; 200 + 179 201 /// A handle representing a started or restarted timer. 180 202 /// 181 203 /// If the timer is running or if the timer callback is executing when the ··· 193 205 194 206 /// Start the timer with expiry after `expires` time units. If the timer was 195 207 /// already running, it is restarted with the new expiry time. 196 - fn start(self, expires: Ktime) -> Self::TimerHandle; 208 + fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle; 197 209 } 198 210 199 211 /// Unsafe version of [`HrTimerPointer`] for situations where leaking the ··· 208 220 /// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`] 209 221 /// instances. 210 222 pub unsafe trait UnsafeHrTimerPointer: Sync + Sized { 223 + /// The operational mode associated with this timer. 224 + /// 225 + /// This defines how the expiration value is interpreted. 226 + type TimerMode: HrTimerMode; 227 + 211 228 /// A handle representing a running timer. 212 229 /// 213 230 /// # Safety ··· 229 236 /// 230 237 /// Caller promises keep the timer structure alive until the timer is dead. 231 238 /// Caller can ensure this by not leaking the returned [`Self::TimerHandle`]. 232 - unsafe fn start(self, expires: Ktime) -> Self::TimerHandle; 239 + unsafe fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle; 233 240 } 234 241 235 242 /// A trait for stack allocated timers. ··· 239 246 /// Implementers must ensure that `start_scoped` does not return until the 240 247 /// timer is dead and the timer handler is not running. 241 248 pub unsafe trait ScopedHrTimerPointer { 249 + /// The operational mode associated with this timer. 250 + /// 251 + /// This defines how the expiration value is interpreted. 252 + type TimerMode: HrTimerMode; 253 + 242 254 /// Start the timer to run after `expires` time units and immediately 243 255 /// after call `f`. When `f` returns, the timer is cancelled. 244 - fn start_scoped<T, F>(self, expires: Ktime, f: F) -> T 256 + fn start_scoped<T, F>(self, expires: <Self::TimerMode as HrTimerMode>::Expires, f: F) -> T 245 257 where 246 258 F: FnOnce() -> T; 247 259 } ··· 258 260 where 259 261 T: UnsafeHrTimerPointer, 260 262 { 261 - fn start_scoped<U, F>(self, expires: Ktime, f: F) -> U 263 + type TimerMode = T::TimerMode; 264 + 265 + fn start_scoped<U, F>( 266 + self, 267 + expires: <<T as UnsafeHrTimerPointer>::TimerMode as HrTimerMode>::Expires, 268 + f: F, 269 + ) -> U 262 270 where 263 271 F: FnOnce() -> U, 264 272 { ··· 339 335 /// their documentation. All the methods of this trait must operate on the same 340 336 /// field. 341 337 pub unsafe trait HasHrTimer<T> { 338 + /// The operational mode associated with this timer. 339 + /// 340 + /// This defines how the expiration value is interpreted. 341 + type TimerMode: HrTimerMode; 342 + 342 343 /// Return a pointer to the [`HrTimer`] within `Self`. 343 344 /// 344 345 /// This function is useful to get access to the value without creating ··· 391 382 /// - `this` must point to a valid `Self`. 392 383 /// - Caller must ensure that the pointee of `this` lives until the timer 393 384 /// fires or is canceled. 394 - unsafe fn start(this: *const Self, expires: Ktime) { 385 + unsafe fn start(this: *const Self, expires: <Self::TimerMode as HrTimerMode>::Expires) { 395 386 // SAFETY: By function safety requirement, `this` is a valid `Self`. 396 387 unsafe { 397 388 bindings::hrtimer_start_range_ns( 398 389 Self::c_timer_ptr(this).cast_mut(), 399 - expires.to_ns(), 390 + expires.as_nanos(), 400 391 0, 401 - (*Self::raw_get_timer(this)).mode.into_c(), 392 + <Self::TimerMode as HrTimerMode>::C_MODE, 402 393 ); 403 394 } 404 395 } ··· 420 411 } 421 412 } 422 413 423 - /// Operational mode of [`HrTimer`]. 424 - // NOTE: Some of these have the same encoding on the C side, so we keep 425 - // `repr(Rust)` and convert elsewhere. 426 - #[derive(Clone, Copy, PartialEq, Eq, Debug)] 427 - pub enum HrTimerMode { 428 - /// Timer expires at the given expiration time. 429 - Absolute, 430 - /// Timer expires after the given expiration time interpreted as a duration from now. 431 - Relative, 432 - /// Timer does not move between CPU cores. 433 - Pinned, 434 - /// Timer handler is executed in soft irq context. 435 - Soft, 436 - /// Timer handler is executed in hard irq context. 437 - Hard, 438 - /// Timer expires at the given expiration time. 439 - /// Timer does not move between CPU cores. 440 - AbsolutePinned, 441 - /// Timer expires after the given expiration time interpreted as a duration from now. 442 - /// Timer does not move between CPU cores. 443 - RelativePinned, 444 - /// Timer expires at the given expiration time. 445 - /// Timer handler is executed in soft irq context. 446 - AbsoluteSoft, 447 - /// Timer expires after the given expiration time interpreted as a duration from now. 448 - /// Timer handler is executed in soft irq context. 449 - RelativeSoft, 450 - /// Timer expires at the given expiration time. 451 - /// Timer does not move between CPU cores. 452 - /// Timer handler is executed in soft irq context. 453 - AbsolutePinnedSoft, 454 - /// Timer expires after the given expiration time interpreted as a duration from now. 455 - /// Timer does not move between CPU cores. 456 - /// Timer handler is executed in soft irq context. 457 - RelativePinnedSoft, 458 - /// Timer expires at the given expiration time. 459 - /// Timer handler is executed in hard irq context. 460 - AbsoluteHard, 461 - /// Timer expires after the given expiration time interpreted as a duration from now. 462 - /// Timer handler is executed in hard irq context. 463 - RelativeHard, 464 - /// Timer expires at the given expiration time. 465 - /// Timer does not move between CPU cores. 466 - /// Timer handler is executed in hard irq context. 467 - AbsolutePinnedHard, 468 - /// Timer expires after the given expiration time interpreted as a duration from now. 469 - /// Timer does not move between CPU cores. 470 - /// Timer handler is executed in hard irq context. 471 - RelativePinnedHard, 414 + /// Time representations that can be used as expiration values in [`HrTimer`]. 415 + pub trait HrTimerExpires { 416 + /// Converts the expiration time into a nanosecond representation. 417 + /// 418 + /// This value corresponds to a raw ktime_t value, suitable for passing to kernel 419 + /// timer functions. The interpretation (absolute vs relative) depends on the 420 + /// associated [HrTimerMode] in use. 421 + fn as_nanos(&self) -> i64; 472 422 } 473 423 474 - impl HrTimerMode { 475 - fn into_c(self) -> bindings::hrtimer_mode { 476 - use bindings::*; 477 - match self { 478 - HrTimerMode::Absolute => hrtimer_mode_HRTIMER_MODE_ABS, 479 - HrTimerMode::Relative => hrtimer_mode_HRTIMER_MODE_REL, 480 - HrTimerMode::Pinned => hrtimer_mode_HRTIMER_MODE_PINNED, 481 - HrTimerMode::Soft => hrtimer_mode_HRTIMER_MODE_SOFT, 482 - HrTimerMode::Hard => hrtimer_mode_HRTIMER_MODE_HARD, 483 - HrTimerMode::AbsolutePinned => hrtimer_mode_HRTIMER_MODE_ABS_PINNED, 484 - HrTimerMode::RelativePinned => hrtimer_mode_HRTIMER_MODE_REL_PINNED, 485 - HrTimerMode::AbsoluteSoft => hrtimer_mode_HRTIMER_MODE_ABS_SOFT, 486 - HrTimerMode::RelativeSoft => hrtimer_mode_HRTIMER_MODE_REL_SOFT, 487 - HrTimerMode::AbsolutePinnedSoft => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT, 488 - HrTimerMode::RelativePinnedSoft => hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT, 489 - HrTimerMode::AbsoluteHard => hrtimer_mode_HRTIMER_MODE_ABS_HARD, 490 - HrTimerMode::RelativeHard => hrtimer_mode_HRTIMER_MODE_REL_HARD, 491 - HrTimerMode::AbsolutePinnedHard => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD, 492 - HrTimerMode::RelativePinnedHard => hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD, 493 - } 424 + impl<C: ClockSource> HrTimerExpires for Instant<C> { 425 + #[inline] 426 + fn as_nanos(&self) -> i64 { 427 + Instant::<C>::as_nanos(self) 494 428 } 429 + } 430 + 431 + impl HrTimerExpires for Delta { 432 + #[inline] 433 + fn as_nanos(&self) -> i64 { 434 + Delta::as_nanos(*self) 435 + } 436 + } 437 + 438 + mod private { 439 + use crate::time::ClockSource; 440 + 441 + pub trait Sealed {} 442 + 443 + impl<C: ClockSource> Sealed for super::AbsoluteMode<C> {} 444 + impl<C: ClockSource> Sealed for super::RelativeMode<C> {} 445 + impl<C: ClockSource> Sealed for super::AbsolutePinnedMode<C> {} 446 + impl<C: ClockSource> Sealed for super::RelativePinnedMode<C> {} 447 + impl<C: ClockSource> Sealed for super::AbsoluteSoftMode<C> {} 448 + impl<C: ClockSource> Sealed for super::RelativeSoftMode<C> {} 449 + impl<C: ClockSource> Sealed for super::AbsolutePinnedSoftMode<C> {} 450 + impl<C: ClockSource> Sealed for super::RelativePinnedSoftMode<C> {} 451 + impl<C: ClockSource> Sealed for super::AbsoluteHardMode<C> {} 452 + impl<C: ClockSource> Sealed for super::RelativeHardMode<C> {} 453 + impl<C: ClockSource> Sealed for super::AbsolutePinnedHardMode<C> {} 454 + impl<C: ClockSource> Sealed for super::RelativePinnedHardMode<C> {} 455 + } 456 + 457 + /// Operational mode of [`HrTimer`]. 458 + pub trait HrTimerMode: private::Sealed { 459 + /// The C representation of hrtimer mode. 460 + const C_MODE: bindings::hrtimer_mode; 461 + 462 + /// Type representing the clock source. 463 + type Clock: ClockSource; 464 + 465 + /// Type representing the expiration specification (absolute or relative time). 466 + type Expires: HrTimerExpires; 467 + } 468 + 469 + /// Timer that expires at a fixed point in time. 470 + pub struct AbsoluteMode<C: ClockSource>(PhantomData<C>); 471 + 472 + impl<C: ClockSource> HrTimerMode for AbsoluteMode<C> { 473 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS; 474 + 475 + type Clock = C; 476 + type Expires = Instant<C>; 477 + } 478 + 479 + /// Timer that expires after a delay from now. 480 + pub struct RelativeMode<C: ClockSource>(PhantomData<C>); 481 + 482 + impl<C: ClockSource> HrTimerMode for RelativeMode<C> { 483 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL; 484 + 485 + type Clock = C; 486 + type Expires = Delta; 487 + } 488 + 489 + /// Timer with absolute expiration time, pinned to its current CPU. 490 + pub struct AbsolutePinnedMode<C: ClockSource>(PhantomData<C>); 491 + impl<C: ClockSource> HrTimerMode for AbsolutePinnedMode<C> { 492 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED; 493 + 494 + type Clock = C; 495 + type Expires = Instant<C>; 496 + } 497 + 498 + /// Timer with relative expiration time, pinned to its current CPU. 499 + pub struct RelativePinnedMode<C: ClockSource>(PhantomData<C>); 500 + impl<C: ClockSource> HrTimerMode for RelativePinnedMode<C> { 501 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED; 502 + 503 + type Clock = C; 504 + type Expires = Delta; 505 + } 506 + 507 + /// Timer with absolute expiration, handled in soft irq context. 508 + pub struct AbsoluteSoftMode<C: ClockSource>(PhantomData<C>); 509 + impl<C: ClockSource> HrTimerMode for AbsoluteSoftMode<C> { 510 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_SOFT; 511 + 512 + type Clock = C; 513 + type Expires = Instant<C>; 514 + } 515 + 516 + /// Timer with relative expiration, handled in soft irq context. 517 + pub struct RelativeSoftMode<C: ClockSource>(PhantomData<C>); 518 + impl<C: ClockSource> HrTimerMode for RelativeSoftMode<C> { 519 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_SOFT; 520 + 521 + type Clock = C; 522 + type Expires = Delta; 523 + } 524 + 525 + /// Timer with absolute expiration, pinned to CPU and handled in soft irq context. 526 + pub struct AbsolutePinnedSoftMode<C: ClockSource>(PhantomData<C>); 527 + impl<C: ClockSource> HrTimerMode for AbsolutePinnedSoftMode<C> { 528 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT; 529 + 530 + type Clock = C; 531 + type Expires = Instant<C>; 532 + } 533 + 534 + /// Timer with absolute expiration, pinned to CPU and handled in soft irq context. 535 + pub struct RelativePinnedSoftMode<C: ClockSource>(PhantomData<C>); 536 + impl<C: ClockSource> HrTimerMode for RelativePinnedSoftMode<C> { 537 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT; 538 + 539 + type Clock = C; 540 + type Expires = Delta; 541 + } 542 + 543 + /// Timer with absolute expiration, handled in hard irq context. 544 + pub struct AbsoluteHardMode<C: ClockSource>(PhantomData<C>); 545 + impl<C: ClockSource> HrTimerMode for AbsoluteHardMode<C> { 546 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_HARD; 547 + 548 + type Clock = C; 549 + type Expires = Instant<C>; 550 + } 551 + 552 + /// Timer with relative expiration, handled in hard irq context. 553 + pub struct RelativeHardMode<C: ClockSource>(PhantomData<C>); 554 + impl<C: ClockSource> HrTimerMode for RelativeHardMode<C> { 555 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_HARD; 556 + 557 + type Clock = C; 558 + type Expires = Delta; 559 + } 560 + 561 + /// Timer with absolute expiration, pinned to CPU and handled in hard irq context. 562 + pub struct AbsolutePinnedHardMode<C: ClockSource>(PhantomData<C>); 563 + impl<C: ClockSource> HrTimerMode for AbsolutePinnedHardMode<C> { 564 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD; 565 + 566 + type Clock = C; 567 + type Expires = Instant<C>; 568 + } 569 + 570 + /// Timer with relative expiration, pinned to CPU and handled in hard irq context. 571 + pub struct RelativePinnedHardMode<C: ClockSource>(PhantomData<C>); 572 + impl<C: ClockSource> HrTimerMode for RelativePinnedHardMode<C> { 573 + const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD; 574 + 575 + type Clock = C; 576 + type Expires = Delta; 495 577 } 496 578 497 579 /// Use to implement the [`HasHrTimer<T>`] trait. ··· 596 496 impl$({$($generics:tt)*})? 597 497 HasHrTimer<$timer_type:ty> 598 498 for $self:ty 599 - { self.$field:ident } 499 + { 500 + mode : $mode:ty, 501 + field : self.$field:ident $(,)? 502 + } 600 503 $($rest:tt)* 601 504 ) => { 602 505 // SAFETY: This implementation of `raw_get_timer` only compiles if the 603 506 // field has the right type. 604 507 unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self { 508 + type TimerMode = $mode; 605 509 606 510 #[inline] 607 511 unsafe fn raw_get_timer(
+6 -2
rust/kernel/time/hrtimer/arc.rs
··· 4 4 use super::HrTimer; 5 5 use super::HrTimerCallback; 6 6 use super::HrTimerHandle; 7 + use super::HrTimerMode; 7 8 use super::HrTimerPointer; 8 - use super::Ktime; 9 9 use super::RawHrTimerCallback; 10 10 use crate::sync::Arc; 11 11 use crate::sync::ArcBorrow; ··· 54 54 T: HasHrTimer<T>, 55 55 T: for<'a> HrTimerCallback<Pointer<'a> = Self>, 56 56 { 57 + type TimerMode = <T as HasHrTimer<T>>::TimerMode; 57 58 type TimerHandle = ArcHrTimerHandle<T>; 58 59 59 - fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> { 60 + fn start( 61 + self, 62 + expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, 63 + ) -> ArcHrTimerHandle<T> { 60 64 // SAFETY: 61 65 // - We keep `self` alive by wrapping it in a handle below. 62 66 // - Since we generate the pointer passed to `start` from a valid
+7 -3
rust/kernel/time/hrtimer/pin.rs
··· 4 4 use super::HrTimer; 5 5 use super::HrTimerCallback; 6 6 use super::HrTimerHandle; 7 - use super::Ktime; 7 + use super::HrTimerMode; 8 8 use super::RawHrTimerCallback; 9 9 use super::UnsafeHrTimerPointer; 10 10 use core::pin::Pin; ··· 54 54 T: HasHrTimer<T>, 55 55 T: HrTimerCallback<Pointer<'a> = Self>, 56 56 { 57 + type TimerMode = <T as HasHrTimer<T>>::TimerMode; 57 58 type TimerHandle = PinHrTimerHandle<'a, T>; 58 59 59 - unsafe fn start(self, expires: Ktime) -> Self::TimerHandle { 60 + unsafe fn start( 61 + self, 62 + expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, 63 + ) -> Self::TimerHandle { 60 64 // Cast to pointer 61 65 let self_ptr: *const T = self.get_ref(); 62 66 ··· 83 79 84 80 unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart { 85 81 // `HrTimer` is `repr(C)` 86 - let timer_ptr = ptr as *mut HrTimer<T>; 82 + let timer_ptr = ptr.cast::<HrTimer<T>>(); 87 83 88 84 // SAFETY: By the safety requirement of this function, `timer_ptr` 89 85 // points to a `HrTimer<T>` contained in an `T`.
+7 -3
rust/kernel/time/hrtimer/pin_mut.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 3 use super::{ 4 - HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, Ktime, RawHrTimerCallback, 4 + HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, HrTimerMode, RawHrTimerCallback, 5 5 UnsafeHrTimerPointer, 6 6 }; 7 7 use core::{marker::PhantomData, pin::Pin, ptr::NonNull}; ··· 52 52 T: HasHrTimer<T>, 53 53 T: HrTimerCallback<Pointer<'a> = Self>, 54 54 { 55 + type TimerMode = <T as HasHrTimer<T>>::TimerMode; 55 56 type TimerHandle = PinMutHrTimerHandle<'a, T>; 56 57 57 - unsafe fn start(mut self, expires: Ktime) -> Self::TimerHandle { 58 + unsafe fn start( 59 + mut self, 60 + expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, 61 + ) -> Self::TimerHandle { 58 62 // SAFETY: 59 63 // - We promise not to move out of `self`. We only pass `self` 60 64 // back to the caller as a `Pin<&mut self>`. ··· 87 83 88 84 unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart { 89 85 // `HrTimer` is `repr(C)` 90 - let timer_ptr = ptr as *mut HrTimer<T>; 86 + let timer_ptr = ptr.cast::<HrTimer<T>>(); 91 87 92 88 // SAFETY: By the safety requirement of this function, `timer_ptr` 93 89 // points to a `HrTimer<T>` contained in an `T`.
+6 -2
rust/kernel/time/hrtimer/tbox.rs
··· 4 4 use super::HrTimer; 5 5 use super::HrTimerCallback; 6 6 use super::HrTimerHandle; 7 + use super::HrTimerMode; 7 8 use super::HrTimerPointer; 8 - use super::Ktime; 9 9 use super::RawHrTimerCallback; 10 10 use crate::prelude::*; 11 11 use core::ptr::NonNull; ··· 64 64 T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>, 65 65 A: crate::alloc::Allocator, 66 66 { 67 + type TimerMode = <T as HasHrTimer<T>>::TimerMode; 67 68 type TimerHandle = BoxHrTimerHandle<T, A>; 68 69 69 - fn start(self, expires: Ktime) -> Self::TimerHandle { 70 + fn start( 71 + self, 72 + expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, 73 + ) -> Self::TimerHandle { 70 74 // SAFETY: 71 75 // - We will not move out of this box during timer callback (we pass an 72 76 // immutable reference to the callback).
+34 -195
rust/kernel/types.rs
··· 2 2 3 3 //! Kernel types. 4 4 5 + use crate::ffi::c_void; 5 6 use core::{ 6 7 cell::UnsafeCell, 7 8 marker::{PhantomData, PhantomPinned}, 8 - mem::{ManuallyDrop, MaybeUninit}, 9 + mem::MaybeUninit, 9 10 ops::{Deref, DerefMut}, 10 - ptr::NonNull, 11 11 }; 12 12 use pin_init::{PinInit, Wrapper, Zeroable}; 13 + 14 + pub use crate::sync::aref::{ARef, AlwaysRefCounted}; 13 15 14 16 /// Used to transfer ownership to and from foreign (non-Rust) languages. 15 17 /// ··· 23 21 /// 24 22 /// # Safety 25 23 /// 26 - /// Implementers must ensure that [`into_foreign`] returns a pointer which meets the alignment 27 - /// requirements of [`PointedTo`]. 28 - /// 29 - /// [`into_foreign`]: Self::into_foreign 30 - /// [`PointedTo`]: Self::PointedTo 24 + /// - Implementations must satisfy the guarantees of [`Self::into_foreign`]. 31 25 pub unsafe trait ForeignOwnable: Sized { 32 - /// Type used when the value is foreign-owned. In practical terms only defines the alignment of 33 - /// the pointer. 34 - type PointedTo; 26 + /// The alignment of pointers returned by `into_foreign`. 27 + const FOREIGN_ALIGN: usize; 35 28 36 29 /// Type used to immutably borrow a value that is currently foreign-owned. 37 30 type Borrowed<'a>; ··· 36 39 37 40 /// Converts a Rust-owned object to a foreign-owned one. 38 41 /// 42 + /// The foreign representation is a pointer to void. Aside from the guarantees listed below, 43 + /// there are no other guarantees for this pointer. For example, it might be invalid, dangling 44 + /// or pointing to uninitialized memory. Using it in any way except for [`from_foreign`], 45 + /// [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can result in undefined behavior. 46 + /// 39 47 /// # Guarantees 40 48 /// 41 - /// The return value is guaranteed to be well-aligned, but there are no other guarantees for 42 - /// this pointer. For example, it might be null, dangling, or point to uninitialized memory. 43 - /// Using it in any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], 44 - /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. 49 + /// - Minimum alignment of returned pointer is [`Self::FOREIGN_ALIGN`]. 50 + /// - The returned pointer is not null. 45 51 /// 46 52 /// [`from_foreign`]: Self::from_foreign 47 53 /// [`try_from_foreign`]: Self::try_from_foreign 48 54 /// [`borrow`]: Self::borrow 49 55 /// [`borrow_mut`]: Self::borrow_mut 50 - fn into_foreign(self) -> *mut Self::PointedTo; 56 + fn into_foreign(self) -> *mut c_void; 51 57 52 58 /// Converts a foreign-owned object back to a Rust-owned one. 53 59 /// ··· 60 60 /// must not be passed to `from_foreign` more than once. 61 61 /// 62 62 /// [`into_foreign`]: Self::into_foreign 63 - unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self; 63 + unsafe fn from_foreign(ptr: *mut c_void) -> Self; 64 64 65 65 /// Tries to convert a foreign-owned object back to a Rust-owned one. 66 66 /// ··· 72 72 /// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`]. 73 73 /// 74 74 /// [`from_foreign`]: Self::from_foreign 75 - unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option<Self> { 75 + unsafe fn try_from_foreign(ptr: *mut c_void) -> Option<Self> { 76 76 if ptr.is_null() { 77 77 None 78 78 } else { ··· 95 95 /// 96 96 /// [`into_foreign`]: Self::into_foreign 97 97 /// [`from_foreign`]: Self::from_foreign 98 - unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>; 98 + unsafe fn borrow<'a>(ptr: *mut c_void) -> Self::Borrowed<'a>; 99 99 100 100 /// Borrows a foreign-owned object mutably. 101 101 /// ··· 123 123 /// [`from_foreign`]: Self::from_foreign 124 124 /// [`borrow`]: Self::borrow 125 125 /// [`Arc`]: crate::sync::Arc 126 - unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedMut<'a>; 126 + unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a>; 127 127 } 128 128 129 - // SAFETY: The `into_foreign` function returns a pointer that is dangling, but well-aligned. 129 + // SAFETY: The pointer returned by `into_foreign` comes from a well aligned 130 + // pointer to `()`. 130 131 unsafe impl ForeignOwnable for () { 131 - type PointedTo = (); 132 + const FOREIGN_ALIGN: usize = core::mem::align_of::<()>(); 132 133 type Borrowed<'a> = (); 133 134 type BorrowedMut<'a> = (); 134 135 135 - fn into_foreign(self) -> *mut Self::PointedTo { 136 + fn into_foreign(self) -> *mut c_void { 136 137 core::ptr::NonNull::dangling().as_ptr() 137 138 } 138 139 139 - unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {} 140 + unsafe fn from_foreign(_: *mut c_void) -> Self {} 140 141 141 - unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {} 142 - unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut<'a> {} 142 + unsafe fn borrow<'a>(_: *mut c_void) -> Self::Borrowed<'a> {} 143 + unsafe fn borrow_mut<'a>(_: *mut c_void) -> Self::BorrowedMut<'a> {} 143 144 } 144 145 145 146 /// Runs a cleanup function/closure when dropped. ··· 367 366 // initialize the `T`. 368 367 unsafe { 369 368 pin_init::pin_init_from_closure::<_, ::core::convert::Infallible>(move |slot| { 370 - init_func(Self::raw_get(slot)); 369 + init_func(Self::cast_into(slot)); 371 370 Ok(()) 372 371 }) 373 372 } ··· 387 386 // SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully 388 387 // initialize the `T`. 389 388 unsafe { 390 - pin_init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot))) 389 + pin_init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::cast_into(slot))) 391 390 } 392 391 } 393 392 ··· 400 399 /// 401 400 /// This function is useful to get access to the value without creating intermediate 402 401 /// references. 403 - pub const fn raw_get(this: *const Self) -> *mut T { 402 + pub const fn cast_into(this: *const Self) -> *mut T { 404 403 UnsafeCell::raw_get(this.cast::<UnsafeCell<MaybeUninit<T>>>()).cast::<T>() 404 + } 405 + 406 + /// The opposite operation of [`Opaque::cast_into`]. 407 + pub const fn cast_from(this: *const T) -> *const Self { 408 + this.cast() 405 409 } 406 410 } 407 411 ··· 421 415 unsafe { PinInit::<T, E>::__pinned_init(slot, ptr) } 422 416 }) 423 417 } 424 - } 425 - 426 - /// Types that are _always_ reference counted. 427 - /// 428 - /// It allows such types to define their own custom ref increment and decrement functions. 429 - /// Additionally, it allows users to convert from a shared reference `&T` to an owned reference 430 - /// [`ARef<T>`]. 431 - /// 432 - /// This is usually implemented by wrappers to existing structures on the C side of the code. For 433 - /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted 434 - /// instances of a type. 435 - /// 436 - /// # Safety 437 - /// 438 - /// Implementers must ensure that increments to the reference count keep the object alive in memory 439 - /// at least until matching decrements are performed. 440 - /// 441 - /// Implementers must also ensure that all instances are reference-counted. (Otherwise they 442 - /// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object 443 - /// alive.) 444 - pub unsafe trait AlwaysRefCounted { 445 - /// Increments the reference count on the object. 446 - fn inc_ref(&self); 447 - 448 - /// Decrements the reference count on the object. 449 - /// 450 - /// Frees the object when the count reaches zero. 451 - /// 452 - /// # Safety 453 - /// 454 - /// Callers must ensure that there was a previous matching increment to the reference count, 455 - /// and that the object is no longer used after its reference count is decremented (as it may 456 - /// result in the object being freed), unless the caller owns another increment on the refcount 457 - /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls 458 - /// [`AlwaysRefCounted::dec_ref`] once). 459 - unsafe fn dec_ref(obj: NonNull<Self>); 460 - } 461 - 462 - /// An owned reference to an always-reference-counted object. 463 - /// 464 - /// The object's reference count is automatically decremented when an instance of [`ARef`] is 465 - /// dropped. It is also automatically incremented when a new instance is created via 466 - /// [`ARef::clone`]. 467 - /// 468 - /// # Invariants 469 - /// 470 - /// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In 471 - /// particular, the [`ARef`] instance owns an increment on the underlying object's reference count. 472 - pub struct ARef<T: AlwaysRefCounted> { 473 - ptr: NonNull<T>, 474 - _p: PhantomData<T>, 475 - } 476 - 477 - // SAFETY: It is safe to send `ARef<T>` to another thread when the underlying `T` is `Sync` because 478 - // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs 479 - // `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a 480 - // mutable reference, for example, when the reference count reaches zero and `T` is dropped. 481 - unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {} 482 - 483 - // SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync` 484 - // because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, 485 - // it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an 486 - // `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for 487 - // example, when the reference count reaches zero and `T` is dropped. 488 - unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {} 489 - 490 - impl<T: AlwaysRefCounted> ARef<T> { 491 - /// Creates a new instance of [`ARef`]. 492 - /// 493 - /// It takes over an increment of the reference count on the underlying object. 494 - /// 495 - /// # Safety 496 - /// 497 - /// Callers must ensure that the reference count was incremented at least once, and that they 498 - /// are properly relinquishing one increment. That is, if there is only one increment, callers 499 - /// must not use the underlying object anymore -- it is only safe to do so via the newly 500 - /// created [`ARef`]. 501 - pub unsafe fn from_raw(ptr: NonNull<T>) -> Self { 502 - // INVARIANT: The safety requirements guarantee that the new instance now owns the 503 - // increment on the refcount. 504 - Self { 505 - ptr, 506 - _p: PhantomData, 507 - } 508 - } 509 - 510 - /// Consumes the `ARef`, returning a raw pointer. 511 - /// 512 - /// This function does not change the refcount. After calling this function, the caller is 513 - /// responsible for the refcount previously managed by the `ARef`. 514 - /// 515 - /// # Examples 516 - /// 517 - /// ``` 518 - /// use core::ptr::NonNull; 519 - /// use kernel::types::{ARef, AlwaysRefCounted}; 520 - /// 521 - /// struct Empty {} 522 - /// 523 - /// # // SAFETY: TODO. 524 - /// unsafe impl AlwaysRefCounted for Empty { 525 - /// fn inc_ref(&self) {} 526 - /// unsafe fn dec_ref(_obj: NonNull<Self>) {} 527 - /// } 528 - /// 529 - /// let mut data = Empty {}; 530 - /// let ptr = NonNull::<Empty>::new(&mut data).unwrap(); 531 - /// # // SAFETY: TODO. 532 - /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) }; 533 - /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref); 534 - /// 535 - /// assert_eq!(ptr, raw_ptr); 536 - /// ``` 537 - pub fn into_raw(me: Self) -> NonNull<T> { 538 - ManuallyDrop::new(me).ptr 539 - } 540 - } 541 - 542 - impl<T: AlwaysRefCounted> Clone for ARef<T> { 543 - fn clone(&self) -> Self { 544 - self.inc_ref(); 545 - // SAFETY: We just incremented the refcount above. 546 - unsafe { Self::from_raw(self.ptr) } 547 - } 548 - } 549 - 550 - impl<T: AlwaysRefCounted> Deref for ARef<T> { 551 - type Target = T; 552 - 553 - fn deref(&self) -> &Self::Target { 554 - // SAFETY: The type invariants guarantee that the object is valid. 555 - unsafe { self.ptr.as_ref() } 556 - } 557 - } 558 - 559 - impl<T: AlwaysRefCounted> From<&T> for ARef<T> { 560 - fn from(b: &T) -> Self { 561 - b.inc_ref(); 562 - // SAFETY: We just incremented the refcount above. 563 - unsafe { Self::from_raw(NonNull::from(b)) } 564 - } 565 - } 566 - 567 - impl<T: AlwaysRefCounted> Drop for ARef<T> { 568 - fn drop(&mut self) { 569 - // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to 570 - // decrement. 571 - unsafe { T::dec_ref(self.ptr) }; 572 - } 573 - } 574 - 575 - /// A sum type that always holds either a value of type `L` or `R`. 576 - /// 577 - /// # Examples 578 - /// 579 - /// ``` 580 - /// use kernel::types::Either; 581 - /// 582 - /// let left_value: Either<i32, &str> = Either::Left(7); 583 - /// let right_value: Either<i32, &str> = Either::Right("right value"); 584 - /// ``` 585 - pub enum Either<L, R> { 586 - /// Constructs an instance of [`Either`] containing a value of type `L`. 587 - Left(L), 588 - 589 - /// Constructs an instance of [`Either`] containing a value of type `R`. 590 - Right(R), 591 418 } 592 419 593 420 /// Zero-sized type to mark types not [`Send`].
+153 -14
rust/kernel/uaccess.rs
··· 8 8 alloc::{Allocator, Flags}, 9 9 bindings, 10 10 error::Result, 11 - ffi::c_void, 11 + ffi::{c_char, c_void}, 12 12 prelude::*, 13 13 transmute::{AsBytes, FromBytes}, 14 14 }; 15 15 use core::mem::{size_of, MaybeUninit}; 16 16 17 - /// The type used for userspace addresses. 18 - pub type UserPtr = usize; 17 + /// A pointer into userspace. 18 + /// 19 + /// This is the Rust equivalent to C pointers tagged with `__user`. 20 + #[repr(transparent)] 21 + #[derive(Copy, Clone)] 22 + pub struct UserPtr(*mut c_void); 23 + 24 + impl UserPtr { 25 + /// Create a `UserPtr` from an integer representing the userspace address. 26 + #[inline] 27 + pub fn from_addr(addr: usize) -> Self { 28 + Self(addr as *mut c_void) 29 + } 30 + 31 + /// Create a `UserPtr` from a pointer representing the userspace address. 32 + #[inline] 33 + pub fn from_ptr(addr: *mut c_void) -> Self { 34 + Self(addr) 35 + } 36 + 37 + /// Cast this userspace pointer to a raw const void pointer. 38 + /// 39 + /// It is up to the caller to use the returned pointer correctly. 40 + #[inline] 41 + pub fn as_const_ptr(self) -> *const c_void { 42 + self.0 43 + } 44 + 45 + /// Cast this userspace pointer to a raw mutable void pointer. 46 + /// 47 + /// It is up to the caller to use the returned pointer correctly. 48 + #[inline] 49 + pub fn as_mut_ptr(self) -> *mut c_void { 50 + self.0 51 + } 52 + 53 + /// Increment this user pointer by `add` bytes. 54 + /// 55 + /// This addition is wrapping, so wrapping around the address space does not result in a panic 56 + /// even if `CONFIG_RUST_OVERFLOW_CHECKS` is enabled. 57 + #[inline] 58 + pub fn wrapping_byte_add(self, add: usize) -> UserPtr { 59 + UserPtr(self.0.wrapping_byte_add(add)) 60 + } 61 + } 19 62 20 63 /// A pointer to an area in userspace memory, which can be either read-only or read-write. 21 64 /// ··· 220 177 pub fn skip(&mut self, num_skip: usize) -> Result { 221 178 // Update `self.length` first since that's the fallible part of this operation. 222 179 self.length = self.length.checked_sub(num_skip).ok_or(EFAULT)?; 223 - self.ptr = self.ptr.wrapping_add(num_skip); 180 + self.ptr = self.ptr.wrapping_byte_add(num_skip); 224 181 Ok(()) 225 182 } 226 183 ··· 267 224 } 268 225 // SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write 269 226 // that many bytes to it. 270 - let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) }; 227 + let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr.as_const_ptr(), len) }; 271 228 if res != 0 { 272 229 return Err(EFAULT); 273 230 } 274 - self.ptr = self.ptr.wrapping_add(len); 231 + self.ptr = self.ptr.wrapping_byte_add(len); 275 232 self.length -= len; 276 233 Ok(()) 277 234 } ··· 283 240 pub fn read_slice(&mut self, out: &mut [u8]) -> Result { 284 241 // SAFETY: The types are compatible and `read_raw` doesn't write uninitialized bytes to 285 242 // `out`. 286 - let out = unsafe { &mut *(out as *mut [u8] as *mut [MaybeUninit<u8>]) }; 243 + let out = unsafe { &mut *(core::ptr::from_mut(out) as *mut [MaybeUninit<u8>]) }; 287 244 self.read_raw(out) 288 245 } 289 246 ··· 305 262 let res = unsafe { 306 263 bindings::_copy_from_user( 307 264 out.as_mut_ptr().cast::<c_void>(), 308 - self.ptr as *const c_void, 265 + self.ptr.as_const_ptr(), 309 266 len, 310 267 ) 311 268 }; 312 269 if res != 0 { 313 270 return Err(EFAULT); 314 271 } 315 - self.ptr = self.ptr.wrapping_add(len); 272 + self.ptr = self.ptr.wrapping_byte_add(len); 316 273 self.length -= len; 317 274 // SAFETY: The read above has initialized all bytes in `out`, and since `T` implements 318 275 // `FromBytes`, any bit-pattern is a valid value for this type. ··· 333 290 // vector have been initialized. 334 291 unsafe { buf.inc_len(len) }; 335 292 Ok(()) 293 + } 294 + 295 + /// Read a NUL-terminated string from userspace and return it. 296 + /// 297 + /// The string is read into `buf` and a NUL-terminator is added if the end of `buf` is reached. 298 + /// Since there must be space to add a NUL-terminator, the buffer must not be empty. The 299 + /// returned `&CStr` points into `buf`. 300 + /// 301 + /// Fails with [`EFAULT`] if the read happens on a bad address (some data may have been 302 + /// copied). 303 + #[doc(alias = "strncpy_from_user")] 304 + pub fn strcpy_into_buf<'buf>(self, buf: &'buf mut [u8]) -> Result<&'buf CStr> { 305 + if buf.is_empty() { 306 + return Err(EINVAL); 307 + } 308 + 309 + // SAFETY: The types are compatible and `strncpy_from_user` doesn't write uninitialized 310 + // bytes to `buf`. 311 + let mut dst = unsafe { &mut *(core::ptr::from_mut(buf) as *mut [MaybeUninit<u8>]) }; 312 + 313 + // We never read more than `self.length` bytes. 314 + if dst.len() > self.length { 315 + dst = &mut dst[..self.length]; 316 + } 317 + 318 + let mut len = raw_strncpy_from_user(dst, self.ptr)?; 319 + if len < dst.len() { 320 + // Add one to include the NUL-terminator. 321 + len += 1; 322 + } else if len < buf.len() { 323 + // This implies that `len == dst.len() < buf.len()`. 324 + // 325 + // This means that we could not fill the entire buffer, but we had to stop reading 326 + // because we hit the `self.length` limit of this `UserSliceReader`. Since we did not 327 + // fill the buffer, we treat this case as if we tried to read past the `self.length` 328 + // limit and received a page fault, which is consistent with other `UserSliceReader` 329 + // methods that also return page faults when you exceed `self.length`. 330 + return Err(EFAULT); 331 + } else { 332 + // This implies that `len == buf.len()`. 333 + // 334 + // This means that we filled the buffer exactly. In this case, we add a NUL-terminator 335 + // and return it. Unlike the `len < dst.len()` branch, don't modify `len` because it 336 + // already represents the length including the NUL-terminator. 337 + // 338 + // SAFETY: Due to the check at the beginning, the buffer is not empty. 339 + unsafe { *buf.last_mut().unwrap_unchecked() = 0 }; 340 + } 341 + 342 + // This method consumes `self`, so it can only be called once, thus we do not need to 343 + // update `self.length`. This sidesteps concerns such as whether `self.length` should be 344 + // incremented by `len` or `len-1` in the `len == buf.len()` case. 345 + 346 + // SAFETY: There are two cases: 347 + // * If we hit the `len < dst.len()` case, then `raw_strncpy_from_user` guarantees that 348 + // this slice contains exactly one NUL byte at the end of the string. 349 + // * Otherwise, `raw_strncpy_from_user` guarantees that the string contained no NUL bytes, 350 + // and we have since added a NUL byte at the end. 351 + Ok(unsafe { CStr::from_bytes_with_nul_unchecked(&buf[..len]) }) 336 352 } 337 353 } 338 354 ··· 429 327 } 430 328 // SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read 431 329 // that many bytes from it. 432 - let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) }; 330 + let res = unsafe { bindings::copy_to_user(self.ptr.as_mut_ptr(), data_ptr, len) }; 433 331 if res != 0 { 434 332 return Err(EFAULT); 435 333 } 436 - self.ptr = self.ptr.wrapping_add(len); 334 + self.ptr = self.ptr.wrapping_byte_add(len); 437 335 self.length -= len; 438 336 Ok(()) 439 337 } ··· 456 354 // is a compile-time constant. 457 355 let res = unsafe { 458 356 bindings::_copy_to_user( 459 - self.ptr as *mut c_void, 460 - (value as *const T).cast::<c_void>(), 357 + self.ptr.as_mut_ptr(), 358 + core::ptr::from_ref(value).cast::<c_void>(), 461 359 len, 462 360 ) 463 361 }; 464 362 if res != 0 { 465 363 return Err(EFAULT); 466 364 } 467 - self.ptr = self.ptr.wrapping_add(len); 365 + self.ptr = self.ptr.wrapping_byte_add(len); 468 366 self.length -= len; 469 367 Ok(()) 470 368 } 369 + } 370 + 371 + /// Reads a nul-terminated string into `dst` and returns the length. 372 + /// 373 + /// This reads from userspace until a NUL byte is encountered, or until `dst.len()` bytes have been 374 + /// read. Fails with [`EFAULT`] if a read happens on a bad address (some data may have been 375 + /// copied). When the end of the buffer is encountered, no NUL byte is added, so the string is 376 + /// *not* guaranteed to be NUL-terminated when `Ok(dst.len())` is returned. 377 + /// 378 + /// # Guarantees 379 + /// 380 + /// When this function returns `Ok(len)`, it is guaranteed that the first `len` bytes of `dst` are 381 + /// initialized and non-zero. Furthermore, if `len < dst.len()`, then `dst[len]` is a NUL byte. 382 + #[inline] 383 + fn raw_strncpy_from_user(dst: &mut [MaybeUninit<u8>], src: UserPtr) -> Result<usize> { 384 + // CAST: Slice lengths are guaranteed to be `<= isize::MAX`. 385 + let len = dst.len() as isize; 386 + 387 + // SAFETY: `dst` is valid for writing `dst.len()` bytes. 388 + let res = unsafe { 389 + bindings::strncpy_from_user( 390 + dst.as_mut_ptr().cast::<c_char>(), 391 + src.as_const_ptr().cast::<c_char>(), 392 + len, 393 + ) 394 + }; 395 + 396 + if res < 0 { 397 + return Err(Error::from_errno(res as i32)); 398 + } 399 + 400 + #[cfg(CONFIG_RUST_OVERFLOW_CHECKS)] 401 + assert!(res <= len); 402 + 403 + // GUARANTEES: `strncpy_from_user` was successful, so `dst` has contents in accordance with the 404 + // guarantees of this function. 405 + Ok(res as usize) 471 406 }
+333 -9
rust/kernel/workqueue.rs
··· 26 26 //! * The [`WorkItemPointer`] trait is implemented for the pointer type that points at a something 27 27 //! that implements [`WorkItem`]. 28 28 //! 29 - //! ## Example 29 + //! ## Examples 30 30 //! 31 31 //! This example defines a struct that holds an integer and can be scheduled on the workqueue. When 32 32 //! the struct is executed, it will print the integer. Since there is only one `work_struct` field, ··· 131 131 //! # print_2_later(MyStruct::new(41, 42).unwrap()); 132 132 //! ``` 133 133 //! 134 + //! This example shows how you can schedule delayed work items: 135 + //! 136 + //! ``` 137 + //! use kernel::sync::Arc; 138 + //! use kernel::workqueue::{self, impl_has_delayed_work, new_delayed_work, DelayedWork, WorkItem}; 139 + //! 140 + //! #[pin_data] 141 + //! struct MyStruct { 142 + //! value: i32, 143 + //! #[pin] 144 + //! work: DelayedWork<MyStruct>, 145 + //! } 146 + //! 147 + //! impl_has_delayed_work! { 148 + //! impl HasDelayedWork<Self> for MyStruct { self.work } 149 + //! } 150 + //! 151 + //! impl MyStruct { 152 + //! fn new(value: i32) -> Result<Arc<Self>> { 153 + //! Arc::pin_init( 154 + //! pin_init!(MyStruct { 155 + //! value, 156 + //! work <- new_delayed_work!("MyStruct::work"), 157 + //! }), 158 + //! GFP_KERNEL, 159 + //! ) 160 + //! } 161 + //! } 162 + //! 163 + //! impl WorkItem for MyStruct { 164 + //! type Pointer = Arc<MyStruct>; 165 + //! 166 + //! fn run(this: Arc<MyStruct>) { 167 + //! pr_info!("The value is: {}\n", this.value); 168 + //! } 169 + //! } 170 + //! 171 + //! /// This method will enqueue the struct for execution on the system workqueue, where its value 172 + //! /// will be printed 12 jiffies later. 173 + //! fn print_later(val: Arc<MyStruct>) { 174 + //! let _ = workqueue::system().enqueue_delayed(val, 12); 175 + //! } 176 + //! 177 + //! /// It is also possible to use the ordinary `enqueue` method together with `DelayedWork`. This 178 + //! /// is equivalent to calling `enqueue_delayed` with a delay of zero. 179 + //! fn print_now(val: Arc<MyStruct>) { 180 + //! let _ = workqueue::system().enqueue(val); 181 + //! } 182 + //! # print_later(MyStruct::new(42).unwrap()); 183 + //! # print_now(MyStruct::new(42).unwrap()); 184 + //! ``` 185 + //! 134 186 //! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h) 135 187 136 - use crate::alloc::{AllocError, Flags}; 137 - use crate::{prelude::*, sync::Arc, sync::LockClassKey, types::Opaque}; 188 + use crate::{ 189 + alloc::{AllocError, Flags}, 190 + container_of, 191 + prelude::*, 192 + sync::Arc, 193 + sync::LockClassKey, 194 + time::Jiffies, 195 + types::Opaque, 196 + }; 138 197 use core::marker::PhantomData; 139 198 140 199 /// Creates a [`Work`] initialiser with the given name and a newly-created lock class. ··· 204 145 }; 205 146 } 206 147 pub use new_work; 148 + 149 + /// Creates a [`DelayedWork`] initialiser with the given name and a newly-created lock class. 150 + #[macro_export] 151 + macro_rules! new_delayed_work { 152 + () => { 153 + $crate::workqueue::DelayedWork::new( 154 + $crate::optional_name!(), 155 + $crate::static_lock_class!(), 156 + $crate::c_str!(::core::concat!( 157 + ::core::file!(), 158 + ":", 159 + ::core::line!(), 160 + "_timer" 161 + )), 162 + $crate::static_lock_class!(), 163 + ) 164 + }; 165 + ($name:literal) => { 166 + $crate::workqueue::DelayedWork::new( 167 + $crate::c_str!($name), 168 + $crate::static_lock_class!(), 169 + $crate::c_str!(::core::concat!($name, "_timer")), 170 + $crate::static_lock_class!(), 171 + ) 172 + }; 173 + } 174 + pub use new_delayed_work; 207 175 208 176 /// A kernel work queue. 209 177 /// ··· 256 170 pub unsafe fn from_raw<'a>(ptr: *const bindings::workqueue_struct) -> &'a Queue { 257 171 // SAFETY: The `Queue` type is `#[repr(transparent)]`, so the pointer cast is valid. The 258 172 // caller promises that the pointer is not dangling. 259 - unsafe { &*(ptr as *const Queue) } 173 + unsafe { &*ptr.cast::<Queue>() } 260 174 } 261 175 262 176 /// Enqueues a work item. ··· 284 198 unsafe { 285 199 w.__enqueue(move |work_ptr| { 286 200 bindings::queue_work_on( 287 - bindings::wq_misc_consts_WORK_CPU_UNBOUND as _, 201 + bindings::wq_misc_consts_WORK_CPU_UNBOUND as ffi::c_int, 288 202 queue_ptr, 289 203 work_ptr, 204 + ) 205 + }) 206 + } 207 + } 208 + 209 + /// Enqueues a delayed work item. 210 + /// 211 + /// This may fail if the work item is already enqueued in a workqueue. 212 + /// 213 + /// The work item will be submitted using `WORK_CPU_UNBOUND`. 214 + pub fn enqueue_delayed<W, const ID: u64>(&self, w: W, delay: Jiffies) -> W::EnqueueOutput 215 + where 216 + W: RawDelayedWorkItem<ID> + Send + 'static, 217 + { 218 + let queue_ptr = self.0.get(); 219 + 220 + // SAFETY: We only return `false` if the `work_struct` is already in a workqueue. The other 221 + // `__enqueue` requirements are not relevant since `W` is `Send` and static. 222 + // 223 + // The call to `bindings::queue_delayed_work_on` will dereference the provided raw pointer, 224 + // which is ok because `__enqueue` guarantees that the pointer is valid for the duration of 225 + // this closure, and the safety requirements of `RawDelayedWorkItem` expands this 226 + // requirement to apply to the entire `delayed_work`. 227 + // 228 + // Furthermore, if the C workqueue code accesses the pointer after this call to 229 + // `__enqueue`, then the work item was successfully enqueued, and 230 + // `bindings::queue_delayed_work_on` will have returned true. In this case, `__enqueue` 231 + // promises that the raw pointer will stay valid until we call the function pointer in the 232 + // `work_struct`, so the access is ok. 233 + unsafe { 234 + w.__enqueue(move |work_ptr| { 235 + bindings::queue_delayed_work_on( 236 + bindings::wq_misc_consts_WORK_CPU_UNBOUND as ffi::c_int, 237 + queue_ptr, 238 + container_of!(work_ptr, bindings::delayed_work, work), 239 + delay, 290 240 ) 291 241 }) 292 242 } ··· 419 297 where 420 298 F: FnOnce(*mut bindings::work_struct) -> bool; 421 299 } 300 + 301 + /// A raw delayed work item. 302 + /// 303 + /// # Safety 304 + /// 305 + /// If the `__enqueue` method in the `RawWorkItem` implementation calls the closure, then the 306 + /// provided pointer must point at the `work` field of a valid `delayed_work`, and the guarantees 307 + /// that `__enqueue` provides about accessing the `work_struct` must also apply to the rest of the 308 + /// `delayed_work` struct. 309 + pub unsafe trait RawDelayedWorkItem<const ID: u64>: RawWorkItem<ID> {} 422 310 423 311 /// Defines the method that should be called directly when a work item is executed. 424 312 /// ··· 535 403 // 536 404 // A pointer cast would also be ok due to `#[repr(transparent)]`. We use `addr_of!` so that 537 405 // the compiler does not complain that the `work` field is unused. 538 - unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).work)) } 406 + unsafe { Opaque::cast_into(core::ptr::addr_of!((*ptr).work)) } 539 407 } 540 408 } 541 409 542 - /// Declares that a type has a [`Work<T, ID>`] field. 410 + /// Declares that a type contains a [`Work<T, ID>`]. 543 411 /// 544 412 /// The intended way of using this trait is via the [`impl_has_work!`] macro. You can use the macro 545 413 /// like this: ··· 638 506 impl{T} HasWork<Self> for ClosureWork<T> { self.work } 639 507 } 640 508 509 + /// Links for a delayed work item. 510 + /// 511 + /// This struct contains a function pointer to the [`run`] function from the [`WorkItemPointer`] 512 + /// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue in 513 + /// a delayed manner. 514 + /// 515 + /// Wraps the kernel's C `struct delayed_work`. 516 + /// 517 + /// This is a helper type used to associate a `delayed_work` with the [`WorkItem`] that uses it. 518 + /// 519 + /// [`run`]: WorkItemPointer::run 520 + #[pin_data] 521 + #[repr(transparent)] 522 + pub struct DelayedWork<T: ?Sized, const ID: u64 = 0> { 523 + #[pin] 524 + dwork: Opaque<bindings::delayed_work>, 525 + _inner: PhantomData<T>, 526 + } 527 + 528 + // SAFETY: Kernel work items are usable from any thread. 529 + // 530 + // We do not need to constrain `T` since the work item does not actually contain a `T`. 531 + unsafe impl<T: ?Sized, const ID: u64> Send for DelayedWork<T, ID> {} 532 + // SAFETY: Kernel work items are usable from any thread. 533 + // 534 + // We do not need to constrain `T` since the work item does not actually contain a `T`. 535 + unsafe impl<T: ?Sized, const ID: u64> Sync for DelayedWork<T, ID> {} 536 + 537 + impl<T: ?Sized, const ID: u64> DelayedWork<T, ID> { 538 + /// Creates a new instance of [`DelayedWork`]. 539 + #[inline] 540 + pub fn new( 541 + work_name: &'static CStr, 542 + work_key: Pin<&'static LockClassKey>, 543 + timer_name: &'static CStr, 544 + timer_key: Pin<&'static LockClassKey>, 545 + ) -> impl PinInit<Self> 546 + where 547 + T: WorkItem<ID>, 548 + { 549 + pin_init!(Self { 550 + dwork <- Opaque::ffi_init(|slot: *mut bindings::delayed_work| { 551 + // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as 552 + // the work item function. 553 + unsafe { 554 + bindings::init_work_with_key( 555 + core::ptr::addr_of_mut!((*slot).work), 556 + Some(T::Pointer::run), 557 + false, 558 + work_name.as_char_ptr(), 559 + work_key.as_ptr(), 560 + ) 561 + } 562 + 563 + // SAFETY: The `delayed_work_timer_fn` function pointer can be used here because 564 + // the timer is embedded in a `struct delayed_work`, and only ever scheduled via 565 + // the core workqueue code, and configured to run in irqsafe context. 566 + unsafe { 567 + bindings::timer_init_key( 568 + core::ptr::addr_of_mut!((*slot).timer), 569 + Some(bindings::delayed_work_timer_fn), 570 + bindings::TIMER_IRQSAFE, 571 + timer_name.as_char_ptr(), 572 + timer_key.as_ptr(), 573 + ) 574 + } 575 + }), 576 + _inner: PhantomData, 577 + }) 578 + } 579 + 580 + /// Get a pointer to the inner `delayed_work`. 581 + /// 582 + /// # Safety 583 + /// 584 + /// The provided pointer must not be dangling and must be properly aligned. (But the memory 585 + /// need not be initialized.) 586 + #[inline] 587 + pub unsafe fn raw_as_work(ptr: *const Self) -> *mut Work<T, ID> { 588 + // SAFETY: The caller promises that the pointer is aligned and not dangling. 589 + let dw: *mut bindings::delayed_work = 590 + unsafe { Opaque::cast_into(core::ptr::addr_of!((*ptr).dwork)) }; 591 + // SAFETY: The caller promises that the pointer is aligned and not dangling. 592 + let wrk: *mut bindings::work_struct = unsafe { core::ptr::addr_of_mut!((*dw).work) }; 593 + // CAST: Work and work_struct have compatible layouts. 594 + wrk.cast() 595 + } 596 + } 597 + 598 + /// Declares that a type contains a [`DelayedWork<T, ID>`]. 599 + /// 600 + /// # Safety 601 + /// 602 + /// The `HasWork<T, ID>` implementation must return a `work_struct` that is stored in the `work` 603 + /// field of a `delayed_work` with the same access rules as the `work_struct`. 604 + pub unsafe trait HasDelayedWork<T, const ID: u64 = 0>: HasWork<T, ID> {} 605 + 606 + /// Used to safely implement the [`HasDelayedWork<T, ID>`] trait. 607 + /// 608 + /// This macro also implements the [`HasWork`] trait, so you do not need to use [`impl_has_work!`] 609 + /// when using this macro. 610 + /// 611 + /// # Examples 612 + /// 613 + /// ``` 614 + /// use kernel::sync::Arc; 615 + /// use kernel::workqueue::{self, impl_has_delayed_work, DelayedWork}; 616 + /// 617 + /// struct MyStruct<'a, T, const N: usize> { 618 + /// work_field: DelayedWork<MyStruct<'a, T, N>, 17>, 619 + /// f: fn(&'a [T; N]), 620 + /// } 621 + /// 622 + /// impl_has_delayed_work! { 623 + /// impl{'a, T, const N: usize} HasDelayedWork<MyStruct<'a, T, N>, 17> 624 + /// for MyStruct<'a, T, N> { self.work_field } 625 + /// } 626 + /// ``` 627 + #[macro_export] 628 + macro_rules! impl_has_delayed_work { 629 + ($(impl$({$($generics:tt)*})? 630 + HasDelayedWork<$work_type:ty $(, $id:tt)?> 631 + for $self:ty 632 + { self.$field:ident } 633 + )*) => {$( 634 + // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right 635 + // type. 636 + unsafe impl$(<$($generics)+>)? 637 + $crate::workqueue::HasDelayedWork<$work_type $(, $id)?> for $self {} 638 + 639 + // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right 640 + // type. 641 + unsafe impl$(<$($generics)+>)? $crate::workqueue::HasWork<$work_type $(, $id)?> for $self { 642 + #[inline] 643 + unsafe fn raw_get_work( 644 + ptr: *mut Self 645 + ) -> *mut $crate::workqueue::Work<$work_type $(, $id)?> { 646 + // SAFETY: The caller promises that the pointer is not dangling. 647 + let ptr: *mut $crate::workqueue::DelayedWork<$work_type $(, $id)?> = unsafe { 648 + ::core::ptr::addr_of_mut!((*ptr).$field) 649 + }; 650 + 651 + // SAFETY: The caller promises that the pointer is not dangling. 652 + unsafe { $crate::workqueue::DelayedWork::raw_as_work(ptr) } 653 + } 654 + 655 + #[inline] 656 + unsafe fn work_container_of( 657 + ptr: *mut $crate::workqueue::Work<$work_type $(, $id)?>, 658 + ) -> *mut Self { 659 + // SAFETY: The caller promises that the pointer points at a field of the right type 660 + // in the right kind of struct. 661 + let ptr = unsafe { $crate::workqueue::Work::raw_get(ptr) }; 662 + 663 + // SAFETY: The caller promises that the pointer points at a field of the right type 664 + // in the right kind of struct. 665 + let delayed_work = unsafe { 666 + $crate::container_of!(ptr, $crate::bindings::delayed_work, work) 667 + }; 668 + 669 + let delayed_work: *mut $crate::workqueue::DelayedWork<$work_type $(, $id)?> = 670 + delayed_work.cast(); 671 + 672 + // SAFETY: The caller promises that the pointer points at a field of the right type 673 + // in the right kind of struct. 674 + unsafe { $crate::container_of!(delayed_work, Self, $field) } 675 + } 676 + } 677 + )*}; 678 + } 679 + pub use impl_has_delayed_work; 680 + 641 681 // SAFETY: The `__enqueue` implementation in RawWorkItem uses a `work_struct` initialized with the 642 682 // `run` method of this trait as the function pointer because: 643 683 // - `__enqueue` gets the `work_struct` from the `Work` field, using `T::raw_get_work`. ··· 826 522 { 827 523 unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { 828 524 // The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. 829 - let ptr = ptr as *mut Work<T, ID>; 525 + let ptr = ptr.cast::<Work<T, ID>>(); 830 526 // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. 831 527 let ptr = unsafe { T::work_container_of(ptr) }; 832 528 // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership. ··· 871 567 } 872 568 } 873 569 570 + // SAFETY: By the safety requirements of `HasDelayedWork`, the `work_struct` returned by methods in 571 + // `HasWork` provides a `work_struct` that is the `work` field of a `delayed_work`, and the rest of 572 + // the `delayed_work` has the same access rules as its `work` field. 573 + unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Arc<T> 574 + where 575 + T: WorkItem<ID, Pointer = Self>, 576 + T: HasDelayedWork<T, ID>, 577 + { 578 + } 579 + 874 580 // SAFETY: TODO. 875 581 unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<KBox<T>> 876 582 where ··· 889 575 { 890 576 unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { 891 577 // The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`. 892 - let ptr = ptr as *mut Work<T, ID>; 578 + let ptr = ptr.cast::<Work<T, ID>>(); 893 579 // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. 894 580 let ptr = unsafe { T::work_container_of(ptr) }; 895 581 // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership. ··· 929 615 unsafe { ::core::hint::unreachable_unchecked() } 930 616 } 931 617 } 618 + } 619 + 620 + // SAFETY: By the safety requirements of `HasDelayedWork`, the `work_struct` returned by methods in 621 + // `HasWork` provides a `work_struct` that is the `work` field of a `delayed_work`, and the rest of 622 + // the `delayed_work` has the same access rules as its `work` field. 623 + unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Pin<KBox<T>> 624 + where 625 + T: WorkItem<ID, Pointer = Self>, 626 + T: HasDelayedWork<T, ID>, 627 + { 932 628 } 933 629 934 630 /// Returns the system work queue (`system_wq`).
+5 -4
rust/kernel/xarray.rs
··· 7 7 use crate::{ 8 8 alloc, bindings, build_assert, 9 9 error::{Error, Result}, 10 + ffi::c_void, 10 11 types::{ForeignOwnable, NotThreadSafe, Opaque}, 11 12 }; 12 - use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull}; 13 + use core::{iter, marker::PhantomData, pin::Pin, ptr::NonNull}; 13 14 use pin_init::{pin_data, pin_init, pinned_drop, PinInit}; 14 15 15 16 /// An array which efficiently maps sparse integer indices to owned objects. ··· 102 101 }) 103 102 } 104 103 105 - fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_ { 104 + fn iter(&self) -> impl Iterator<Item = NonNull<c_void>> + '_ { 106 105 let mut index = 0; 107 106 108 107 // SAFETY: `self.xa` is always valid by the type invariant. ··· 180 179 impl<'a, T: ForeignOwnable> Guard<'a, T> { 181 180 fn load<F, U>(&self, index: usize, f: F) -> Option<U> 182 181 where 183 - F: FnOnce(NonNull<T::PointedTo>) -> U, 182 + F: FnOnce(NonNull<c_void>) -> U, 184 183 { 185 184 // SAFETY: `self.xa.xa` is always valid by the type invariant. 186 185 let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) }; ··· 231 230 gfp: alloc::Flags, 232 231 ) -> Result<Option<T>, StoreError<T>> { 233 232 build_assert!( 234 - mem::align_of::<T::PointedTo>() >= 4, 233 + T::FOREIGN_ALIGN >= 4, 235 234 "pointers stored in XArray must be 4-byte aligned" 236 235 ); 237 236 let new = value.into_foreign();
-6
rust/macros/module.rs
··· 94 94 type_: String, 95 95 license: String, 96 96 name: String, 97 - author: Option<String>, 98 97 authors: Option<Vec<String>>, 99 98 description: Option<String>, 100 99 alias: Option<Vec<String>>, ··· 107 108 const EXPECTED_KEYS: &[&str] = &[ 108 109 "type", 109 110 "name", 110 - "author", 111 111 "authors", 112 112 "description", 113 113 "license", ··· 132 134 match key.as_str() { 133 135 "type" => info.type_ = expect_ident(it), 134 136 "name" => info.name = expect_string_ascii(it), 135 - "author" => info.author = Some(expect_string(it)), 136 137 "authors" => info.authors = Some(expect_string_array(it)), 137 138 "description" => info.description = Some(expect_string(it)), 138 139 "license" => info.license = expect_string_ascii(it), ··· 176 179 // Rust does not allow hyphens in identifiers, use underscore instead. 177 180 let ident = info.name.replace('-', "_"); 178 181 let mut modinfo = ModInfoBuilder::new(ident.as_ref()); 179 - if let Some(author) = info.author { 180 - modinfo.emit("author", &author); 181 - } 182 182 if let Some(authors) = info.authors { 183 183 for author in authors { 184 184 modinfo.emit("author", &author);
+1 -1
rust/pin-init/README.md
··· 125 125 fn new() -> impl PinInit<Self, Error> { 126 126 try_pin_init!(Self { 127 127 status <- CMutex::new(0), 128 - buffer: Box::init(pin_init::zeroed())?, 128 + buffer: Box::init(pin_init::init_zeroed())?, 129 129 }? Error) 130 130 } 131 131 }
+16 -12
rust/pin-init/examples/big_struct_in_place.rs
··· 4 4 5 5 // Struct with size over 1GiB 6 6 #[derive(Debug)] 7 + #[allow(dead_code)] 7 8 pub struct BigStruct { 8 9 buf: [u8; 1024 * 1024 * 1024], 9 10 a: u64, ··· 21 20 22 21 impl ManagedBuf { 23 22 pub fn new() -> impl Init<Self> { 24 - init!(ManagedBuf { buf <- zeroed() }) 23 + init!(ManagedBuf { buf <- init_zeroed() }) 25 24 } 26 25 } 27 26 28 27 fn main() { 29 - // we want to initialize the struct in-place, otherwise we would get a stackoverflow 30 - let buf: Box<BigStruct> = Box::init(init!(BigStruct { 31 - buf <- zeroed(), 32 - a: 7, 33 - b: 186, 34 - c: 7789, 35 - d: 34, 36 - managed_buf <- ManagedBuf::new(), 37 - })) 38 - .unwrap(); 39 - println!("{}", core::mem::size_of_val(&*buf)); 28 + #[cfg(any(feature = "std", feature = "alloc"))] 29 + { 30 + // we want to initialize the struct in-place, otherwise we would get a stackoverflow 31 + let buf: Box<BigStruct> = Box::init(init!(BigStruct { 32 + buf <- init_zeroed(), 33 + a: 7, 34 + b: 186, 35 + c: 7789, 36 + d: 34, 37 + managed_buf <- ManagedBuf::new(), 38 + })) 39 + .unwrap(); 40 + println!("{}", core::mem::size_of_val(&*buf)); 41 + } 40 42 }
+9 -1
rust/pin-init/examples/linked_list.rs
··· 14 14 15 15 use pin_init::*; 16 16 17 - #[expect(unused_attributes)] 17 + #[allow(unused_attributes)] 18 18 mod error; 19 + #[allow(unused_imports)] 19 20 use error::Error; 20 21 21 22 #[pin_data(PinnedDrop)] ··· 40 39 } 41 40 42 41 #[inline] 42 + #[allow(dead_code)] 43 43 pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ { 44 44 try_pin_init!(&this in Self { 45 45 prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}), ··· 114 112 } 115 113 116 114 #[inline] 115 + #[allow(dead_code)] 117 116 fn prev(&self) -> &Link { 118 117 unsafe { &(*self.0.get().as_ptr()).prev } 119 118 } ··· 141 138 } 142 139 143 140 #[allow(dead_code)] 141 + #[cfg(not(any(feature = "std", feature = "alloc")))] 142 + fn main() {} 143 + 144 + #[allow(dead_code)] 144 145 #[cfg_attr(test, test)] 146 + #[cfg(any(feature = "std", feature = "alloc"))] 145 147 fn main() -> Result<(), Error> { 146 148 let a = Box::pin_init(ListHead::new())?; 147 149 stack_pin_init!(let b = ListHead::insert_next(&a));
+56 -41
rust/pin-init/examples/mutex.rs
··· 12 12 pin::Pin, 13 13 sync::atomic::{AtomicBool, Ordering}, 14 14 }; 15 + #[cfg(feature = "std")] 15 16 use std::{ 16 17 sync::Arc, 17 - thread::{self, park, sleep, Builder, Thread}, 18 + thread::{self, sleep, Builder, Thread}, 18 19 time::Duration, 19 20 }; 20 21 21 22 use pin_init::*; 22 - #[expect(unused_attributes)] 23 + #[allow(unused_attributes)] 23 24 #[path = "./linked_list.rs"] 24 25 pub mod linked_list; 25 26 use linked_list::*; ··· 37 36 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) 38 37 .is_err() 39 38 { 39 + #[cfg(feature = "std")] 40 40 while self.inner.load(Ordering::Relaxed) { 41 41 thread::yield_now(); 42 42 } ··· 96 94 // println!("wait list length: {}", self.wait_list.size()); 97 95 while self.locked.get() { 98 96 drop(sguard); 99 - park(); 97 + #[cfg(feature = "std")] 98 + thread::park(); 100 99 sguard = self.spin_lock.acquire(); 101 100 } 102 101 // This does have an effect, as the ListHead inside wait_entry implements Drop! ··· 134 131 let sguard = self.mtx.spin_lock.acquire(); 135 132 self.mtx.locked.set(false); 136 133 if let Some(list_field) = self.mtx.wait_list.next() { 137 - let wait_entry = list_field.as_ptr().cast::<WaitEntry>(); 138 - unsafe { (*wait_entry).thread.unpark() }; 134 + let _wait_entry = list_field.as_ptr().cast::<WaitEntry>(); 135 + #[cfg(feature = "std")] 136 + unsafe { 137 + (*_wait_entry).thread.unpark() 138 + }; 139 139 } 140 140 drop(sguard); 141 141 } ··· 165 159 struct WaitEntry { 166 160 #[pin] 167 161 wait_list: ListHead, 162 + #[cfg(feature = "std")] 168 163 thread: Thread, 169 164 } 170 165 171 166 impl WaitEntry { 172 167 #[inline] 173 168 fn insert_new(list: &ListHead) -> impl PinInit<Self> + '_ { 174 - pin_init!(Self { 175 - thread: thread::current(), 176 - wait_list <- ListHead::insert_prev(list), 177 - }) 169 + #[cfg(feature = "std")] 170 + { 171 + pin_init!(Self { 172 + thread: thread::current(), 173 + wait_list <- ListHead::insert_prev(list), 174 + }) 175 + } 176 + #[cfg(not(feature = "std"))] 177 + { 178 + pin_init!(Self { 179 + wait_list <- ListHead::insert_prev(list), 180 + }) 181 + } 178 182 } 179 183 } 180 184 181 - #[cfg(not(any(feature = "std", feature = "alloc")))] 182 - fn main() {} 183 - 184 - #[allow(dead_code)] 185 185 #[cfg_attr(test, test)] 186 - #[cfg(any(feature = "std", feature = "alloc"))] 186 + #[allow(dead_code)] 187 187 fn main() { 188 - let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); 189 - let mut handles = vec![]; 190 - let thread_count = 20; 191 - let workload = if cfg!(miri) { 100 } else { 1_000 }; 192 - for i in 0..thread_count { 193 - let mtx = mtx.clone(); 194 - handles.push( 195 - Builder::new() 196 - .name(format!("worker #{i}")) 197 - .spawn(move || { 198 - for _ in 0..workload { 199 - *mtx.lock() += 1; 200 - } 201 - println!("{i} halfway"); 202 - sleep(Duration::from_millis((i as u64) * 10)); 203 - for _ in 0..workload { 204 - *mtx.lock() += 1; 205 - } 206 - println!("{i} finished"); 207 - }) 208 - .expect("should not fail"), 209 - ); 188 + #[cfg(feature = "std")] 189 + { 190 + let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); 191 + let mut handles = vec![]; 192 + let thread_count = 20; 193 + let workload = if cfg!(miri) { 100 } else { 1_000 }; 194 + for i in 0..thread_count { 195 + let mtx = mtx.clone(); 196 + handles.push( 197 + Builder::new() 198 + .name(format!("worker #{i}")) 199 + .spawn(move || { 200 + for _ in 0..workload { 201 + *mtx.lock() += 1; 202 + } 203 + println!("{i} halfway"); 204 + sleep(Duration::from_millis((i as u64) * 10)); 205 + for _ in 0..workload { 206 + *mtx.lock() += 1; 207 + } 208 + println!("{i} finished"); 209 + }) 210 + .expect("should not fail"), 211 + ); 212 + } 213 + for h in handles { 214 + h.join().expect("thread panicked"); 215 + } 216 + println!("{:?}", &*mtx.lock()); 217 + assert_eq!(*mtx.lock(), workload * thread_count * 2); 210 218 } 211 - for h in handles { 212 - h.join().expect("thread panicked"); 213 - } 214 - println!("{:?}", &*mtx.lock()); 215 - assert_eq!(*mtx.lock(), workload * thread_count * 2); 216 219 }
+4
rust/pin-init/examples/pthread_mutex.rs
··· 44 44 pub enum Error { 45 45 #[allow(dead_code)] 46 46 IO(std::io::Error), 47 + #[allow(dead_code)] 47 48 Alloc, 48 49 } 49 50 ··· 62 61 } 63 62 64 63 impl<T> PThreadMutex<T> { 64 + #[allow(dead_code)] 65 65 pub fn new(data: T) -> impl PinInit<Self, Error> { 66 66 fn init_raw() -> impl PinInit<UnsafeCell<libc::pthread_mutex_t>, Error> { 67 67 let init = |slot: *mut UnsafeCell<libc::pthread_mutex_t>| { ··· 105 103 }? Error) 106 104 } 107 105 106 + #[allow(dead_code)] 108 107 pub fn lock(&self) -> PThreadMutexGuard<'_, T> { 109 108 // SAFETY: raw is always initialized 110 109 unsafe { libc::pthread_mutex_lock(self.raw.get()) }; ··· 140 137 } 141 138 142 139 #[cfg_attr(test, test)] 140 + #[cfg_attr(all(test, miri), ignore)] 143 141 fn main() { 144 142 #[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))] 145 143 {
+38 -37
rust/pin-init/examples/static_init.rs
··· 3 3 #![allow(clippy::undocumented_unsafe_blocks)] 4 4 #![cfg_attr(feature = "alloc", feature(allocator_api))] 5 5 #![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))] 6 + #![allow(unused_imports)] 6 7 7 8 use core::{ 8 9 cell::{Cell, UnsafeCell}, ··· 13 12 time::Duration, 14 13 }; 15 14 use pin_init::*; 15 + #[cfg(feature = "std")] 16 16 use std::{ 17 17 sync::Arc, 18 18 thread::{sleep, Builder}, 19 19 }; 20 20 21 - #[expect(unused_attributes)] 21 + #[allow(unused_attributes)] 22 22 mod mutex; 23 23 use mutex::*; 24 24 ··· 84 82 85 83 pub static COUNT: StaticInit<CMutex<usize>, CountInit> = StaticInit::new(CountInit); 86 84 87 - #[cfg(not(any(feature = "std", feature = "alloc")))] 88 - fn main() {} 89 - 90 - #[cfg(any(feature = "std", feature = "alloc"))] 91 85 fn main() { 92 - let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); 93 - let mut handles = vec![]; 94 - let thread_count = 20; 95 - let workload = 1_000; 96 - for i in 0..thread_count { 97 - let mtx = mtx.clone(); 98 - handles.push( 99 - Builder::new() 100 - .name(format!("worker #{i}")) 101 - .spawn(move || { 102 - for _ in 0..workload { 103 - *COUNT.lock() += 1; 104 - std::thread::sleep(std::time::Duration::from_millis(10)); 105 - *mtx.lock() += 1; 106 - std::thread::sleep(std::time::Duration::from_millis(10)); 107 - *COUNT.lock() += 1; 108 - } 109 - println!("{i} halfway"); 110 - sleep(Duration::from_millis((i as u64) * 10)); 111 - for _ in 0..workload { 112 - std::thread::sleep(std::time::Duration::from_millis(10)); 113 - *mtx.lock() += 1; 114 - } 115 - println!("{i} finished"); 116 - }) 117 - .expect("should not fail"), 118 - ); 86 + #[cfg(feature = "std")] 87 + { 88 + let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap(); 89 + let mut handles = vec![]; 90 + let thread_count = 20; 91 + let workload = 1_000; 92 + for i in 0..thread_count { 93 + let mtx = mtx.clone(); 94 + handles.push( 95 + Builder::new() 96 + .name(format!("worker #{i}")) 97 + .spawn(move || { 98 + for _ in 0..workload { 99 + *COUNT.lock() += 1; 100 + std::thread::sleep(std::time::Duration::from_millis(10)); 101 + *mtx.lock() += 1; 102 + std::thread::sleep(std::time::Duration::from_millis(10)); 103 + *COUNT.lock() += 1; 104 + } 105 + println!("{i} halfway"); 106 + sleep(Duration::from_millis((i as u64) * 10)); 107 + for _ in 0..workload { 108 + std::thread::sleep(std::time::Duration::from_millis(10)); 109 + *mtx.lock() += 1; 110 + } 111 + println!("{i} finished"); 112 + }) 113 + .expect("should not fail"), 114 + ); 115 + } 116 + for h in handles { 117 + h.join().expect("thread panicked"); 118 + } 119 + println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock()); 120 + assert_eq!(*mtx.lock(), workload * thread_count * 2); 119 121 } 120 - for h in handles { 121 - h.join().expect("thread panicked"); 122 - } 123 - println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock()); 124 - assert_eq!(*mtx.lock(), workload * thread_count * 2); 125 122 }
+1
rust/pin-init/src/__internal.rs
··· 188 188 } 189 189 190 190 #[test] 191 + #[cfg(feature = "std")] 191 192 fn stack_init_reuse() { 192 193 use ::std::{borrow::ToOwned, println, string::String}; 193 194 use core::pin::pin;
+104 -16
rust/pin-init/src/lib.rs
··· 148 148 //! fn new() -> impl PinInit<Self, Error> { 149 149 //! try_pin_init!(Self { 150 150 //! status <- CMutex::new(0), 151 - //! buffer: Box::init(pin_init::zeroed())?, 151 + //! buffer: Box::init(pin_init::init_zeroed())?, 152 152 //! }? Error) 153 153 //! } 154 154 //! } ··· 742 742 /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. 743 743 /// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`] 744 744 /// pointer named `this` inside of the initializer. 745 - /// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the 745 + /// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the 746 746 /// struct, this initializes every field with 0 and then runs all initializers specified in the 747 747 /// body. This can only be done if [`Zeroable`] is implemented for the struct. 748 748 /// ··· 769 769 /// }); 770 770 /// let init = pin_init!(Buf { 771 771 /// buf: [1; 64], 772 - /// ..Zeroable::zeroed() 772 + /// ..Zeroable::init_zeroed() 773 773 /// }); 774 774 /// ``` 775 775 /// ··· 805 805 /// ```rust 806 806 /// # #![feature(allocator_api)] 807 807 /// # #[path = "../examples/error.rs"] mod error; use error::Error; 808 - /// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed}; 808 + /// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed}; 809 809 /// 810 810 /// #[pin_data] 811 811 /// struct BigBuf { ··· 817 817 /// impl BigBuf { 818 818 /// fn new() -> impl PinInit<Self, Error> { 819 819 /// try_pin_init!(Self { 820 - /// big: Box::init(zeroed())?, 820 + /// big: Box::init(init_zeroed())?, 821 821 /// small: [0; 1024 * 1024], 822 822 /// ptr: core::ptr::null_mut(), 823 823 /// }? Error) ··· 866 866 /// # #[path = "../examples/error.rs"] mod error; use error::Error; 867 867 /// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*; 868 868 /// # use pin_init::InPlaceInit; 869 - /// use pin_init::{init, Init, zeroed}; 869 + /// use pin_init::{init, Init, init_zeroed}; 870 870 /// 871 871 /// struct BigBuf { 872 872 /// small: [u8; 1024 * 1024], ··· 875 875 /// impl BigBuf { 876 876 /// fn new() -> impl Init<Self> { 877 877 /// init!(Self { 878 - /// small <- zeroed(), 878 + /// small <- init_zeroed(), 879 879 /// }) 880 880 /// } 881 881 /// } ··· 913 913 /// # #![feature(allocator_api)] 914 914 /// # use core::alloc::AllocError; 915 915 /// # use pin_init::InPlaceInit; 916 - /// use pin_init::{try_init, Init, zeroed}; 916 + /// use pin_init::{try_init, Init, init_zeroed}; 917 917 /// 918 918 /// struct BigBuf { 919 919 /// big: Box<[u8; 1024 * 1024 * 1024]>, ··· 923 923 /// impl BigBuf { 924 924 /// fn new() -> impl Init<Self, AllocError> { 925 925 /// try_init!(Self { 926 - /// big: Box::init(zeroed())?, 926 + /// big: Box::init(init_zeroed())?, 927 927 /// small: [0; 1024 * 1024], 928 928 /// }? AllocError) 929 929 /// } ··· 953 953 /// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is 954 954 /// structurally pinned. 955 955 /// 956 - /// # Example 956 + /// # Examples 957 957 /// 958 958 /// This will succeed: 959 959 /// ``` ··· 1170 1170 /// 1171 1171 /// ```rust 1172 1172 /// # #![expect(clippy::disallowed_names)] 1173 - /// use pin_init::{init, zeroed, Init}; 1173 + /// use pin_init::{init, init_zeroed, Init}; 1174 1174 /// 1175 1175 /// struct Foo { 1176 1176 /// buf: [u8; 1_000_000], ··· 1183 1183 /// } 1184 1184 /// 1185 1185 /// let foo = init!(Foo { 1186 - /// buf <- zeroed() 1186 + /// buf <- init_zeroed() 1187 1187 /// }).chain(|foo| { 1188 1188 /// foo.setup(); 1189 1189 /// Ok(()) ··· 1495 1495 /// ```rust,ignore 1496 1496 /// let val: Self = unsafe { core::mem::zeroed() }; 1497 1497 /// ``` 1498 - pub unsafe trait Zeroable {} 1498 + pub unsafe trait Zeroable { 1499 + /// Create a new zeroed `Self`. 1500 + /// 1501 + /// The returned initializer will write `0x00` to every byte of the given `slot`. 1502 + #[inline] 1503 + fn init_zeroed() -> impl Init<Self> 1504 + where 1505 + Self: Sized, 1506 + { 1507 + init_zeroed() 1508 + } 1509 + 1510 + /// Create a `Self` consisting of all zeroes. 1511 + /// 1512 + /// Whenever a type implements [`Zeroable`], this function should be preferred over 1513 + /// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`. 1514 + /// 1515 + /// # Examples 1516 + /// 1517 + /// ``` 1518 + /// use pin_init::{Zeroable, zeroed}; 1519 + /// 1520 + /// #[derive(Zeroable)] 1521 + /// struct Point { 1522 + /// x: u32, 1523 + /// y: u32, 1524 + /// } 1525 + /// 1526 + /// let point: Point = zeroed(); 1527 + /// assert_eq!(point.x, 0); 1528 + /// assert_eq!(point.y, 0); 1529 + /// ``` 1530 + fn zeroed() -> Self 1531 + where 1532 + Self: Sized, 1533 + { 1534 + zeroed() 1535 + } 1536 + } 1499 1537 1500 1538 /// Marker trait for types that allow `Option<Self>` to be set to all zeroes in order to write 1501 1539 /// `None` to that location. ··· 1546 1508 // SAFETY: by the safety requirement of `ZeroableOption`, this is valid. 1547 1509 unsafe impl<T: ZeroableOption> Zeroable for Option<T> {} 1548 1510 1549 - /// Create a new zeroed T. 1511 + // SAFETY: `Option<&T>` is part of the option layout optimization guarantee: 1512 + // <https://doc.rust-lang.org/stable/std/option/index.html#representation>. 1513 + unsafe impl<T> ZeroableOption for &T {} 1514 + // SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee: 1515 + // <https://doc.rust-lang.org/stable/std/option/index.html#representation>. 1516 + unsafe impl<T> ZeroableOption for &mut T {} 1517 + // SAFETY: `Option<NonNull<T>>` is part of the option layout optimization guarantee: 1518 + // <https://doc.rust-lang.org/stable/std/option/index.html#representation>. 1519 + unsafe impl<T> ZeroableOption for NonNull<T> {} 1520 + 1521 + /// Create an initializer for a zeroed `T`. 1550 1522 /// 1551 1523 /// The returned initializer will write `0x00` to every byte of the given `slot`. 1552 1524 #[inline] 1553 - pub fn zeroed<T: Zeroable>() -> impl Init<T> { 1525 + pub fn init_zeroed<T: Zeroable>() -> impl Init<T> { 1554 1526 // SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T` 1555 1527 // and because we write all zeroes, the memory is initialized. 1556 1528 unsafe { ··· 1569 1521 Ok(()) 1570 1522 }) 1571 1523 } 1524 + } 1525 + 1526 + /// Create a `T` consisting of all zeroes. 1527 + /// 1528 + /// Whenever a type implements [`Zeroable`], this function should be preferred over 1529 + /// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`. 1530 + /// 1531 + /// # Examples 1532 + /// 1533 + /// ``` 1534 + /// use pin_init::{Zeroable, zeroed}; 1535 + /// 1536 + /// #[derive(Zeroable)] 1537 + /// struct Point { 1538 + /// x: u32, 1539 + /// y: u32, 1540 + /// } 1541 + /// 1542 + /// let point: Point = zeroed(); 1543 + /// assert_eq!(point.x, 0); 1544 + /// assert_eq!(point.y, 0); 1545 + /// ``` 1546 + pub const fn zeroed<T: Zeroable>() -> T { 1547 + // SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`. 1548 + unsafe { core::mem::zeroed() } 1572 1549 } 1573 1550 1574 1551 macro_rules! impl_zeroable { ··· 1633 1560 Option<NonZeroU128>, Option<NonZeroUsize>, 1634 1561 Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>, 1635 1562 Option<NonZeroI128>, Option<NonZeroIsize>, 1636 - {<T>} Option<NonNull<T>>, 1637 1563 1638 1564 // SAFETY: `null` pointer is valid. 1639 1565 // ··· 1661 1589 } 1662 1590 1663 1591 impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); 1592 + 1593 + macro_rules! impl_fn_zeroable_option { 1594 + ([$($abi:literal),* $(,)?] $args:tt) => { 1595 + $(impl_fn_zeroable_option!({extern $abi} $args);)* 1596 + $(impl_fn_zeroable_option!({unsafe extern $abi} $args);)* 1597 + }; 1598 + ({$($prefix:tt)*} {$(,)?}) => {}; 1599 + ({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => { 1600 + // SAFETY: function pointers are part of the option layout optimization: 1601 + // <https://doc.rust-lang.org/stable/std/option/index.html#representation>. 1602 + unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {} 1603 + impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,}); 1604 + }; 1605 + } 1606 + 1607 + impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U }); 1664 1608 1665 1609 /// This trait allows creating an instance of `Self` which contains exactly one 1666 1610 /// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
+8 -8
rust/pin-init/src/macros.rs
··· 1030 1030 /// 1031 1031 /// This macro has multiple internal call configurations, these are always the very first ident: 1032 1032 /// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros. 1033 - /// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled. 1033 + /// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax has been handled. 1034 1034 /// - `init_slot`: recursively creates the code that initializes all fields in `slot`. 1035 1035 /// - `make_initializer`: recursively create the struct initializer that guarantees that every 1036 1036 /// field has been initialized exactly once. ··· 1059 1059 @data($data, $($use_data)?), 1060 1060 @has_data($has_data, $get_data), 1061 1061 @construct_closure($construct_closure), 1062 - @zeroed(), // Nothing means default behavior. 1062 + @init_zeroed(), // Nothing means default behavior. 1063 1063 ) 1064 1064 }; 1065 1065 ( ··· 1074 1074 @has_data($has_data:ident, $get_data:ident), 1075 1075 // `pin_init_from_closure` or `init_from_closure`. 1076 1076 @construct_closure($construct_closure:ident), 1077 - @munch_fields(..Zeroable::zeroed()), 1077 + @munch_fields(..Zeroable::init_zeroed()), 1078 1078 ) => { 1079 1079 $crate::__init_internal!(with_update_parsed: 1080 1080 @this($($this)?), ··· 1084 1084 @data($data, $($use_data)?), 1085 1085 @has_data($has_data, $get_data), 1086 1086 @construct_closure($construct_closure), 1087 - @zeroed(()), // `()` means zero all fields not mentioned. 1087 + @init_zeroed(()), // `()` means zero all fields not mentioned. 1088 1088 ) 1089 1089 }; 1090 1090 ( ··· 1124 1124 @has_data($has_data:ident, $get_data:ident), 1125 1125 // `pin_init_from_closure` or `init_from_closure`. 1126 1126 @construct_closure($construct_closure:ident), 1127 - @zeroed($($init_zeroed:expr)?), 1127 + @init_zeroed($($init_zeroed:expr)?), 1128 1128 ) => {{ 1129 1129 // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return 1130 1130 // type and shadow it later when we insert the arbitrary user code. That way there will be ··· 1196 1196 @data($data:ident), 1197 1197 @slot($slot:ident), 1198 1198 @guards($($guards:ident,)*), 1199 - @munch_fields($(..Zeroable::zeroed())? $(,)?), 1199 + @munch_fields($(..Zeroable::init_zeroed())? $(,)?), 1200 1200 ) => { 1201 1201 // Endpoint of munching, no fields are left. If execution reaches this point, all fields 1202 1202 // have been initialized. Therefore we can now dismiss the guards by forgetting them. ··· 1300 1300 (make_initializer: 1301 1301 @slot($slot:ident), 1302 1302 @type_name($t:path), 1303 - @munch_fields(..Zeroable::zeroed() $(,)?), 1303 + @munch_fields(..Zeroable::init_zeroed() $(,)?), 1304 1304 @acc($($acc:tt)*), 1305 1305 ) => { 1306 1306 // Endpoint, nothing more to munch, create the initializer. Since the users specified 1307 - // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have 1307 + // `..Zeroable::init_zeroed()`, the slot will already have been zeroed and all field that have 1308 1308 // not been overwritten are thus zero and initialized. We still check that all fields are 1309 1309 // actually accessible by using the struct update syntax ourselves. 1310 1310 // We are inside of a closure that is never executed and thus we can abuse `slot` to
+3
rust/uapi/lib.rs
··· 14 14 #![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))] 15 15 #![allow( 16 16 clippy::all, 17 + clippy::cast_lossless, 18 + clippy::ptr_as_ptr, 19 + clippy::ref_as_ptr, 17 20 clippy::undocumented_unsafe_blocks, 18 21 dead_code, 19 22 missing_docs,
+4 -5
samples/Kconfig
··· 54 54 measures the time taken to invoke one function a number of times. 55 55 56 56 config SAMPLE_TRACE_ARRAY 57 - tristate "Build sample module for kernel access to Ftrace instancess" 57 + tristate "Build sample module for kernel access to Ftrace instances" 58 58 depends on EVENT_TRACING && m 59 59 help 60 60 This builds a module that demonstrates the use of various APIs to ··· 316 316 depends on DETECT_HUNG_TASK && DEBUG_FS 317 317 help 318 318 Build a module that provides debugfs files (e.g., mutex, semaphore, 319 - etc.) under <debugfs>/hung_task. If user reads one of these files, 320 - it will sleep long time (256 seconds) with holding a lock. Thus, 321 - if 2 or more processes read the same file concurrently, it will 322 - be detected by the hung_task watchdog. 319 + rw_semaphore_read, rw_semaphore_write) under <debugfs>/hung_task. 320 + Reading these files with multiple processes triggers hung task 321 + detection by holding locks for a long time (256 seconds). 323 322 324 323 source "samples/rust/Kconfig" 325 324
+74 -7
samples/hung_task/hung_task_tests.c
··· 4 4 * semaphore, etc. 5 5 * 6 6 * Usage: Load this module and read `<debugfs>/hung_task/mutex`, 7 - * `<debugfs>/hung_task/semaphore`, etc., with 2 or more processes. 7 + * `<debugfs>/hung_task/semaphore`, `<debugfs>/hung_task/rw_semaphore_read`, 8 + * `<debugfs>/hung_task/rw_semaphore_write`, etc., with 2 or more processes. 8 9 * 9 10 * This is for testing kernel hung_task error messages with various locking 10 - * mechanisms (e.g., mutex, semaphore, etc.). Note that this may freeze 11 - * your system or cause a panic. Use only for testing purposes. 11 + * mechanisms (e.g., mutex, semaphore, rw_semaphore_read, rw_semaphore_write, etc.). 12 + * Note that this may freeze your system or cause a panic. Use only for testing purposes. 12 13 */ 13 14 14 15 #include <linux/debugfs.h> ··· 18 17 #include <linux/module.h> 19 18 #include <linux/mutex.h> 20 19 #include <linux/semaphore.h> 20 + #include <linux/rwsem.h> 21 21 22 - #define HUNG_TASK_DIR "hung_task" 23 - #define HUNG_TASK_MUTEX_FILE "mutex" 24 - #define HUNG_TASK_SEM_FILE "semaphore" 25 - #define SLEEP_SECOND 256 22 + #define HUNG_TASK_DIR "hung_task" 23 + #define HUNG_TASK_MUTEX_FILE "mutex" 24 + #define HUNG_TASK_SEM_FILE "semaphore" 25 + #define HUNG_TASK_RWSEM_READ_FILE "rw_semaphore_read" 26 + #define HUNG_TASK_RWSEM_WRITE_FILE "rw_semaphore_write" 27 + #define SLEEP_SECOND 256 26 28 27 29 static const char dummy_string[] = "This is a dummy string."; 28 30 static DEFINE_MUTEX(dummy_mutex); 29 31 static DEFINE_SEMAPHORE(dummy_sem, 1); 32 + static DECLARE_RWSEM(dummy_rwsem); 30 33 static struct dentry *hung_task_dir; 31 34 32 35 /* Mutex-based read function */ 33 36 static ssize_t read_dummy_mutex(struct file *file, char __user *user_buf, 34 37 size_t count, loff_t *ppos) 35 38 { 39 + /* Check if data is already read */ 40 + if (*ppos >= sizeof(dummy_string)) 41 + return 0; 42 + 36 43 /* Second task waits on mutex, entering uninterruptible sleep */ 37 44 guard(mutex)(&dummy_mutex); 38 45 ··· 55 46 static ssize_t read_dummy_semaphore(struct file *file, char __user *user_buf, 56 47 size_t count, loff_t *ppos) 57 48 { 49 + /* Check if data is already read */ 50 + if (*ppos >= sizeof(dummy_string)) 51 + return 0; 52 + 58 53 /* Second task waits on semaphore, entering uninterruptible sleep */ 59 54 down(&dummy_sem); 60 55 ··· 66 53 msleep_interruptible(SLEEP_SECOND * 1000); 67 54 68 55 up(&dummy_sem); 56 + 57 + return simple_read_from_buffer(user_buf, count, ppos, dummy_string, 58 + sizeof(dummy_string)); 59 + } 60 + 61 + /* Read-write semaphore read function */ 62 + static ssize_t read_dummy_rwsem_read(struct file *file, char __user *user_buf, 63 + size_t count, loff_t *ppos) 64 + { 65 + /* Check if data is already read */ 66 + if (*ppos >= sizeof(dummy_string)) 67 + return 0; 68 + 69 + /* Acquires read lock, allowing concurrent readers but blocks if write lock is held */ 70 + down_read(&dummy_rwsem); 71 + 72 + /* Sleeps here, potentially triggering hung task detection if lock is held too long */ 73 + msleep_interruptible(SLEEP_SECOND * 1000); 74 + 75 + up_read(&dummy_rwsem); 76 + 77 + return simple_read_from_buffer(user_buf, count, ppos, dummy_string, 78 + sizeof(dummy_string)); 79 + } 80 + 81 + /* Read-write semaphore write function */ 82 + static ssize_t read_dummy_rwsem_write(struct file *file, char __user *user_buf, 83 + size_t count, loff_t *ppos) 84 + { 85 + /* Check if data is already read */ 86 + if (*ppos >= sizeof(dummy_string)) 87 + return 0; 88 + 89 + /* Acquires exclusive write lock, blocking all other readers and writers */ 90 + down_write(&dummy_rwsem); 91 + 92 + /* Sleeps here, potentially triggering hung task detection if lock is held too long */ 93 + msleep_interruptible(SLEEP_SECOND * 1000); 94 + 95 + up_write(&dummy_rwsem); 69 96 70 97 return simple_read_from_buffer(user_buf, count, ppos, dummy_string, 71 98 sizeof(dummy_string)); ··· 121 68 .read = read_dummy_semaphore, 122 69 }; 123 70 71 + /* File operations for rw_semaphore read */ 72 + static const struct file_operations hung_task_rwsem_read_fops = { 73 + .read = read_dummy_rwsem_read, 74 + }; 75 + 76 + /* File operations for rw_semaphore write */ 77 + static const struct file_operations hung_task_rwsem_write_fops = { 78 + .read = read_dummy_rwsem_write, 79 + }; 80 + 124 81 static int __init hung_task_tests_init(void) 125 82 { 126 83 hung_task_dir = debugfs_create_dir(HUNG_TASK_DIR, NULL); ··· 142 79 &hung_task_mutex_fops); 143 80 debugfs_create_file(HUNG_TASK_SEM_FILE, 0400, hung_task_dir, NULL, 144 81 &hung_task_sem_fops); 82 + debugfs_create_file(HUNG_TASK_RWSEM_READ_FILE, 0400, hung_task_dir, NULL, 83 + &hung_task_rwsem_read_fops); 84 + debugfs_create_file(HUNG_TASK_RWSEM_WRITE_FILE, 0400, hung_task_dir, NULL, 85 + &hung_task_rwsem_write_fops); 145 86 146 87 return 0; 147 88 }
+1 -1
samples/rust/rust_configfs.rs
··· 14 14 module! { 15 15 type: RustConfigfs, 16 16 name: "rust_configfs", 17 - author: "Rust for Linux Contributors", 17 + authors: ["Rust for Linux Contributors"], 18 18 description: "Rust configfs sample", 19 19 license: "GPL", 20 20 }
+1 -1
samples/rust/rust_driver_auxiliary.rs
··· 113 113 module! { 114 114 type: SampleModule, 115 115 name: "rust_driver_auxiliary", 116 - author: "Danilo Krummrich", 116 + authors: ["Danilo Krummrich"], 117 117 description: "Rust auxiliary driver", 118 118 license: "GPL v2", 119 119 }
+2
samples/rust/rust_misc_device.rs
··· 176 176 fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize) -> Result<isize> { 177 177 dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n"); 178 178 179 + // Treat the ioctl argument as a user pointer. 180 + let arg = UserPtr::from_addr(arg); 179 181 let size = _IOC_SIZE(cmd); 180 182 181 183 match cmd {
+1 -1
samples/rust/rust_print_main.rs
··· 40 40 // behaviour, contract or protocol on both `i32` and `&str` into a single `Arc` of 41 41 // type `Arc<dyn Display>`. 42 42 43 - use core::fmt::Display; 43 + use kernel::fmt::Display; 44 44 fn arc_dyn_print(arc: &Arc<dyn Display>) { 45 45 pr_info!("Arc<dyn Display> says {arc}"); 46 46 }
+3 -2
scripts/Makefile.build
··· 309 309 # The features in this list are the ones allowed for non-`rust/` code. 310 310 # 311 311 # - Stable since Rust 1.81.0: `feature(lint_reasons)`. 312 - # - Stable since Rust 1.82.0: `feature(asm_const)`, `feature(raw_ref_op)`. 312 + # - Stable since Rust 1.82.0: `feature(asm_const)`, 313 + # `feature(offset_of_nested)`, `feature(raw_ref_op)`. 313 314 # - Stable since Rust 1.87.0: `feature(asm_goto)`. 314 315 # - Expected to become stable: `feature(arbitrary_self_types)`. 315 316 # - To be determined: `feature(used_with_arg)`. 316 317 # 317 318 # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on 318 319 # the unstable features in use. 319 - rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,raw_ref_op,used_with_arg 320 + rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg 320 321 321 322 # `--out-dir` is required to avoid temporaries being created by `rustc` in the 322 323 # current working directory, which may be not accessible in the out-of-tree
+31 -2
scripts/checkpatch.pl
··· 685 685 [\.\!:\s]* 686 686 )}; 687 687 688 + # Device ID types like found in include/linux/mod_devicetable.h. 689 + our $dev_id_types = qr{\b[a-z]\w*_device_id\b}; 690 + 688 691 sub edit_distance_min { 689 692 my (@arr) = @_; 690 693 my $len = scalar @arr; ··· 3503 3500 # Check for various typo / spelling mistakes 3504 3501 if (defined($misspellings) && 3505 3502 ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { 3506 - while ($rawline =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) { 3503 + my $rawline_utf8 = decode("utf8", $rawline); 3504 + while ($rawline_utf8 =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) { 3507 3505 my $typo = $1; 3508 - my $blank = copy_spacing($rawline); 3506 + my $blank = copy_spacing($rawline_utf8); 3509 3507 my $ptr = substr($blank, 0, $-[1]) . "^" x length($typo); 3510 3508 my $hereptr = "$hereline$ptr\n"; 3511 3509 my $typo_fix = $spelling_fix{lc($typo)}; ··· 7691 7687 if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { 7692 7688 WARN("DUPLICATED_SYSCTL_CONST", 7693 7689 "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); 7690 + } 7691 + 7692 + # Check that *_device_id tables have sentinel entries. 7693 + if (defined $stat && $line =~ /struct\s+$dev_id_types\s+\w+\s*\[\s*\]\s*=\s*\{/) { 7694 + my $stripped = $stat; 7695 + 7696 + # Strip diff line prefixes. 7697 + $stripped =~ s/(^|\n)./$1/g; 7698 + # Line continuations. 7699 + $stripped =~ s/\\\n/\n/g; 7700 + # Strip whitespace, empty strings, zeroes, and commas. 7701 + $stripped =~ s/""//g; 7702 + $stripped =~ s/0x0//g; 7703 + $stripped =~ s/[\s$;,0]//g; 7704 + # Strip field assignments. 7705 + $stripped =~ s/\.$Ident=//g; 7706 + 7707 + if (!(substr($stripped, -4) eq "{}};" || 7708 + substr($stripped, -6) eq "{{}}};" || 7709 + $stripped =~ /ISAPNP_DEVICE_SINGLE_END}};$/ || 7710 + $stripped =~ /ISAPNP_CARD_END}};$/ || 7711 + $stripped =~ /NULL};$/ || 7712 + $stripped =~ /PCMCIA_DEVICE_NULL};$/)) { 7713 + ERROR("MISSING_SENTINEL", "missing sentinel in ID array\n" . "$here\n$stat\n"); 7714 + } 7694 7715 } 7695 7716 } 7696 7717
+44 -5
scripts/coccinelle/misc/secs_to_jiffies.cocci
··· 7 7 // Confidence: High 8 8 // Copyright: (C) 2024 Easwar Hariharan, Microsoft 9 9 // Keywords: secs, seconds, jiffies 10 - // 10 + // Options: --include-headers 11 11 12 12 virtual patch 13 + virtual report 14 + virtual context 13 15 14 - @depends on patch@ constant C; @@ 16 + @pconst depends on patch@ constant C; @@ 15 17 16 18 - msecs_to_jiffies(C * 1000) 17 19 + secs_to_jiffies(C) 18 20 19 - @depends on patch@ constant C; @@ 21 + @pconstms depends on patch@ constant C; @@ 20 22 21 23 - msecs_to_jiffies(C * MSEC_PER_SEC) 22 24 + secs_to_jiffies(C) 23 25 24 - @depends on patch@ expression E; @@ 26 + @pexpr depends on patch@ expression E; @@ 25 27 26 28 - msecs_to_jiffies(E * 1000) 27 29 + secs_to_jiffies(E) 28 30 29 - @depends on patch@ expression E; @@ 31 + @pexprms depends on patch@ expression E; @@ 30 32 31 33 - msecs_to_jiffies(E * MSEC_PER_SEC) 32 34 + secs_to_jiffies(E) 35 + 36 + @r depends on report && !patch@ 37 + constant C; 38 + expression E; 39 + position p; 40 + @@ 41 + 42 + ( 43 + msecs_to_jiffies(C@p * 1000) 44 + | 45 + msecs_to_jiffies(C@p * MSEC_PER_SEC) 46 + | 47 + msecs_to_jiffies(E@p * 1000) 48 + | 49 + msecs_to_jiffies(E@p * MSEC_PER_SEC) 50 + ) 51 + 52 + @c depends on context && !patch@ 53 + constant C; 54 + expression E; 55 + @@ 56 + 57 + ( 58 + * msecs_to_jiffies(C * 1000) 59 + | 60 + * msecs_to_jiffies(C * MSEC_PER_SEC) 61 + | 62 + * msecs_to_jiffies(E * 1000) 63 + | 64 + * msecs_to_jiffies(E * MSEC_PER_SEC) 65 + ) 66 + 67 + @script:python depends on report@ 68 + p << r.p; 69 + @@ 70 + 71 + coccilib.report.print_report(p[0], "WARNING opportunity for secs_to_jiffies()")
+6 -7
scripts/extract-vmlinux
··· 12 12 13 13 check_vmlinux() 14 14 { 15 - # Use readelf to check if it's a valid ELF 16 - # TODO: find a better to way to check that it's really vmlinux 17 - # and not just an elf 18 - readelf -h $1 > /dev/null 2>&1 || return 1 19 - 20 - cat $1 21 - exit 0 15 + if file "$1" | grep -q 'Linux kernel.*boot executable' || 16 + readelf -h "$1" > /dev/null 2>&1 17 + then 18 + cat "$1" 19 + exit 0 20 + fi 22 21 } 23 22 24 23 try_decompress()
+6 -6
scripts/gdb/linux/constants.py.in
··· 74 74 LX_GDBPARSED(MOD_RO_AFTER_INIT) 75 75 76 76 /* linux/mount.h */ 77 - LX_VALUE(MNT_NOSUID) 78 - LX_VALUE(MNT_NODEV) 79 - LX_VALUE(MNT_NOEXEC) 80 - LX_VALUE(MNT_NOATIME) 81 - LX_VALUE(MNT_NODIRATIME) 82 - LX_VALUE(MNT_RELATIME) 77 + LX_GDBPARSED(MNT_NOSUID) 78 + LX_GDBPARSED(MNT_NODEV) 79 + LX_GDBPARSED(MNT_NOEXEC) 80 + LX_GDBPARSED(MNT_NOATIME) 81 + LX_GDBPARSED(MNT_NODIRATIME) 82 + LX_GDBPARSED(MNT_RELATIME) 83 83 84 84 /* linux/threads.h */ 85 85 LX_VALUE(NR_CPUS)
+1 -1
scripts/gendwarfksyms/cache.c
··· 15 15 { 16 16 struct cache_item *ci; 17 17 18 - ci = xmalloc(sizeof(struct cache_item)); 18 + ci = xmalloc(sizeof(*ci)); 19 19 ci->key = key; 20 20 ci->value = value; 21 21 hash_add(cache->cache, &ci->hash, hash_32(key));
+2 -2
scripts/gendwarfksyms/die.c
··· 33 33 { 34 34 struct die *cd; 35 35 36 - cd = xmalloc(sizeof(struct die)); 36 + cd = xmalloc(sizeof(*cd)); 37 37 init_die(cd); 38 38 cd->addr = (uintptr_t)die->addr; 39 39 ··· 123 123 { 124 124 struct die_fragment *df; 125 125 126 - df = xmalloc(sizeof(struct die_fragment)); 126 + df = xmalloc(sizeof(*df)); 127 127 df->type = FRAGMENT_EMPTY; 128 128 list_add_tail(&df->list, &cd->fragments); 129 129 return df;
+1 -1
scripts/gendwarfksyms/dwarf.c
··· 634 634 * Note that the user of this feature is responsible for ensuring 635 635 * that the structure actually remains ABI compatible. 636 636 */ 637 - memset(&state.kabi, 0, sizeof(struct kabi_state)); 637 + memset(&state.kabi, 0, sizeof(state.kabi)); 638 638 639 639 res = checkp(process_die_container(&state, NULL, die, 640 640 check_union_member_kabi_status,
+1 -1
scripts/gendwarfksyms/kabi.c
··· 228 228 if (type == KABI_RULE_TYPE_UNKNOWN) 229 229 error("unsupported kABI rule type: '%s'", field); 230 230 231 - rule = xmalloc(sizeof(struct rule)); 231 + rule = xmalloc(sizeof(*rule)); 232 232 233 233 rule->type = type; 234 234 rule->target = xstrdup(get_rule_field(&rule_str, &left));
+1 -1
scripts/gendwarfksyms/symbols.c
··· 146 146 continue; 147 147 } 148 148 149 - sym = xcalloc(1, sizeof(struct symbol)); 149 + sym = xcalloc(1, sizeof(*sym)); 150 150 sym->name = name; 151 151 sym->addr.section = SHN_UNDEF; 152 152 sym->state = SYMBOL_UNPROCESSED;
+28 -5
scripts/gendwarfksyms/types.c
··· 6 6 #define _GNU_SOURCE 7 7 #include <inttypes.h> 8 8 #include <stdio.h> 9 + #include <stdlib.h> 10 + #include <string.h> 9 11 #include <zlib.h> 10 12 11 13 #include "gendwarfksyms.h" ··· 45 43 if (!s) 46 44 return 0; 47 45 48 - entry = xmalloc(sizeof(struct type_list_entry)); 46 + entry = xmalloc(sizeof(*entry)); 49 47 entry->str = s; 50 48 entry->owned = owned; 51 49 list_add_tail(&entry->list, list); ··· 122 120 struct type_expansion *e; 123 121 124 122 if (__type_map_get(name, &e)) { 125 - e = xmalloc(sizeof(struct type_expansion)); 123 + e = xmalloc(sizeof(*e)); 126 124 type_expansion_init(e); 127 125 e->name = xstrdup(name); 128 126 ··· 181 179 return -1; 182 180 } 183 181 182 + static int cmp_expansion_name(const void *p1, const void *p2) 183 + { 184 + struct type_expansion *const *e1 = p1; 185 + struct type_expansion *const *e2 = p2; 186 + 187 + return strcmp((*e1)->name, (*e2)->name); 188 + } 189 + 184 190 static void type_map_write(FILE *file) 185 191 { 186 192 struct type_expansion *e; 187 193 struct hlist_node *tmp; 194 + struct type_expansion **es; 195 + size_t count = 0; 196 + size_t i = 0; 188 197 189 198 if (!file) 190 199 return; 191 200 192 - hash_for_each_safe(type_map, e, tmp, hash) { 193 - checkp(fputs(e->name, file)); 201 + hash_for_each_safe(type_map, e, tmp, hash) 202 + ++count; 203 + es = xmalloc(count * sizeof(*es)); 204 + hash_for_each_safe(type_map, e, tmp, hash) 205 + es[i++] = e; 206 + 207 + qsort(es, count, sizeof(*es), cmp_expansion_name); 208 + 209 + for (i = 0; i < count; ++i) { 210 + checkp(fputs(es[i]->name, file)); 194 211 checkp(fputs(" ", file)); 195 - type_list_write(&e->expanded, file); 212 + type_list_write(&es[i]->expanded, file); 196 213 checkp(fputs("\n", file)); 197 214 } 215 + 216 + free(es); 198 217 } 199 218 200 219 static void type_map_free(void)
+1 -1
scripts/kconfig/conf.c
··· 594 594 default: 595 595 if (!conf_cnt++) 596 596 printf("*\n* Restart config...\n*\n"); 597 - rootEntry = menu_get_parent_menu(menu); 597 + rootEntry = menu_get_menu_or_parent_menu(menu); 598 598 conf(rootEntry); 599 599 break; 600 600 }
+1 -1
scripts/kconfig/confdata.c
··· 77 77 if (map2 == MAP_FAILED) 78 78 goto close2; 79 79 80 - if (bcmp(map1, map2, st1.st_size)) 80 + if (memcmp(map1, map2, st1.st_size)) 81 81 goto close2; 82 82 83 83 ret = true;
+2 -9
scripts/kconfig/gconf-cfg.sh
··· 6 6 cflags=$1 7 7 libs=$2 8 8 9 - PKG="gtk+-2.0 gmodule-2.0 libglade-2.0" 9 + PKG=gtk+-3.0 10 10 11 11 if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then 12 12 echo >&2 "*" ··· 18 18 if ! ${HOSTPKG_CONFIG} --exists $PKG; then 19 19 echo >&2 "*" 20 20 echo >&2 "* Unable to find the GTK+ installation. Please make sure that" 21 - echo >&2 "* the GTK+ 2.0 development package is correctly installed." 21 + echo >&2 "* the GTK 3 development package is correctly installed." 22 22 echo >&2 "* You need $PKG" 23 - echo >&2 "*" 24 - exit 1 25 - fi 26 - 27 - if ! ${HOSTPKG_CONFIG} --atleast-version=2.0.0 gtk+-2.0; then 28 - echo >&2 "*" 29 - echo >&2 "* GTK+ is present but version >= 2.0.0 is required." 30 23 echo >&2 "*" 31 24 exit 1 32 25 fi
+834 -949
scripts/kconfig/gconf.c
··· 7 7 #include "lkc.h" 8 8 #include "images.h" 9 9 10 - #include <glade/glade.h> 11 10 #include <gtk/gtk.h> 12 - #include <glib.h> 13 - #include <gdk/gdkkeysyms.h> 14 11 15 12 #include <stdio.h> 16 13 #include <string.h> ··· 15 18 #include <unistd.h> 16 19 #include <time.h> 17 20 18 - enum { 21 + enum view_mode { 19 22 SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW 20 23 }; 21 24 ··· 27 30 static gboolean show_name = TRUE; 28 31 static gboolean show_range = TRUE; 29 32 static gboolean show_value = TRUE; 30 - static gboolean resizeable = FALSE; 31 33 static int opt_mode = OPT_NORMAL; 32 34 33 - GtkWidget *main_wnd = NULL; 34 - GtkWidget *tree1_w = NULL; // left frame 35 - GtkWidget *tree2_w = NULL; // right frame 36 - GtkWidget *text_w = NULL; 37 - GtkWidget *hpaned = NULL; 38 - GtkWidget *vpaned = NULL; 39 - GtkWidget *back_btn = NULL; 40 - GtkWidget *save_btn = NULL; 41 - GtkWidget *save_menu_item = NULL; 35 + static GtkWidget *main_wnd; 36 + static GtkWidget *tree1_w; // left frame 37 + static GtkWidget *tree2_w; // right frame 38 + static GtkWidget *text_w; 39 + static GtkWidget *hpaned; 40 + static GtkWidget *vpaned; 41 + static GtkWidget *back_btn, *save_btn, *single_btn, *split_btn, *full_btn; 42 + static GtkWidget *save_menu_item; 42 43 43 - GtkTextTag *tag1, *tag2; 44 - GdkColor color; 44 + static GtkTextTag *tag1, *tag2; 45 45 46 - GtkTreeStore *tree1, *tree2, *tree; 47 - GtkTreeModel *model1, *model2; 48 - static GtkTreeIter *parents[256]; 49 - static gint indent; 46 + static GtkTreeStore *tree1, *tree2; 47 + static GdkPixbuf *pix_menu; 50 48 51 - static struct menu *current; // current node for SINGLE view 52 - static struct menu *browsed; // browsed node for SPLIT view 49 + static struct menu *browsed; // browsed menu for SINGLE/SPLIT view 50 + static struct menu *selected; // selected entry 53 51 54 52 enum { 55 53 COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, ··· 53 61 COL_NUMBER 54 62 }; 55 63 56 - static void display_list(void); 57 - static void display_tree(struct menu *menu); 58 - static void display_tree_part(void); 59 - static void update_tree(struct menu *src, GtkTreeIter * dst); 60 - 61 - static void replace_button_icon(GladeXML *xml, GdkDrawable *window, 62 - GtkStyle *style, gchar *btn_name, gchar **xpm) 63 - { 64 - GdkPixmap *pixmap; 65 - GdkBitmap *mask; 66 - GtkToolButton *button; 67 - GtkWidget *image; 68 - 69 - pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, 70 - &style->bg[GTK_STATE_NORMAL], 71 - xpm); 72 - 73 - button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); 74 - image = gtk_image_new_from_pixmap(pixmap, mask); 75 - gtk_widget_show(image); 76 - gtk_tool_button_set_icon_widget(button, image); 77 - } 64 + static void display_tree(GtkTreeStore *store, struct menu *menu); 65 + static void recreate_tree(void); 78 66 79 67 static void conf_changed(bool dirty) 80 68 { ··· 62 90 gtk_widget_set_sensitive(save_menu_item, dirty); 63 91 } 64 92 65 - /* Main Window Initialization */ 66 - static void init_main_window(const gchar *glade_file) 67 - { 68 - GladeXML *xml; 69 - GtkWidget *widget; 70 - GtkTextBuffer *txtbuf; 71 - GtkStyle *style; 72 - 73 - xml = glade_xml_new(glade_file, "window1", NULL); 74 - if (!xml) 75 - g_error("GUI loading failed !\n"); 76 - glade_xml_signal_autoconnect(xml); 77 - 78 - main_wnd = glade_xml_get_widget(xml, "window1"); 79 - hpaned = glade_xml_get_widget(xml, "hpaned1"); 80 - vpaned = glade_xml_get_widget(xml, "vpaned1"); 81 - tree1_w = glade_xml_get_widget(xml, "treeview1"); 82 - tree2_w = glade_xml_get_widget(xml, "treeview2"); 83 - text_w = glade_xml_get_widget(xml, "textview3"); 84 - 85 - back_btn = glade_xml_get_widget(xml, "button1"); 86 - gtk_widget_set_sensitive(back_btn, FALSE); 87 - 88 - widget = glade_xml_get_widget(xml, "show_name1"); 89 - gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 90 - show_name); 91 - 92 - widget = glade_xml_get_widget(xml, "show_range1"); 93 - gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 94 - show_range); 95 - 96 - widget = glade_xml_get_widget(xml, "show_data1"); 97 - gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 98 - show_value); 99 - 100 - save_btn = glade_xml_get_widget(xml, "button3"); 101 - save_menu_item = glade_xml_get_widget(xml, "save1"); 102 - conf_set_changed_callback(conf_changed); 103 - 104 - style = gtk_widget_get_style(main_wnd); 105 - widget = glade_xml_get_widget(xml, "toolbar1"); 106 - 107 - replace_button_icon(xml, main_wnd->window, style, 108 - "button4", (gchar **) xpm_single_view); 109 - replace_button_icon(xml, main_wnd->window, style, 110 - "button5", (gchar **) xpm_split_view); 111 - replace_button_icon(xml, main_wnd->window, style, 112 - "button6", (gchar **) xpm_tree_view); 113 - 114 - txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 115 - tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", 116 - "foreground", "red", 117 - "weight", PANGO_WEIGHT_BOLD, 118 - NULL); 119 - tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", 120 - /*"style", PANGO_STYLE_OBLIQUE, */ 121 - NULL); 122 - 123 - gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); 124 - 125 - gtk_widget_show(main_wnd); 126 - } 127 - 128 - static void init_tree_model(void) 129 - { 130 - gint i; 131 - 132 - tree = tree2 = gtk_tree_store_new(COL_NUMBER, 133 - G_TYPE_STRING, G_TYPE_STRING, 134 - G_TYPE_STRING, G_TYPE_STRING, 135 - G_TYPE_STRING, G_TYPE_STRING, 136 - G_TYPE_POINTER, GDK_TYPE_COLOR, 137 - G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, 138 - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 139 - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 140 - G_TYPE_BOOLEAN); 141 - model2 = GTK_TREE_MODEL(tree2); 142 - 143 - for (parents[0] = NULL, i = 1; i < 256; i++) 144 - parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); 145 - 146 - tree1 = gtk_tree_store_new(COL_NUMBER, 147 - G_TYPE_STRING, G_TYPE_STRING, 148 - G_TYPE_STRING, G_TYPE_STRING, 149 - G_TYPE_STRING, G_TYPE_STRING, 150 - G_TYPE_POINTER, GDK_TYPE_COLOR, 151 - G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, 152 - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 153 - G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 154 - G_TYPE_BOOLEAN); 155 - model1 = GTK_TREE_MODEL(tree1); 156 - } 157 - 158 - static void init_left_tree(void) 159 - { 160 - GtkTreeView *view = GTK_TREE_VIEW(tree1_w); 161 - GtkCellRenderer *renderer; 162 - GtkTreeSelection *sel; 163 - GtkTreeViewColumn *column; 164 - 165 - gtk_tree_view_set_model(view, model1); 166 - gtk_tree_view_set_headers_visible(view, TRUE); 167 - gtk_tree_view_set_rules_hint(view, TRUE); 168 - 169 - column = gtk_tree_view_column_new(); 170 - gtk_tree_view_append_column(view, column); 171 - gtk_tree_view_column_set_title(column, "Options"); 172 - 173 - renderer = gtk_cell_renderer_toggle_new(); 174 - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 175 - renderer, FALSE); 176 - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 177 - renderer, 178 - "active", COL_BTNACT, 179 - "inconsistent", COL_BTNINC, 180 - "visible", COL_BTNVIS, 181 - "radio", COL_BTNRAD, NULL); 182 - renderer = gtk_cell_renderer_text_new(); 183 - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 184 - renderer, FALSE); 185 - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 186 - renderer, 187 - "text", COL_OPTION, 188 - "foreground-gdk", 189 - COL_COLOR, NULL); 190 - 191 - sel = gtk_tree_view_get_selection(view); 192 - gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); 193 - gtk_widget_realize(tree1_w); 194 - } 195 - 196 - static void renderer_edited(GtkCellRendererText * cell, 197 - const gchar * path_string, 198 - const gchar * new_text, gpointer user_data); 199 - 200 - static void init_right_tree(void) 201 - { 202 - GtkTreeView *view = GTK_TREE_VIEW(tree2_w); 203 - GtkCellRenderer *renderer; 204 - GtkTreeSelection *sel; 205 - GtkTreeViewColumn *column; 206 - gint i; 207 - 208 - gtk_tree_view_set_model(view, model2); 209 - gtk_tree_view_set_headers_visible(view, TRUE); 210 - gtk_tree_view_set_rules_hint(view, TRUE); 211 - 212 - column = gtk_tree_view_column_new(); 213 - gtk_tree_view_append_column(view, column); 214 - gtk_tree_view_column_set_title(column, "Options"); 215 - 216 - renderer = gtk_cell_renderer_pixbuf_new(); 217 - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 218 - renderer, FALSE); 219 - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 220 - renderer, 221 - "pixbuf", COL_PIXBUF, 222 - "visible", COL_PIXVIS, NULL); 223 - renderer = gtk_cell_renderer_toggle_new(); 224 - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 225 - renderer, FALSE); 226 - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 227 - renderer, 228 - "active", COL_BTNACT, 229 - "inconsistent", COL_BTNINC, 230 - "visible", COL_BTNVIS, 231 - "radio", COL_BTNRAD, NULL); 232 - renderer = gtk_cell_renderer_text_new(); 233 - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 234 - renderer, FALSE); 235 - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 236 - renderer, 237 - "text", COL_OPTION, 238 - "foreground-gdk", 239 - COL_COLOR, NULL); 240 - 241 - renderer = gtk_cell_renderer_text_new(); 242 - gtk_tree_view_insert_column_with_attributes(view, -1, 243 - "Name", renderer, 244 - "text", COL_NAME, 245 - "foreground-gdk", 246 - COL_COLOR, NULL); 247 - renderer = gtk_cell_renderer_text_new(); 248 - gtk_tree_view_insert_column_with_attributes(view, -1, 249 - "N", renderer, 250 - "text", COL_NO, 251 - "foreground-gdk", 252 - COL_COLOR, NULL); 253 - renderer = gtk_cell_renderer_text_new(); 254 - gtk_tree_view_insert_column_with_attributes(view, -1, 255 - "M", renderer, 256 - "text", COL_MOD, 257 - "foreground-gdk", 258 - COL_COLOR, NULL); 259 - renderer = gtk_cell_renderer_text_new(); 260 - gtk_tree_view_insert_column_with_attributes(view, -1, 261 - "Y", renderer, 262 - "text", COL_YES, 263 - "foreground-gdk", 264 - COL_COLOR, NULL); 265 - renderer = gtk_cell_renderer_text_new(); 266 - gtk_tree_view_insert_column_with_attributes(view, -1, 267 - "Value", renderer, 268 - "text", COL_VALUE, 269 - "editable", 270 - COL_EDIT, 271 - "foreground-gdk", 272 - COL_COLOR, NULL); 273 - g_signal_connect(G_OBJECT(renderer), "edited", 274 - G_CALLBACK(renderer_edited), NULL); 275 - 276 - column = gtk_tree_view_get_column(view, COL_NAME); 277 - gtk_tree_view_column_set_visible(column, show_name); 278 - column = gtk_tree_view_get_column(view, COL_NO); 279 - gtk_tree_view_column_set_visible(column, show_range); 280 - column = gtk_tree_view_get_column(view, COL_MOD); 281 - gtk_tree_view_column_set_visible(column, show_range); 282 - column = gtk_tree_view_get_column(view, COL_YES); 283 - gtk_tree_view_column_set_visible(column, show_range); 284 - column = gtk_tree_view_get_column(view, COL_VALUE); 285 - gtk_tree_view_column_set_visible(column, show_value); 286 - 287 - if (resizeable) { 288 - for (i = 0; i < COL_VALUE; i++) { 289 - column = gtk_tree_view_get_column(view, i); 290 - gtk_tree_view_column_set_resizable(column, TRUE); 291 - } 292 - } 293 - 294 - sel = gtk_tree_view_get_selection(view); 295 - gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); 296 - } 297 - 298 - 299 93 /* Utility Functions */ 300 94 301 - 302 - static void text_insert_help(struct menu *menu) 95 + static void text_insert_msg(const char *title, const char *msg) 303 96 { 304 97 GtkTextBuffer *buffer; 305 98 GtkTextIter start, end; 306 - const char *prompt = menu_get_prompt(menu); 307 - struct gstr help = str_new(); 308 - 309 - menu_get_ext_help(menu, &help); 310 - 311 - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 312 - gtk_text_buffer_get_bounds(buffer, &start, &end); 313 - gtk_text_buffer_delete(buffer, &start, &end); 314 - gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); 315 - 316 - gtk_text_buffer_get_end_iter(buffer, &end); 317 - gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, 318 - NULL); 319 - gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); 320 - gtk_text_buffer_get_end_iter(buffer, &end); 321 - gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2, 322 - NULL); 323 - str_free(&help); 324 - } 325 - 326 - 327 - static void text_insert_msg(const char *title, const char *message) 328 - { 329 - GtkTextBuffer *buffer; 330 - GtkTextIter start, end; 331 - const char *msg = message; 332 99 333 100 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 334 101 gtk_text_buffer_get_bounds(buffer, &start, &end); ··· 83 372 NULL); 84 373 } 85 374 86 - 87 - /* Main Windows Callbacks */ 88 - 89 - void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); 90 - gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, 91 - gpointer user_data) 375 + static void text_insert_help(struct menu *menu) 92 376 { 93 - GtkWidget *dialog, *label; 94 - gint result; 377 + struct gstr help = str_new(); 95 378 96 - if (!conf_get_changed()) 97 - return FALSE; 379 + menu_get_ext_help(menu, &help); 380 + text_insert_msg(menu_get_prompt(menu), str_get(&help)); 381 + str_free(&help); 382 + } 98 383 99 - dialog = gtk_dialog_new_with_buttons("Warning !", 100 - GTK_WINDOW(main_wnd), 101 - (GtkDialogFlags) 102 - (GTK_DIALOG_MODAL | 103 - GTK_DIALOG_DESTROY_WITH_PARENT), 104 - GTK_STOCK_OK, 105 - GTK_RESPONSE_YES, 106 - GTK_STOCK_NO, 107 - GTK_RESPONSE_NO, 108 - GTK_STOCK_CANCEL, 109 - GTK_RESPONSE_CANCEL, NULL); 110 - gtk_dialog_set_default_response(GTK_DIALOG(dialog), 111 - GTK_RESPONSE_CANCEL); 384 + static void _select_menu(GtkTreeView *view, GtkTreeModel *model, 385 + GtkTreeIter *parent, struct menu *match) 386 + { 387 + GtkTreeIter iter; 388 + gboolean valid; 112 389 113 - label = gtk_label_new("\nSave configuration ?\n"); 114 - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); 115 - gtk_widget_show(label); 390 + valid = gtk_tree_model_iter_children(model, &iter, parent); 391 + while (valid) { 392 + struct menu *menu; 116 393 117 - result = gtk_dialog_run(GTK_DIALOG(dialog)); 118 - switch (result) { 119 - case GTK_RESPONSE_YES: 120 - on_save_activate(NULL, NULL); 121 - return FALSE; 122 - case GTK_RESPONSE_NO: 123 - return FALSE; 124 - case GTK_RESPONSE_CANCEL: 125 - case GTK_RESPONSE_DELETE_EVENT: 126 - default: 127 - gtk_widget_destroy(dialog); 128 - return TRUE; 394 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 395 + 396 + if (menu == match) { 397 + GtkTreeSelection *selection; 398 + GtkTreePath *path; 399 + 400 + /* 401 + * Expand parents to reflect the selection, and 402 + * scroll down to it. 403 + */ 404 + path = gtk_tree_model_get_path(model, &iter); 405 + gtk_tree_view_expand_to_path(view, path); 406 + gtk_tree_view_scroll_to_cell(view, path, NULL, TRUE, 407 + 0.5, 0.0); 408 + gtk_tree_path_free(path); 409 + 410 + selection = gtk_tree_view_get_selection(view); 411 + gtk_tree_selection_select_iter(selection, &iter); 412 + 413 + text_insert_help(menu); 414 + } 415 + 416 + _select_menu(view, model, &iter, match); 417 + 418 + valid = gtk_tree_model_iter_next(model, &iter); 419 + } 420 + } 421 + 422 + static void select_menu(GtkTreeView *view, struct menu *match) 423 + { 424 + _select_menu(view, gtk_tree_view_get_model(view), NULL, match); 425 + } 426 + 427 + static void _update_row_visibility(GtkTreeView *view) 428 + { 429 + GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(view)); 430 + 431 + gtk_tree_model_filter_refilter(filter); 432 + } 433 + 434 + static void update_row_visibility(void) 435 + { 436 + if (view_mode == SPLIT_VIEW) 437 + _update_row_visibility(GTK_TREE_VIEW(tree1_w)); 438 + _update_row_visibility(GTK_TREE_VIEW(tree2_w)); 439 + } 440 + 441 + static void set_node(GtkTreeStore *tree, GtkTreeIter *node, struct menu *menu) 442 + { 443 + struct symbol *sym = menu->sym; 444 + tristate val; 445 + gchar *option; 446 + const gchar *_no = ""; 447 + const gchar *_mod = ""; 448 + const gchar *_yes = ""; 449 + const gchar *value = ""; 450 + GdkRGBA color; 451 + gboolean editable = FALSE; 452 + gboolean btnvis = FALSE; 453 + 454 + option = g_strdup_printf("%s %s %s %s", 455 + menu->type == M_COMMENT ? "***" : "", 456 + menu_get_prompt(menu), 457 + menu->type == M_COMMENT ? "***" : "", 458 + sym && !sym_has_value(sym) ? "(NEW)" : ""); 459 + 460 + gdk_rgba_parse(&color, menu_is_visible(menu) ? "Black" : "DarkGray"); 461 + 462 + if (!sym) 463 + goto set; 464 + 465 + sym_calc_value(sym); 466 + 467 + if (menu->type == M_CHOICE) { // parse children to get a final value 468 + struct symbol *def_sym = sym_calc_choice(menu); 469 + struct menu *def_menu = NULL; 470 + 471 + for (struct menu *child = menu->list; child; child = child->next) { 472 + if (menu_is_visible(child) && child->sym == def_sym) 473 + def_menu = child; 474 + } 475 + 476 + if (def_menu) 477 + value = menu_get_prompt(def_menu); 478 + 479 + goto set; 129 480 } 130 481 131 - return FALSE; 482 + switch (sym_get_type(sym)) { 483 + case S_BOOLEAN: 484 + case S_TRISTATE: 485 + 486 + btnvis = TRUE; 487 + 488 + val = sym_get_tristate_value(sym); 489 + switch (val) { 490 + case no: 491 + _no = "N"; 492 + value = "N"; 493 + break; 494 + case mod: 495 + _mod = "M"; 496 + value = "M"; 497 + break; 498 + case yes: 499 + _yes = "Y"; 500 + value = "Y"; 501 + break; 502 + } 503 + 504 + if (val != no && sym_tristate_within_range(sym, no)) 505 + _no = "_"; 506 + if (val != mod && sym_tristate_within_range(sym, mod)) 507 + _mod = "_"; 508 + if (val != yes && sym_tristate_within_range(sym, yes)) 509 + _yes = "_"; 510 + break; 511 + default: 512 + value = sym_get_string_value(sym); 513 + editable = TRUE; 514 + break; 515 + } 516 + 517 + set: 518 + gtk_tree_store_set(tree, node, 519 + COL_OPTION, option, 520 + COL_NAME, sym ? sym->name : "", 521 + COL_NO, _no, 522 + COL_MOD, _mod, 523 + COL_YES, _yes, 524 + COL_VALUE, value, 525 + COL_MENU, (gpointer) menu, 526 + COL_COLOR, &color, 527 + COL_EDIT, editable, 528 + COL_PIXBUF, pix_menu, 529 + COL_PIXVIS, view_mode == SINGLE_VIEW && menu->type == M_MENU, 530 + COL_BTNVIS, btnvis, 531 + COL_BTNACT, _yes[0] == 'Y', 532 + COL_BTNINC, _mod[0] == 'M', 533 + COL_BTNRAD, sym && sym_is_choice_value(sym), 534 + -1); 535 + 536 + g_free(option); 132 537 } 133 538 134 - 135 - void on_window1_destroy(GtkObject * object, gpointer user_data) 539 + static void _update_tree(GtkTreeStore *store, GtkTreeIter *parent) 136 540 { 137 - gtk_main_quit(); 541 + GtkTreeModel *model = GTK_TREE_MODEL(store); 542 + GtkTreeIter iter; 543 + gboolean valid; 544 + 545 + valid = gtk_tree_model_iter_children(model, &iter, parent); 546 + while (valid) { 547 + struct menu *menu; 548 + 549 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 550 + 551 + if (menu) 552 + set_node(store, &iter, menu); 553 + 554 + _update_tree(store, &iter); 555 + 556 + valid = gtk_tree_model_iter_next(model, &iter); 557 + } 138 558 } 139 559 140 - 141 - void 142 - on_window1_size_request(GtkWidget * widget, 143 - GtkRequisition * requisition, gpointer user_data) 560 + static void update_tree(GtkTreeStore *store) 144 561 { 145 - static gint old_h; 146 - gint w, h; 147 - 148 - if (widget->window == NULL) 149 - gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); 150 - else 151 - gdk_window_get_size(widget->window, &w, &h); 152 - 153 - if (h == old_h) 154 - return; 155 - old_h = h; 156 - 157 - gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); 562 + _update_tree(store, NULL); 563 + update_row_visibility(); 158 564 } 159 565 566 + static void update_trees(void) 567 + { 568 + if (view_mode == SPLIT_VIEW) 569 + update_tree(tree1); 570 + update_tree(tree2); 571 + } 572 + 573 + static void set_view_mode(enum view_mode mode) 574 + { 575 + view_mode = mode; 576 + 577 + if (mode == SPLIT_VIEW) { // two panes 578 + gint w; 579 + 580 + gtk_widget_show(tree1_w); 581 + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, NULL); 582 + gtk_paned_set_position(GTK_PANED(hpaned), w / 2); 583 + } else { 584 + gtk_widget_hide(tree1_w); 585 + gtk_paned_set_position(GTK_PANED(hpaned), 0); 586 + } 587 + 588 + gtk_widget_set_sensitive(single_btn, TRUE); 589 + gtk_widget_set_sensitive(split_btn, TRUE); 590 + gtk_widget_set_sensitive(full_btn, TRUE); 591 + 592 + switch (mode) { 593 + case SINGLE_VIEW: 594 + if (selected) 595 + browsed = menu_get_parent_menu(selected) ?: &rootmenu; 596 + else 597 + browsed = &rootmenu; 598 + recreate_tree(); 599 + text_insert_msg("", ""); 600 + select_menu(GTK_TREE_VIEW(tree2_w), selected); 601 + gtk_widget_set_sensitive(single_btn, FALSE); 602 + break; 603 + case SPLIT_VIEW: 604 + browsed = selected; 605 + while (browsed && !(browsed->flags & MENU_ROOT)) 606 + browsed = browsed->parent; 607 + gtk_tree_store_clear(tree1); 608 + display_tree(tree1, &rootmenu); 609 + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); 610 + gtk_tree_store_clear(tree2); 611 + if (browsed) 612 + display_tree(tree2, browsed); 613 + text_insert_msg("", ""); 614 + select_menu(GTK_TREE_VIEW(tree1_w), browsed); 615 + select_menu(GTK_TREE_VIEW(tree2_w), selected); 616 + gtk_widget_set_sensitive(split_btn, FALSE); 617 + break; 618 + case FULL_VIEW: 619 + gtk_tree_store_clear(tree2); 620 + display_tree(tree2, &rootmenu); 621 + text_insert_msg("", ""); 622 + select_menu(GTK_TREE_VIEW(tree2_w), selected); 623 + gtk_widget_set_sensitive(full_btn, FALSE); 624 + break; 625 + } 626 + 627 + gtk_widget_set_sensitive(back_btn, 628 + mode == SINGLE_VIEW && browsed != &rootmenu); 629 + } 160 630 161 631 /* Menu & Toolbar Callbacks */ 162 632 163 - 164 - static void 165 - load_filename(GtkFileSelection * file_selector, gpointer user_data) 633 + static void on_load1_activate(GtkMenuItem *menuitem, gpointer user_data) 166 634 { 167 - const gchar *fn; 635 + GtkWidget *dialog; 636 + GtkFileChooser *chooser; 637 + gint res; 168 638 169 - fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION 170 - (user_data)); 639 + dialog = gtk_file_chooser_dialog_new("Load file...", 640 + GTK_WINDOW(user_data), 641 + GTK_FILE_CHOOSER_ACTION_OPEN, 642 + "_Cancel", GTK_RESPONSE_CANCEL, 643 + "_Open", GTK_RESPONSE_ACCEPT, 644 + NULL); 171 645 172 - if (conf_read(fn)) 173 - text_insert_msg("Error", "Unable to load configuration !"); 174 - else 175 - display_tree_part(); 646 + chooser = GTK_FILE_CHOOSER(dialog); 647 + gtk_file_chooser_set_filename(chooser, conf_get_configname()); 648 + 649 + res = gtk_dialog_run(GTK_DIALOG(dialog)); 650 + if (res == GTK_RESPONSE_ACCEPT) { 651 + char *filename; 652 + 653 + filename = gtk_file_chooser_get_filename(chooser); 654 + 655 + if (conf_read(filename)) 656 + text_insert_msg("Error", 657 + "Unable to load configuration!"); 658 + else 659 + update_trees(); 660 + 661 + g_free(filename); 662 + } 663 + 664 + gtk_widget_destroy(GTK_WIDGET(dialog)); 176 665 } 177 666 178 - void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) 179 - { 180 - GtkWidget *fs; 181 - 182 - fs = gtk_file_selection_new("Load file..."); 183 - g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), 184 - "clicked", 185 - G_CALLBACK(load_filename), (gpointer) fs); 186 - g_signal_connect_swapped(GTK_OBJECT 187 - (GTK_FILE_SELECTION(fs)->ok_button), 188 - "clicked", G_CALLBACK(gtk_widget_destroy), 189 - (gpointer) fs); 190 - g_signal_connect_swapped(GTK_OBJECT 191 - (GTK_FILE_SELECTION(fs)->cancel_button), 192 - "clicked", G_CALLBACK(gtk_widget_destroy), 193 - (gpointer) fs); 194 - gtk_widget_show(fs); 195 - } 196 - 197 - 198 - void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) 667 + static void on_save_activate(GtkMenuItem *menuitem, gpointer user_data) 199 668 { 200 669 if (conf_write(NULL)) 201 670 text_insert_msg("Error", "Unable to save configuration !"); 202 671 conf_write_autoconf(0); 203 672 } 204 673 205 - 206 - static void 207 - store_filename(GtkFileSelection * file_selector, gpointer user_data) 674 + static void on_save_as1_activate(GtkMenuItem *menuitem, gpointer user_data) 208 675 { 209 - const gchar *fn; 676 + GtkWidget *dialog; 677 + GtkFileChooser *chooser; 678 + gint res; 210 679 211 - fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION 212 - (user_data)); 680 + dialog = gtk_file_chooser_dialog_new("Save file as...", 681 + GTK_WINDOW(user_data), 682 + GTK_FILE_CHOOSER_ACTION_SAVE, 683 + "_Cancel", GTK_RESPONSE_CANCEL, 684 + "_Save", GTK_RESPONSE_ACCEPT, 685 + NULL); 213 686 214 - if (conf_write(fn)) 215 - text_insert_msg("Error", "Unable to save configuration !"); 687 + chooser = GTK_FILE_CHOOSER(dialog); 688 + gtk_file_chooser_set_filename(chooser, conf_get_configname()); 216 689 217 - gtk_widget_destroy(GTK_WIDGET(user_data)); 690 + res = gtk_dialog_run(GTK_DIALOG(dialog)); 691 + if (res == GTK_RESPONSE_ACCEPT) { 692 + char *filename; 693 + 694 + filename = gtk_file_chooser_get_filename(chooser); 695 + 696 + if (conf_write(filename)) 697 + text_insert_msg("Error", 698 + "Unable to save configuration !"); 699 + 700 + g_free(filename); 701 + } 702 + 703 + gtk_widget_destroy(dialog); 218 704 } 219 705 220 - void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) 221 - { 222 - GtkWidget *fs; 223 - 224 - fs = gtk_file_selection_new("Save file as..."); 225 - g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), 226 - "clicked", 227 - G_CALLBACK(store_filename), (gpointer) fs); 228 - g_signal_connect_swapped(GTK_OBJECT 229 - (GTK_FILE_SELECTION(fs)->ok_button), 230 - "clicked", G_CALLBACK(gtk_widget_destroy), 231 - (gpointer) fs); 232 - g_signal_connect_swapped(GTK_OBJECT 233 - (GTK_FILE_SELECTION(fs)->cancel_button), 234 - "clicked", G_CALLBACK(gtk_widget_destroy), 235 - (gpointer) fs); 236 - gtk_widget_show(fs); 237 - } 238 - 239 - 240 - void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) 241 - { 242 - if (!on_window1_delete_event(NULL, NULL, NULL)) 243 - gtk_widget_destroy(GTK_WIDGET(main_wnd)); 244 - } 245 - 246 - 247 - void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) 706 + static void on_show_name1_activate(GtkMenuItem *menuitem, gpointer user_data) 248 707 { 249 708 GtkTreeViewColumn *col; 250 709 251 - show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; 710 + show_name = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)); 252 711 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); 253 712 if (col) 254 713 gtk_tree_view_column_set_visible(col, show_name); 255 714 } 256 715 257 - 258 - void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) 716 + static void on_show_range1_activate(GtkMenuItem *menuitem, gpointer user_data) 259 717 { 260 718 GtkTreeViewColumn *col; 261 719 262 - show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; 720 + show_range = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)); 263 721 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); 264 722 if (col) 265 723 gtk_tree_view_column_set_visible(col, show_range); ··· 441 561 442 562 } 443 563 444 - 445 - void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) 564 + static void on_show_data1_activate(GtkMenuItem *menuitem, gpointer user_data) 446 565 { 447 566 GtkTreeViewColumn *col; 448 567 449 - show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; 568 + show_value = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)); 450 569 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); 451 570 if (col) 452 571 gtk_tree_view_column_set_visible(col, show_value); 453 572 } 454 573 455 - 456 - void 457 - on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) 574 + static void on_set_option_mode1_activate(GtkMenuItem *menuitem, 575 + gpointer user_data) 458 576 { 459 577 opt_mode = OPT_NORMAL; 460 - gtk_tree_store_clear(tree2); 461 - display_tree(&rootmenu); /* instead of update_tree to speed-up */ 578 + update_row_visibility(); 462 579 } 463 580 464 - 465 - void 466 - on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) 581 + static void on_set_option_mode2_activate(GtkMenuItem *menuitem, 582 + gpointer user_data) 467 583 { 468 584 opt_mode = OPT_ALL; 469 - gtk_tree_store_clear(tree2); 470 - display_tree(&rootmenu); /* instead of update_tree to speed-up */ 585 + update_row_visibility(); 471 586 } 472 587 473 - 474 - void 475 - on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) 588 + static void on_set_option_mode3_activate(GtkMenuItem *menuitem, 589 + gpointer user_data) 476 590 { 477 591 opt_mode = OPT_PROMPT; 478 - gtk_tree_store_clear(tree2); 479 - display_tree(&rootmenu); /* instead of update_tree to speed-up */ 592 + update_row_visibility(); 480 593 } 481 594 482 - 483 - void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) 595 + static void on_introduction1_activate(GtkMenuItem *menuitem, gpointer user_data) 484 596 { 485 597 GtkWidget *dialog; 486 598 const gchar *intro_text = ··· 493 621 GTK_DIALOG_DESTROY_WITH_PARENT, 494 622 GTK_MESSAGE_INFO, 495 623 GTK_BUTTONS_CLOSE, "%s", intro_text); 496 - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 497 - G_CALLBACK(gtk_widget_destroy), 498 - GTK_OBJECT(dialog)); 499 - gtk_widget_show_all(dialog); 624 + gtk_dialog_run(GTK_DIALOG(dialog)); 625 + gtk_widget_destroy(dialog); 500 626 } 501 627 502 - 503 - void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) 628 + static void on_about1_activate(GtkMenuItem *menuitem, gpointer user_data) 504 629 { 505 630 GtkWidget *dialog; 506 631 const gchar *about_text = ··· 507 638 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), 508 639 GTK_DIALOG_DESTROY_WITH_PARENT, 509 640 GTK_MESSAGE_INFO, 510 - GTK_BUTTONS_CLOSE, "%s", about_text); 511 - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 512 - G_CALLBACK(gtk_widget_destroy), 513 - GTK_OBJECT(dialog)); 514 - gtk_widget_show_all(dialog); 641 + GTK_BUTTONS_CLOSE, "%s\nGTK version: %d.%d.%d", 642 + about_text, 643 + gtk_get_major_version(), 644 + gtk_get_minor_version(), 645 + gtk_get_micro_version()); 646 + gtk_dialog_run(GTK_DIALOG(dialog)); 647 + gtk_widget_destroy(dialog); 515 648 } 516 649 517 - 518 - void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) 650 + static void on_license1_activate(GtkMenuItem *menuitem, gpointer user_data) 519 651 { 520 652 GtkWidget *dialog; 521 653 const gchar *license_text = ··· 528 658 GTK_DIALOG_DESTROY_WITH_PARENT, 529 659 GTK_MESSAGE_INFO, 530 660 GTK_BUTTONS_CLOSE, "%s", license_text); 531 - g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 532 - G_CALLBACK(gtk_widget_destroy), 533 - GTK_OBJECT(dialog)); 534 - gtk_widget_show_all(dialog); 661 + gtk_dialog_run(GTK_DIALOG(dialog)); 662 + gtk_widget_destroy(dialog); 535 663 } 536 664 537 - 538 - void on_back_clicked(GtkButton * button, gpointer user_data) 665 + /* toolbar handlers */ 666 + static void on_back_clicked(GtkButton *button, gpointer user_data) 539 667 { 540 - enum prop_type ptype; 668 + browsed = menu_get_parent_menu(browsed) ?: &rootmenu; 541 669 542 - current = current->parent; 543 - ptype = current->prompt ? current->prompt->type : P_UNKNOWN; 544 - if (ptype != P_MENU) 545 - current = current->parent; 546 - display_tree_part(); 670 + recreate_tree(); 547 671 548 - if (current == &rootmenu) 672 + if (browsed == &rootmenu) 549 673 gtk_widget_set_sensitive(back_btn, FALSE); 550 674 } 551 675 552 - 553 - void on_load_clicked(GtkButton * button, gpointer user_data) 676 + static void on_load_clicked(GtkButton *button, gpointer user_data) 554 677 { 555 678 on_load1_activate(NULL, user_data); 556 679 } 557 680 558 - 559 - void on_single_clicked(GtkButton * button, gpointer user_data) 681 + static void on_save_clicked(GtkButton *button, gpointer user_data) 560 682 { 561 - view_mode = SINGLE_VIEW; 562 - gtk_widget_hide(tree1_w); 563 - current = &rootmenu; 564 - display_tree_part(); 683 + on_save_activate(NULL, user_data); 565 684 } 566 685 567 - 568 - void on_split_clicked(GtkButton * button, gpointer user_data) 686 + static void on_single_clicked(GtkButton *button, gpointer user_data) 569 687 { 570 - gint w, h; 571 - view_mode = SPLIT_VIEW; 572 - gtk_widget_show(tree1_w); 573 - gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); 574 - gtk_paned_set_position(GTK_PANED(hpaned), w / 2); 575 - if (tree2) 576 - gtk_tree_store_clear(tree2); 577 - display_list(); 578 - 579 - /* Disable back btn, like in full mode. */ 580 - gtk_widget_set_sensitive(back_btn, FALSE); 688 + set_view_mode(SINGLE_VIEW); 581 689 } 582 690 583 - 584 - void on_full_clicked(GtkButton * button, gpointer user_data) 691 + static void on_split_clicked(GtkButton *button, gpointer user_data) 585 692 { 586 - view_mode = FULL_VIEW; 587 - gtk_widget_hide(tree1_w); 588 - if (tree2) 589 - gtk_tree_store_clear(tree2); 590 - display_tree(&rootmenu); 591 - gtk_widget_set_sensitive(back_btn, FALSE); 693 + set_view_mode(SPLIT_VIEW); 592 694 } 593 695 696 + static void on_full_clicked(GtkButton *button, gpointer user_data) 697 + { 698 + set_view_mode(FULL_VIEW); 699 + } 594 700 595 - void on_collapse_clicked(GtkButton * button, gpointer user_data) 701 + static void on_collapse_clicked(GtkButton *button, gpointer user_data) 596 702 { 597 703 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); 598 704 } 599 705 600 - 601 - void on_expand_clicked(GtkButton * button, gpointer user_data) 706 + static void on_expand_clicked(GtkButton *button, gpointer user_data) 602 707 { 603 708 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); 604 709 } 605 710 711 + /* Main Windows Callbacks */ 712 + 713 + static void on_window1_destroy(GtkWidget *widget, gpointer user_data) 714 + { 715 + gtk_main_quit(); 716 + } 717 + 718 + static gboolean on_window1_configure(GtkWidget *self, 719 + GdkEventConfigure *event, 720 + gpointer user_data) 721 + { 722 + gtk_paned_set_position(GTK_PANED(vpaned), 2 * event->height / 3); 723 + return FALSE; 724 + } 725 + 726 + static gboolean on_window1_delete_event(GtkWidget *widget, GdkEvent *event, 727 + gpointer user_data) 728 + { 729 + GtkWidget *dialog, *label, *content_area; 730 + gint result; 731 + gint ret = FALSE; 732 + 733 + if (!conf_get_changed()) 734 + return FALSE; 735 + 736 + dialog = gtk_dialog_new_with_buttons("Warning !", 737 + GTK_WINDOW(main_wnd), 738 + (GtkDialogFlags) 739 + (GTK_DIALOG_MODAL | 740 + GTK_DIALOG_DESTROY_WITH_PARENT), 741 + "_OK", 742 + GTK_RESPONSE_YES, 743 + "_No", 744 + GTK_RESPONSE_NO, 745 + "_Cancel", 746 + GTK_RESPONSE_CANCEL, NULL); 747 + gtk_dialog_set_default_response(GTK_DIALOG(dialog), 748 + GTK_RESPONSE_CANCEL); 749 + 750 + label = gtk_label_new("\nSave configuration ?\n"); 751 + content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); 752 + gtk_container_add(GTK_CONTAINER(content_area), label); 753 + gtk_widget_show(label); 754 + 755 + result = gtk_dialog_run(GTK_DIALOG(dialog)); 756 + switch (result) { 757 + case GTK_RESPONSE_YES: 758 + on_save_activate(NULL, NULL); 759 + break; 760 + case GTK_RESPONSE_NO: 761 + break; 762 + case GTK_RESPONSE_CANCEL: 763 + case GTK_RESPONSE_DELETE_EVENT: 764 + default: 765 + ret = TRUE; 766 + break; 767 + } 768 + 769 + gtk_widget_destroy(dialog); 770 + 771 + if (!ret) 772 + g_object_unref(pix_menu); 773 + 774 + return ret; 775 + } 776 + 777 + static void on_quit1_activate(GtkMenuItem *menuitem, gpointer user_data) 778 + { 779 + if (!on_window1_delete_event(NULL, NULL, NULL)) 780 + gtk_widget_destroy(GTK_WIDGET(main_wnd)); 781 + } 606 782 607 783 /* CTree Callbacks */ 608 784 ··· 657 741 const gchar * path_string, 658 742 const gchar * new_text, gpointer user_data) 659 743 { 744 + GtkTreeView *view = GTK_TREE_VIEW(user_data); 745 + GtkTreeModel *model = gtk_tree_view_get_model(view); 660 746 GtkTreePath *path = gtk_tree_path_new_from_string(path_string); 661 747 GtkTreeIter iter; 662 748 const char *old_def, *new_def; 663 749 struct menu *menu; 664 750 struct symbol *sym; 665 751 666 - if (!gtk_tree_model_get_iter(model2, &iter, path)) 667 - return; 752 + if (!gtk_tree_model_get_iter(model, &iter, path)) 753 + goto free; 668 754 669 - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 755 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 670 756 sym = menu->sym; 671 757 672 - gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); 758 + gtk_tree_model_get(model, &iter, COL_VALUE, &old_def, -1); 673 759 new_def = new_text; 674 760 675 761 sym_set_string_value(sym, new_def); 676 762 677 - update_tree(&rootmenu, NULL); 763 + update_trees(); 678 764 765 + free: 679 766 gtk_tree_path_free(path); 680 767 } 681 768 ··· 706 787 if (!sym_tristate_within_range(sym, newval)) 707 788 newval = yes; 708 789 sym_set_tristate_value(sym, newval); 709 - if (view_mode == FULL_VIEW) 710 - update_tree(&rootmenu, NULL); 711 - else if (view_mode == SPLIT_VIEW) { 712 - update_tree(browsed, NULL); 713 - display_list(); 714 - } 715 - else if (view_mode == SINGLE_VIEW) 716 - display_tree_part(); //fixme: keep exp/coll 790 + update_trees(); 717 791 break; 718 792 case S_INT: 719 793 case S_HEX: ··· 722 810 return; 723 811 724 812 sym_toggle_tristate_value(menu->sym); 725 - if (view_mode == FULL_VIEW) 726 - update_tree(&rootmenu, NULL); 727 - else if (view_mode == SPLIT_VIEW) { 728 - update_tree(browsed, NULL); 729 - display_list(); 730 - } 731 - else if (view_mode == SINGLE_VIEW) 732 - display_tree_part(); //fixme: keep exp/coll 813 + update_trees(); 733 814 } 734 815 735 816 static gint column2index(GtkTreeViewColumn * column) ··· 742 837 743 838 744 839 /* User click: update choice (full) or goes down (single) */ 745 - gboolean 746 - on_treeview2_button_press_event(GtkWidget * widget, 747 - GdkEventButton * event, gpointer user_data) 840 + static gboolean on_treeview2_button_press_event(GtkWidget *widget, 841 + GdkEventButton *event, 842 + gpointer user_data) 748 843 { 749 844 GtkTreeView *view = GTK_TREE_VIEW(widget); 845 + GtkTreeModel *model = gtk_tree_view_get_model(view); 750 846 GtkTreePath *path; 751 847 GtkTreeViewColumn *column; 752 848 GtkTreeIter iter; 753 849 struct menu *menu; 754 850 gint col; 755 - 756 - #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK 757 851 gint tx = (gint) event->x; 758 852 gint ty = (gint) event->y; 759 - gint cx, cy; 760 853 761 - gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, 762 - &cy); 763 - #else 764 - gtk_tree_view_get_cursor(view, &path, &column); 765 - #endif 854 + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, NULL, NULL); 766 855 if (path == NULL) 767 856 return FALSE; 768 857 769 - if (!gtk_tree_model_get_iter(model2, &iter, path)) 858 + if (!gtk_tree_model_get_iter(model, &iter, path)) 770 859 return FALSE; 771 - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 860 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 861 + 862 + selected = menu; 772 863 773 864 col = column2index(column); 774 865 if (event->type == GDK_2BUTTON_PRESS) { 775 866 enum prop_type ptype; 776 867 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 777 868 778 - if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { 869 + if (ptype == P_MENU && view_mode == SINGLE_VIEW && col == COL_OPTION) { 779 870 // goes down into menu 780 - current = menu; 781 - display_tree_part(); 871 + browsed = menu; 872 + recreate_tree(); 782 873 gtk_widget_set_sensitive(back_btn, TRUE); 783 874 } else if (col == COL_OPTION) { 784 875 toggle_sym_value(menu); ··· 795 894 } 796 895 797 896 /* Key pressed: update choice */ 798 - gboolean 799 - on_treeview2_key_press_event(GtkWidget * widget, 800 - GdkEventKey * event, gpointer user_data) 897 + static gboolean on_treeview2_key_press_event(GtkWidget *widget, 898 + GdkEventKey *event, 899 + gpointer user_data) 801 900 { 802 901 GtkTreeView *view = GTK_TREE_VIEW(widget); 902 + GtkTreeModel *model = gtk_tree_view_get_model(view); 803 903 GtkTreePath *path; 804 - GtkTreeViewColumn *column; 805 904 GtkTreeIter iter; 806 905 struct menu *menu; 807 906 gint col; 808 907 809 - gtk_tree_view_get_cursor(view, &path, &column); 908 + gtk_tree_view_get_cursor(view, &path, NULL); 810 909 if (path == NULL) 811 910 return FALSE; 812 911 813 - if (event->keyval == GDK_space) { 912 + if (event->keyval == GDK_KEY_space) { 814 913 if (gtk_tree_view_row_expanded(view, path)) 815 914 gtk_tree_view_collapse_row(view, path); 816 915 else 817 916 gtk_tree_view_expand_row(view, path, FALSE); 818 917 return TRUE; 819 918 } 820 - if (event->keyval == GDK_KP_Enter) { 821 - } 822 - if (widget == tree1_w) 823 - return FALSE; 824 919 825 - gtk_tree_model_get_iter(model2, &iter, path); 826 - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 920 + gtk_tree_model_get_iter(model, &iter, path); 921 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 827 922 828 923 if (!strcasecmp(event->string, "n")) 829 924 col = COL_NO; ··· 836 939 837 940 838 941 /* Row selection changed: update help */ 839 - void 840 - on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) 942 + static void on_treeview2_cursor_changed(GtkTreeView *treeview, 943 + gpointer user_data) 841 944 { 945 + GtkTreeModel *model = gtk_tree_view_get_model(treeview); 842 946 GtkTreeSelection *selection; 843 947 GtkTreeIter iter; 844 948 struct menu *menu; 845 949 846 950 selection = gtk_tree_view_get_selection(treeview); 847 - if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { 848 - gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 951 + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { 952 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 849 953 text_insert_help(menu); 850 954 } 851 955 } 852 956 853 957 854 958 /* User click: display sub-tree in the right frame. */ 855 - gboolean 856 - on_treeview1_button_press_event(GtkWidget * widget, 857 - GdkEventButton * event, gpointer user_data) 959 + static gboolean on_treeview1_button_press_event(GtkWidget *widget, 960 + GdkEventButton *event, 961 + gpointer user_data) 858 962 { 859 963 GtkTreeView *view = GTK_TREE_VIEW(widget); 964 + GtkTreeModel *model = gtk_tree_view_get_model(view); 860 965 GtkTreePath *path; 861 - GtkTreeViewColumn *column; 862 966 GtkTreeIter iter; 863 967 struct menu *menu; 864 - 865 968 gint tx = (gint) event->x; 866 969 gint ty = (gint) event->y; 867 - gint cx, cy; 868 970 869 - gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, 870 - &cy); 971 + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, NULL, NULL, NULL); 871 972 if (path == NULL) 872 973 return FALSE; 873 974 874 - gtk_tree_model_get_iter(model1, &iter, path); 875 - gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); 975 + gtk_tree_model_get_iter(model, &iter, path); 976 + gtk_tree_model_get(model, &iter, COL_MENU, &menu, -1); 876 977 877 - if (event->type == GDK_2BUTTON_PRESS) { 978 + if (event->type == GDK_2BUTTON_PRESS) 878 979 toggle_sym_value(menu); 879 - current = menu; 880 - display_tree_part(); 881 - } else { 980 + 981 + selected = menu; 982 + 983 + if (menu->type == M_MENU) { 882 984 browsed = menu; 883 - display_tree_part(); 985 + recreate_tree(); 884 986 } 885 987 886 - gtk_widget_realize(tree2_w); 887 988 gtk_tree_view_set_cursor(view, path, NULL, FALSE); 888 989 gtk_widget_grab_focus(tree2_w); 889 990 890 991 return FALSE; 891 992 } 892 993 893 - 894 - /* Fill a row of strings */ 895 - static gchar **fill_row(struct menu *menu) 896 - { 897 - static gchar *row[COL_NUMBER]; 898 - struct symbol *sym = menu->sym; 899 - const char *def; 900 - int stype; 901 - tristate val; 902 - enum prop_type ptype; 903 - int i; 904 - 905 - for (i = COL_OPTION; i <= COL_COLOR; i++) 906 - g_free(row[i]); 907 - bzero(row, sizeof(row)); 908 - 909 - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 910 - 911 - row[COL_OPTION] = 912 - g_strdup_printf("%s %s %s %s", 913 - ptype == P_COMMENT ? "***" : "", 914 - menu_get_prompt(menu), 915 - ptype == P_COMMENT ? "***" : "", 916 - sym && !sym_has_value(sym) ? "(NEW)" : ""); 917 - 918 - if (opt_mode == OPT_ALL && !menu_is_visible(menu)) 919 - row[COL_COLOR] = g_strdup("DarkGray"); 920 - else if (opt_mode == OPT_PROMPT && 921 - menu_has_prompt(menu) && !menu_is_visible(menu)) 922 - row[COL_COLOR] = g_strdup("DarkGray"); 923 - else 924 - row[COL_COLOR] = g_strdup("Black"); 925 - 926 - switch (ptype) { 927 - case P_MENU: 928 - row[COL_PIXBUF] = (gchar *) xpm_menu; 929 - if (view_mode == SINGLE_VIEW) 930 - row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); 931 - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 932 - break; 933 - case P_COMMENT: 934 - row[COL_PIXBUF] = (gchar *) xpm_void; 935 - row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); 936 - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 937 - break; 938 - default: 939 - row[COL_PIXBUF] = (gchar *) xpm_void; 940 - row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); 941 - row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); 942 - break; 943 - } 944 - 945 - if (!sym) 946 - return row; 947 - row[COL_NAME] = g_strdup(sym->name); 948 - 949 - sym_calc_value(sym); 950 - menu->flags &= ~MENU_CHANGED; 951 - 952 - if (sym_is_choice(sym)) { // parse childs for getting final value 953 - struct menu *child; 954 - struct symbol *def_sym = sym_calc_choice(menu); 955 - struct menu *def_menu = NULL; 956 - 957 - for (child = menu->list; child; child = child->next) { 958 - if (menu_is_visible(child) 959 - && child->sym == def_sym) 960 - def_menu = child; 961 - } 962 - 963 - if (def_menu) 964 - row[COL_VALUE] = 965 - g_strdup(menu_get_prompt(def_menu)); 966 - 967 - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 968 - return row; 969 - } 970 - if (sym_is_choice_value(sym)) 971 - row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); 972 - 973 - stype = sym_get_type(sym); 974 - switch (stype) { 975 - case S_BOOLEAN: 976 - case S_TRISTATE: 977 - val = sym_get_tristate_value(sym); 978 - switch (val) { 979 - case no: 980 - row[COL_NO] = g_strdup("N"); 981 - row[COL_VALUE] = g_strdup("N"); 982 - row[COL_BTNACT] = GINT_TO_POINTER(FALSE); 983 - row[COL_BTNINC] = GINT_TO_POINTER(FALSE); 984 - break; 985 - case mod: 986 - row[COL_MOD] = g_strdup("M"); 987 - row[COL_VALUE] = g_strdup("M"); 988 - row[COL_BTNINC] = GINT_TO_POINTER(TRUE); 989 - break; 990 - case yes: 991 - row[COL_YES] = g_strdup("Y"); 992 - row[COL_VALUE] = g_strdup("Y"); 993 - row[COL_BTNACT] = GINT_TO_POINTER(TRUE); 994 - row[COL_BTNINC] = GINT_TO_POINTER(FALSE); 995 - break; 996 - } 997 - 998 - if (val != no && sym_tristate_within_range(sym, no)) 999 - row[COL_NO] = g_strdup("_"); 1000 - if (val != mod && sym_tristate_within_range(sym, mod)) 1001 - row[COL_MOD] = g_strdup("_"); 1002 - if (val != yes && sym_tristate_within_range(sym, yes)) 1003 - row[COL_YES] = g_strdup("_"); 1004 - break; 1005 - case S_INT: 1006 - case S_HEX: 1007 - case S_STRING: 1008 - def = sym_get_string_value(sym); 1009 - row[COL_VALUE] = g_strdup(def); 1010 - row[COL_EDIT] = GINT_TO_POINTER(TRUE); 1011 - row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 1012 - break; 1013 - } 1014 - 1015 - return row; 1016 - } 1017 - 1018 - 1019 - /* Set the node content with a row of strings */ 1020 - static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) 1021 - { 1022 - GdkColor color; 1023 - gboolean success; 1024 - GdkPixbuf *pix; 1025 - 1026 - pix = gdk_pixbuf_new_from_xpm_data((const char **) 1027 - row[COL_PIXBUF]); 1028 - 1029 - gdk_color_parse(row[COL_COLOR], &color); 1030 - gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, 1031 - FALSE, FALSE, &success); 1032 - 1033 - gtk_tree_store_set(tree, node, 1034 - COL_OPTION, row[COL_OPTION], 1035 - COL_NAME, row[COL_NAME], 1036 - COL_NO, row[COL_NO], 1037 - COL_MOD, row[COL_MOD], 1038 - COL_YES, row[COL_YES], 1039 - COL_VALUE, row[COL_VALUE], 1040 - COL_MENU, (gpointer) menu, 1041 - COL_COLOR, &color, 1042 - COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), 1043 - COL_PIXBUF, pix, 1044 - COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), 1045 - COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), 1046 - COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), 1047 - COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), 1048 - COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), 1049 - -1); 1050 - 1051 - g_object_unref(pix); 1052 - } 1053 - 1054 - 1055 - /* Add a node to the tree */ 1056 - static void place_node(struct menu *menu, char **row) 1057 - { 1058 - GtkTreeIter *parent = parents[indent - 1]; 1059 - GtkTreeIter *node = parents[indent]; 1060 - 1061 - gtk_tree_store_append(tree, node, parent); 1062 - set_node(node, menu, row); 1063 - } 1064 - 1065 - 1066 - /* Find a node in the GTK+ tree */ 1067 - static GtkTreeIter found; 1068 - 1069 - /* 1070 - * Find a menu in the GtkTree starting at parent. 1071 - */ 1072 - static GtkTreeIter *gtktree_iter_find_node(GtkTreeIter *parent, 1073 - struct menu *tofind) 1074 - { 1075 - GtkTreeIter iter; 1076 - GtkTreeIter *child = &iter; 1077 - gboolean valid; 1078 - GtkTreeIter *ret; 1079 - 1080 - valid = gtk_tree_model_iter_children(model2, child, parent); 1081 - while (valid) { 1082 - struct menu *menu; 1083 - 1084 - gtk_tree_model_get(model2, child, 6, &menu, -1); 1085 - 1086 - if (menu == tofind) { 1087 - memcpy(&found, child, sizeof(GtkTreeIter)); 1088 - return &found; 1089 - } 1090 - 1091 - ret = gtktree_iter_find_node(child, tofind); 1092 - if (ret) 1093 - return ret; 1094 - 1095 - valid = gtk_tree_model_iter_next(model2, child); 1096 - } 1097 - 1098 - return NULL; 1099 - } 1100 - 1101 - 1102 - /* 1103 - * Update the tree by adding/removing entries 1104 - * Does not change other nodes 1105 - */ 1106 - static void update_tree(struct menu *src, GtkTreeIter * dst) 1107 - { 1108 - struct menu *child1; 1109 - GtkTreeIter iter, tmp; 1110 - GtkTreeIter *child2 = &iter; 1111 - gboolean valid; 1112 - GtkTreeIter *sibling; 1113 - struct symbol *sym; 1114 - struct menu *menu1, *menu2; 1115 - 1116 - if (src == &rootmenu) 1117 - indent = 1; 1118 - 1119 - valid = gtk_tree_model_iter_children(model2, child2, dst); 1120 - for (child1 = src->list; child1; child1 = child1->next) { 1121 - 1122 - sym = child1->sym; 1123 - 1124 - reparse: 1125 - menu1 = child1; 1126 - if (valid) 1127 - gtk_tree_model_get(model2, child2, COL_MENU, 1128 - &menu2, -1); 1129 - else 1130 - menu2 = NULL; // force adding of a first child 1131 - 1132 - if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || 1133 - (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || 1134 - (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { 1135 - 1136 - /* remove node */ 1137 - if (gtktree_iter_find_node(dst, menu1) != NULL) { 1138 - memcpy(&tmp, child2, sizeof(GtkTreeIter)); 1139 - valid = gtk_tree_model_iter_next(model2, 1140 - child2); 1141 - gtk_tree_store_remove(tree2, &tmp); 1142 - if (!valid) 1143 - return; /* next parent */ 1144 - else 1145 - goto reparse; /* next child */ 1146 - } else 1147 - continue; 1148 - } 1149 - 1150 - if (menu1 != menu2) { 1151 - if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node 1152 - if (!valid && !menu2) 1153 - sibling = NULL; 1154 - else 1155 - sibling = child2; 1156 - gtk_tree_store_insert_before(tree2, 1157 - child2, 1158 - dst, sibling); 1159 - set_node(child2, menu1, fill_row(menu1)); 1160 - if (menu2 == NULL) 1161 - valid = TRUE; 1162 - } else { // remove node 1163 - memcpy(&tmp, child2, sizeof(GtkTreeIter)); 1164 - valid = gtk_tree_model_iter_next(model2, 1165 - child2); 1166 - gtk_tree_store_remove(tree2, &tmp); 1167 - if (!valid) 1168 - return; // next parent 1169 - else 1170 - goto reparse; // next child 1171 - } 1172 - } else if (sym && (child1->flags & MENU_CHANGED)) { 1173 - set_node(child2, menu1, fill_row(menu1)); 1174 - } 1175 - 1176 - indent++; 1177 - update_tree(child1, child2); 1178 - indent--; 1179 - 1180 - valid = gtk_tree_model_iter_next(model2, child2); 1181 - } 1182 - } 1183 - 1184 - 1185 994 /* Display the whole tree (single/split/full view) */ 1186 - static void display_tree(struct menu *menu) 995 + static void _display_tree(GtkTreeStore *tree, struct menu *menu, 996 + GtkTreeIter *parent) 1187 997 { 1188 - struct property *prop; 1189 998 struct menu *child; 1190 - enum prop_type ptype; 1191 - 1192 - if (menu == &rootmenu) { 1193 - indent = 1; 1194 - current = &rootmenu; 1195 - } 999 + GtkTreeIter iter; 1196 1000 1197 1001 for (child = menu->list; child; child = child->next) { 1198 - prop = child->prompt; 1199 - ptype = prop ? prop->type : P_UNKNOWN; 1200 - 1201 - menu->flags &= ~MENU_CHANGED; 1002 + /* 1003 + * REVISIT: 1004 + * menu_finalize() creates empty "if" entries. 1005 + * Do not confuse gtk_tree_model_get(), which would otherwise 1006 + * return "if" menu entry. 1007 + */ 1008 + if (child->type == M_IF) 1009 + continue; 1202 1010 1203 1011 if ((view_mode == SPLIT_VIEW) 1204 1012 && !(child->flags & MENU_ROOT) && (tree == tree1)) ··· 913 1311 && (tree == tree2)) 914 1312 continue; 915 1313 916 - if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || 917 - (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || 918 - (opt_mode == OPT_ALL && menu_get_prompt(child))) 919 - place_node(child, fill_row(child)); 1314 + gtk_tree_store_append(tree, &iter, parent); 1315 + set_node(tree, &iter, child); 920 1316 921 - if ((view_mode != FULL_VIEW) && (ptype == P_MENU) 922 - && (tree == tree2)) 923 - continue; 924 - /* 925 - if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) 926 - || (view_mode == FULL_VIEW) 927 - || (view_mode == SPLIT_VIEW))*/ 928 - 929 - /* Change paned position if the view is not in 'split mode' */ 930 - if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) { 931 - gtk_paned_set_position(GTK_PANED(hpaned), 0); 932 - } 933 - 934 - if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) 935 - || (view_mode == FULL_VIEW) 936 - || (view_mode == SPLIT_VIEW)) { 937 - indent++; 938 - display_tree(child); 939 - indent--; 940 - } 1317 + if (view_mode != SINGLE_VIEW || child->type != M_MENU) 1318 + _display_tree(tree, child, &iter); 941 1319 } 942 1320 } 943 1321 944 - /* Display a part of the tree starting at current node (single/split view) */ 945 - static void display_tree_part(void) 1322 + static void display_tree(GtkTreeStore *store, struct menu *menu) 946 1323 { 947 - if (tree2) 948 - gtk_tree_store_clear(tree2); 949 - if (view_mode == SINGLE_VIEW) 950 - display_tree(current); 951 - else if (view_mode == SPLIT_VIEW) 952 - display_tree(browsed); 953 - else if (view_mode == FULL_VIEW) 954 - display_tree(&rootmenu); 955 - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); 1324 + _display_tree(store, menu, NULL); 956 1325 } 957 1326 958 - /* Display the list in the left frame (split view) */ 959 - static void display_list(void) 1327 + /* Recreate the tree store starting at 'browsed' node */ 1328 + static void recreate_tree(void) 960 1329 { 961 - if (tree1) 962 - gtk_tree_store_clear(tree1); 963 - 964 - tree = tree1; 965 - display_tree(&rootmenu); 966 - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); 967 - tree = tree2; 1330 + gtk_tree_store_clear(tree2); 1331 + display_tree(tree2, browsed); 1332 + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); 968 1333 } 969 1334 970 1335 static void fixup_rootmenu(struct menu *menu) ··· 950 1381 } 951 1382 } 952 1383 1384 + /* Main Window Initialization */ 1385 + static void replace_button_icon(GtkWidget *widget, const char * const xpm[]) 1386 + { 1387 + GdkPixbuf *pixbuf; 1388 + GtkWidget *image; 1389 + 1390 + pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)xpm); 1391 + image = gtk_image_new_from_pixbuf(pixbuf); 1392 + g_object_unref(pixbuf); 1393 + 1394 + gtk_widget_show(image); 1395 + gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(widget), image); 1396 + } 1397 + 1398 + static void init_main_window(const gchar *glade_file) 1399 + { 1400 + GtkBuilder *builder; 1401 + GtkWidget *widget; 1402 + GtkTextBuffer *txtbuf; 1403 + 1404 + builder = gtk_builder_new_from_file(glade_file); 1405 + if (!builder) 1406 + g_error("GUI loading failed !\n"); 1407 + 1408 + main_wnd = GTK_WIDGET(gtk_builder_get_object(builder, "window1")); 1409 + g_signal_connect(main_wnd, "destroy", 1410 + G_CALLBACK(on_window1_destroy), NULL); 1411 + g_signal_connect(main_wnd, "configure-event", 1412 + G_CALLBACK(on_window1_configure), NULL); 1413 + g_signal_connect(main_wnd, "delete-event", 1414 + G_CALLBACK(on_window1_delete_event), NULL); 1415 + 1416 + hpaned = GTK_WIDGET(gtk_builder_get_object(builder, "hpaned1")); 1417 + vpaned = GTK_WIDGET(gtk_builder_get_object(builder, "vpaned1")); 1418 + tree1_w = GTK_WIDGET(gtk_builder_get_object(builder, "treeview1")); 1419 + g_signal_connect(tree1_w, "cursor-changed", 1420 + G_CALLBACK(on_treeview2_cursor_changed), NULL); 1421 + g_signal_connect(tree1_w, "button-press-event", 1422 + G_CALLBACK(on_treeview1_button_press_event), NULL); 1423 + g_signal_connect(tree1_w, "key-press-event", 1424 + G_CALLBACK(on_treeview2_key_press_event), NULL); 1425 + 1426 + tree2_w = GTK_WIDGET(gtk_builder_get_object(builder, "treeview2")); 1427 + g_signal_connect(tree2_w, "cursor-changed", 1428 + G_CALLBACK(on_treeview2_cursor_changed), NULL); 1429 + g_signal_connect(tree2_w, "button-press-event", 1430 + G_CALLBACK(on_treeview2_button_press_event), NULL); 1431 + g_signal_connect(tree2_w, "key-press-event", 1432 + G_CALLBACK(on_treeview2_key_press_event), NULL); 1433 + 1434 + text_w = GTK_WIDGET(gtk_builder_get_object(builder, "textview3")); 1435 + 1436 + /* menubar */ 1437 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "load1")); 1438 + g_signal_connect(widget, "activate", 1439 + G_CALLBACK(on_load1_activate), NULL); 1440 + 1441 + save_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "save1")); 1442 + g_signal_connect(save_menu_item, "activate", 1443 + G_CALLBACK(on_save_activate), NULL); 1444 + 1445 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "save_as1")); 1446 + g_signal_connect(widget, "activate", 1447 + G_CALLBACK(on_save_as1_activate), NULL); 1448 + 1449 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "quit1")); 1450 + g_signal_connect(widget, "activate", 1451 + G_CALLBACK(on_quit1_activate), NULL); 1452 + 1453 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_name1")); 1454 + g_signal_connect(widget, "activate", 1455 + G_CALLBACK(on_show_name1_activate), NULL); 1456 + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 1457 + show_name); 1458 + 1459 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_range1")); 1460 + g_signal_connect(widget, "activate", 1461 + G_CALLBACK(on_show_range1_activate), NULL); 1462 + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 1463 + show_range); 1464 + 1465 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "show_data1")); 1466 + g_signal_connect(widget, "activate", 1467 + G_CALLBACK(on_show_data1_activate), NULL); 1468 + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 1469 + show_value); 1470 + 1471 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode1")); 1472 + g_signal_connect(widget, "activate", 1473 + G_CALLBACK(on_set_option_mode1_activate), NULL); 1474 + 1475 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode2")); 1476 + g_signal_connect(widget, "activate", 1477 + G_CALLBACK(on_set_option_mode2_activate), NULL); 1478 + 1479 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "set_option_mode3")); 1480 + g_signal_connect(widget, "activate", 1481 + G_CALLBACK(on_set_option_mode3_activate), NULL); 1482 + 1483 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "introduction1")); 1484 + g_signal_connect(widget, "activate", 1485 + G_CALLBACK(on_introduction1_activate), NULL); 1486 + 1487 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "about1")); 1488 + g_signal_connect(widget, "activate", 1489 + G_CALLBACK(on_about1_activate), NULL); 1490 + 1491 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "license1")); 1492 + g_signal_connect(widget, "activate", 1493 + G_CALLBACK(on_license1_activate), NULL); 1494 + 1495 + /* toolbar */ 1496 + back_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button1")); 1497 + g_signal_connect(back_btn, "clicked", 1498 + G_CALLBACK(on_back_clicked), NULL); 1499 + gtk_widget_set_sensitive(back_btn, FALSE); 1500 + 1501 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "button2")); 1502 + g_signal_connect(widget, "clicked", 1503 + G_CALLBACK(on_load_clicked), NULL); 1504 + 1505 + save_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button3")); 1506 + g_signal_connect(save_btn, "clicked", 1507 + G_CALLBACK(on_save_clicked), NULL); 1508 + 1509 + single_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button4")); 1510 + g_signal_connect(single_btn, "clicked", 1511 + G_CALLBACK(on_single_clicked), NULL); 1512 + replace_button_icon(single_btn, xpm_single_view); 1513 + 1514 + split_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button5")); 1515 + g_signal_connect(split_btn, "clicked", 1516 + G_CALLBACK(on_split_clicked), NULL); 1517 + replace_button_icon(split_btn, xpm_split_view); 1518 + 1519 + full_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button6")); 1520 + g_signal_connect(full_btn, "clicked", 1521 + G_CALLBACK(on_full_clicked), NULL); 1522 + replace_button_icon(full_btn, xpm_tree_view); 1523 + 1524 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "button7")); 1525 + g_signal_connect(widget, "clicked", 1526 + G_CALLBACK(on_collapse_clicked), NULL); 1527 + 1528 + widget = GTK_WIDGET(gtk_builder_get_object(builder, "button8")); 1529 + g_signal_connect(widget, "clicked", 1530 + G_CALLBACK(on_expand_clicked), NULL); 1531 + 1532 + txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 1533 + tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", 1534 + "foreground", "red", 1535 + "weight", PANGO_WEIGHT_BOLD, 1536 + NULL); 1537 + tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", 1538 + /*"style", PANGO_STYLE_OBLIQUE, */ 1539 + NULL); 1540 + 1541 + gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); 1542 + 1543 + gtk_widget_show_all(main_wnd); 1544 + 1545 + g_object_unref(builder); 1546 + 1547 + conf_set_changed_callback(conf_changed); 1548 + } 1549 + 1550 + static gboolean visible_func(GtkTreeModel *model, GtkTreeIter *iter, 1551 + gpointer data) 1552 + { 1553 + struct menu *menu; 1554 + 1555 + gtk_tree_model_get(model, iter, COL_MENU, &menu, -1); 1556 + 1557 + if (!menu) 1558 + return FALSE; 1559 + 1560 + return menu_is_visible(menu) || opt_mode == OPT_ALL || 1561 + (opt_mode == OPT_PROMPT && menu_has_prompt(menu)); 1562 + } 1563 + 1564 + static void init_left_tree(void) 1565 + { 1566 + GtkTreeView *view = GTK_TREE_VIEW(tree1_w); 1567 + GtkCellRenderer *renderer; 1568 + GtkTreeSelection *sel; 1569 + GtkTreeViewColumn *column; 1570 + GtkTreeModel *filter; 1571 + 1572 + tree1 = gtk_tree_store_new(COL_NUMBER, 1573 + G_TYPE_STRING, G_TYPE_STRING, 1574 + G_TYPE_STRING, G_TYPE_STRING, 1575 + G_TYPE_STRING, G_TYPE_STRING, 1576 + G_TYPE_POINTER, GDK_TYPE_RGBA, 1577 + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, 1578 + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 1579 + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 1580 + G_TYPE_BOOLEAN); 1581 + 1582 + filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(tree1), NULL); 1583 + 1584 + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter), 1585 + visible_func, NULL, NULL); 1586 + gtk_tree_view_set_model(view, filter); 1587 + 1588 + column = gtk_tree_view_column_new(); 1589 + gtk_tree_view_append_column(view, column); 1590 + gtk_tree_view_column_set_title(column, "Options"); 1591 + 1592 + renderer = gtk_cell_renderer_toggle_new(); 1593 + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 1594 + renderer, FALSE); 1595 + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 1596 + renderer, 1597 + "active", COL_BTNACT, 1598 + "inconsistent", COL_BTNINC, 1599 + "visible", COL_BTNVIS, 1600 + "radio", COL_BTNRAD, NULL); 1601 + renderer = gtk_cell_renderer_text_new(); 1602 + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 1603 + renderer, FALSE); 1604 + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 1605 + renderer, 1606 + "text", COL_OPTION, 1607 + "foreground-rgba", 1608 + COL_COLOR, NULL); 1609 + 1610 + sel = gtk_tree_view_get_selection(view); 1611 + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); 1612 + } 1613 + 1614 + static void init_right_tree(void) 1615 + { 1616 + GtkTreeView *view = GTK_TREE_VIEW(tree2_w); 1617 + GtkCellRenderer *renderer; 1618 + GtkTreeSelection *sel; 1619 + GtkTreeViewColumn *column; 1620 + GtkTreeModel *filter; 1621 + gint i; 1622 + 1623 + tree2 = gtk_tree_store_new(COL_NUMBER, 1624 + G_TYPE_STRING, G_TYPE_STRING, 1625 + G_TYPE_STRING, G_TYPE_STRING, 1626 + G_TYPE_STRING, G_TYPE_STRING, 1627 + G_TYPE_POINTER, GDK_TYPE_RGBA, 1628 + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, 1629 + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 1630 + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 1631 + G_TYPE_BOOLEAN); 1632 + 1633 + filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(tree2), NULL); 1634 + 1635 + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter), 1636 + visible_func, NULL, NULL); 1637 + gtk_tree_view_set_model(view, filter); 1638 + 1639 + column = gtk_tree_view_column_new(); 1640 + gtk_tree_view_append_column(view, column); 1641 + gtk_tree_view_column_set_title(column, "Options"); 1642 + 1643 + renderer = gtk_cell_renderer_pixbuf_new(); 1644 + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 1645 + renderer, FALSE); 1646 + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 1647 + renderer, 1648 + "pixbuf", COL_PIXBUF, 1649 + "visible", COL_PIXVIS, NULL); 1650 + renderer = gtk_cell_renderer_toggle_new(); 1651 + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 1652 + renderer, FALSE); 1653 + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 1654 + renderer, 1655 + "active", COL_BTNACT, 1656 + "inconsistent", COL_BTNINC, 1657 + "visible", COL_BTNVIS, 1658 + "radio", COL_BTNRAD, NULL); 1659 + renderer = gtk_cell_renderer_text_new(); 1660 + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 1661 + renderer, FALSE); 1662 + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 1663 + renderer, 1664 + "text", COL_OPTION, 1665 + "foreground-rgba", 1666 + COL_COLOR, NULL); 1667 + 1668 + renderer = gtk_cell_renderer_text_new(); 1669 + gtk_tree_view_insert_column_with_attributes(view, -1, 1670 + "Name", renderer, 1671 + "text", COL_NAME, 1672 + "foreground-rgba", 1673 + COL_COLOR, NULL); 1674 + renderer = gtk_cell_renderer_text_new(); 1675 + gtk_tree_view_insert_column_with_attributes(view, -1, 1676 + "N", renderer, 1677 + "text", COL_NO, 1678 + "foreground-rgba", 1679 + COL_COLOR, NULL); 1680 + renderer = gtk_cell_renderer_text_new(); 1681 + gtk_tree_view_insert_column_with_attributes(view, -1, 1682 + "M", renderer, 1683 + "text", COL_MOD, 1684 + "foreground-rgba", 1685 + COL_COLOR, NULL); 1686 + renderer = gtk_cell_renderer_text_new(); 1687 + gtk_tree_view_insert_column_with_attributes(view, -1, 1688 + "Y", renderer, 1689 + "text", COL_YES, 1690 + "foreground-rgba", 1691 + COL_COLOR, NULL); 1692 + renderer = gtk_cell_renderer_text_new(); 1693 + gtk_tree_view_insert_column_with_attributes(view, -1, 1694 + "Value", renderer, 1695 + "text", COL_VALUE, 1696 + "editable", 1697 + COL_EDIT, 1698 + "foreground-rgba", 1699 + COL_COLOR, NULL); 1700 + g_signal_connect(G_OBJECT(renderer), "edited", 1701 + G_CALLBACK(renderer_edited), tree2_w); 1702 + 1703 + pix_menu = gdk_pixbuf_new_from_xpm_data((const char **)xpm_menu); 1704 + 1705 + for (i = 0; i < COL_VALUE; i++) { 1706 + column = gtk_tree_view_get_column(view, i); 1707 + gtk_tree_view_column_set_resizable(column, TRUE); 1708 + } 1709 + 1710 + sel = gtk_tree_view_get_selection(view); 1711 + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); 1712 + } 953 1713 954 1714 /* Main */ 955 1715 int main(int ac, char *av[]) ··· 1288 1390 gchar *glade_file; 1289 1391 1290 1392 /* GTK stuffs */ 1291 - gtk_set_locale(); 1292 1393 gtk_init(&ac, &av); 1293 - glade_init(); 1294 1394 1295 1395 /* Determine GUI path */ 1296 1396 env = getenv(SRCTREE); 1297 1397 if (env) 1298 - glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); 1398 + glade_file = g_strconcat(env, "/scripts/kconfig/gconf.ui", NULL); 1299 1399 else if (av[0][0] == '/') 1300 - glade_file = g_strconcat(av[0], ".glade", NULL); 1400 + glade_file = g_strconcat(av[0], ".ui", NULL); 1301 1401 else 1302 - glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); 1402 + glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".ui", NULL); 1303 1403 1304 1404 /* Conf stuffs */ 1305 1405 if (ac > 1 && av[1][0] == '-') { ··· 1322 1426 1323 1427 /* Load the interface and connect signals */ 1324 1428 init_main_window(glade_file); 1325 - init_tree_model(); 1326 1429 init_left_tree(); 1327 1430 init_right_tree(); 1328 1431 1329 1432 conf_read(NULL); 1330 1433 1331 - switch (view_mode) { 1332 - case SINGLE_VIEW: 1333 - display_tree_part(); 1334 - break; 1335 - case SPLIT_VIEW: 1336 - display_list(); 1337 - break; 1338 - case FULL_VIEW: 1339 - display_tree(&rootmenu); 1340 - break; 1341 - } 1434 + set_view_mode(view_mode); 1342 1435 1343 1436 gtk_main(); 1344 1437
+118 -243
scripts/kconfig/gconf.glade scripts/kconfig/gconf.ui
··· 1 1 <?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> 2 2 3 - <glade-interface> 3 + <interface> 4 4 5 - <widget class="GtkWindow" id="window1"> 5 + <object class="GtkWindow" id="window1"> 6 6 <property name="visible">True</property> 7 7 <property name="title" translatable="yes">Gtk Kernel Configurator</property> 8 8 <property name="type">GTK_WINDOW_TOPLEVEL</property> ··· 17 17 <property name="skip_pager_hint">False</property> 18 18 <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> 19 19 <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> 20 - <signal name="destroy" handler="on_window1_destroy" object="window1"/> 21 - <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/> 22 - <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/> 23 20 24 21 <child> 25 - <widget class="GtkVBox" id="vbox1"> 22 + <object class="GtkBox" id="vbox1"> 23 + <property name="orientation">vertical</property> 26 24 <property name="visible">True</property> 27 25 <property name="homogeneous">False</property> 28 26 <property name="spacing">0</property> 29 27 30 28 <child> 31 - <widget class="GtkMenuBar" id="menubar1"> 29 + <object class="GtkMenuBar" id="menubar1"> 32 30 <property name="visible">True</property> 33 31 34 32 <child> 35 - <widget class="GtkMenuItem" id="file1"> 33 + <object class="GtkMenuItem" id="file1"> 36 34 <property name="visible">True</property> 37 35 <property name="label" translatable="yes">_File</property> 38 36 <property name="use_underline">True</property> 39 37 40 - <child> 41 - <widget class="GtkMenu" id="file1_menu"> 38 + <child type="submenu"> 39 + <object class="GtkMenu" id="file1_menu"> 42 40 43 41 <child> 44 - <widget class="GtkImageMenuItem" id="load1"> 42 + <object class="GtkMenuItem" id="load1"> 45 43 <property name="visible">True</property> 46 - <property name="tooltip" translatable="yes">Load a config file</property> 44 + <property name="tooltip-text" translatable="yes">Load a config file</property> 47 45 <property name="label" translatable="yes">_Load</property> 48 46 <property name="use_underline">True</property> 49 - <signal name="activate" handler="on_load1_activate"/> 50 47 <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/> 51 - 52 - <child internal-child="image"> 53 - <widget class="GtkImage" id="image39"> 54 - <property name="visible">True</property> 55 - <property name="stock">gtk-open</property> 56 - <property name="icon_size">1</property> 57 - <property name="xalign">0.5</property> 58 - <property name="yalign">0.5</property> 59 - <property name="xpad">0</property> 60 - <property name="ypad">0</property> 61 - </widget> 62 - </child> 63 - </widget> 48 + </object> 64 49 </child> 65 50 66 51 <child> 67 - <widget class="GtkImageMenuItem" id="save1"> 52 + <object class="GtkMenuItem" id="save1"> 68 53 <property name="visible">True</property> 69 - <property name="tooltip" translatable="yes">Save the config in .config</property> 54 + <property name="tooltip-text" translatable="yes">Save the config in .config</property> 70 55 <property name="label" translatable="yes">_Save</property> 71 56 <property name="use_underline">True</property> 72 - <signal name="activate" handler="on_save_activate"/> 73 57 <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/> 74 - 75 - <child internal-child="image"> 76 - <widget class="GtkImage" id="image40"> 77 - <property name="visible">True</property> 78 - <property name="stock">gtk-save</property> 79 - <property name="icon_size">1</property> 80 - <property name="xalign">0.5</property> 81 - <property name="yalign">0.5</property> 82 - <property name="xpad">0</property> 83 - <property name="ypad">0</property> 84 - </widget> 85 - </child> 86 - </widget> 58 + </object> 87 59 </child> 88 60 89 61 <child> 90 - <widget class="GtkImageMenuItem" id="save_as1"> 62 + <object class="GtkMenuItem" id="save_as1"> 91 63 <property name="visible">True</property> 92 - <property name="tooltip" translatable="yes">Save the config in a file</property> 64 + <property name="tooltip-text" translatable="yes">Save the config in a file</property> 93 65 <property name="label" translatable="yes">Save _as</property> 94 66 <property name="use_underline">True</property> 95 - <signal name="activate" handler="on_save_as1_activate"/> 96 - 97 - <child internal-child="image"> 98 - <widget class="GtkImage" id="image41"> 99 - <property name="visible">True</property> 100 - <property name="stock">gtk-save-as</property> 101 - <property name="icon_size">1</property> 102 - <property name="xalign">0.5</property> 103 - <property name="yalign">0.5</property> 104 - <property name="xpad">0</property> 105 - <property name="ypad">0</property> 106 - </widget> 107 - </child> 108 - </widget> 67 + </object> 109 68 </child> 110 69 111 70 <child> 112 - <widget class="GtkSeparatorMenuItem" id="separator1"> 71 + <object class="GtkSeparatorMenuItem" id="separator1"> 113 72 <property name="visible">True</property> 114 - </widget> 73 + </object> 115 74 </child> 116 75 117 76 <child> 118 - <widget class="GtkImageMenuItem" id="quit1"> 77 + <object class="GtkMenuItem" id="quit1"> 119 78 <property name="visible">True</property> 120 79 <property name="label" translatable="yes">_Quit</property> 121 80 <property name="use_underline">True</property> 122 - <signal name="activate" handler="on_quit1_activate"/> 123 81 <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> 124 - 125 - <child internal-child="image"> 126 - <widget class="GtkImage" id="image42"> 127 - <property name="visible">True</property> 128 - <property name="stock">gtk-quit</property> 129 - <property name="icon_size">1</property> 130 - <property name="xalign">0.5</property> 131 - <property name="yalign">0.5</property> 132 - <property name="xpad">0</property> 133 - <property name="ypad">0</property> 134 - </widget> 135 - </child> 136 - </widget> 82 + </object> 137 83 </child> 138 - </widget> 84 + </object> 139 85 </child> 140 - </widget> 86 + </object> 141 87 </child> 142 88 143 89 <child> 144 - <widget class="GtkMenuItem" id="options1"> 90 + <object class="GtkMenuItem" id="options1"> 145 91 <property name="visible">True</property> 146 92 <property name="label" translatable="yes">_Options</property> 147 93 <property name="use_underline">True</property> 148 94 149 - <child> 150 - <widget class="GtkMenu" id="options1_menu"> 95 + <child type="submenu"> 96 + <object class="GtkMenu" id="options1_menu"> 151 97 152 98 <child> 153 - <widget class="GtkCheckMenuItem" id="show_name1"> 99 + <object class="GtkCheckMenuItem" id="show_name1"> 154 100 <property name="visible">True</property> 155 - <property name="tooltip" translatable="yes">Show name</property> 101 + <property name="tooltip-text" translatable="yes">Show name</property> 156 102 <property name="label" translatable="yes">Show _name</property> 157 103 <property name="use_underline">True</property> 158 104 <property name="active">False</property> 159 - <signal name="activate" handler="on_show_name1_activate"/> 160 - </widget> 105 + </object> 161 106 </child> 162 107 163 108 <child> 164 - <widget class="GtkCheckMenuItem" id="show_range1"> 109 + <object class="GtkCheckMenuItem" id="show_range1"> 165 110 <property name="visible">True</property> 166 - <property name="tooltip" translatable="yes">Show range (Y/M/N)</property> 111 + <property name="tooltip-text" translatable="yes">Show range (Y/M/N)</property> 167 112 <property name="label" translatable="yes">Show _range</property> 168 113 <property name="use_underline">True</property> 169 114 <property name="active">False</property> 170 - <signal name="activate" handler="on_show_range1_activate"/> 171 - </widget> 115 + </object> 172 116 </child> 173 117 174 118 <child> 175 - <widget class="GtkCheckMenuItem" id="show_data1"> 119 + <object class="GtkCheckMenuItem" id="show_data1"> 176 120 <property name="visible">True</property> 177 - <property name="tooltip" translatable="yes">Show value of the option</property> 121 + <property name="tooltip-text" translatable="yes">Show value of the option</property> 178 122 <property name="label" translatable="yes">Show _data</property> 179 123 <property name="use_underline">True</property> 180 124 <property name="active">False</property> 181 - <signal name="activate" handler="on_show_data1_activate"/> 182 - </widget> 125 + </object> 183 126 </child> 184 127 185 128 <child> 186 - <widget class="GtkSeparatorMenuItem" id="separator2"> 129 + <object class="GtkSeparatorMenuItem" id="separator2"> 187 130 <property name="visible">True</property> 188 - </widget> 131 + </object> 189 132 </child> 190 133 191 134 <child> 192 - <widget class="GtkRadioMenuItem" id="set_option_mode1"> 135 + <object class="GtkRadioMenuItem" id="set_option_mode1"> 193 136 <property name="visible">True</property> 194 - <property name="tooltip" translatable="yes">Show normal options</property> 137 + <property name="tooltip-text" translatable="yes">Show normal options</property> 195 138 <property name="label" translatable="yes">Show normal options</property> 196 139 <property name="use_underline">True</property> 197 140 <property name="active">True</property> 198 - <signal name="activate" handler="on_set_option_mode1_activate"/> 199 - </widget> 141 + </object> 200 142 </child> 201 143 202 144 <child> 203 - <widget class="GtkRadioMenuItem" id="set_option_mode2"> 145 + <object class="GtkRadioMenuItem" id="set_option_mode2"> 204 146 <property name="visible">True</property> 205 - <property name="tooltip" translatable="yes">Show all options</property> 147 + <property name="tooltip-text" translatable="yes">Show all options</property> 206 148 <property name="label" translatable="yes">Show all _options</property> 207 149 <property name="use_underline">True</property> 208 150 <property name="active">False</property> 209 151 <property name="group">set_option_mode1</property> 210 - <signal name="activate" handler="on_set_option_mode2_activate"/> 211 - </widget> 152 + </object> 212 153 </child> 213 154 214 155 <child> 215 - <widget class="GtkRadioMenuItem" id="set_option_mode3"> 156 + <object class="GtkRadioMenuItem" id="set_option_mode3"> 216 157 <property name="visible">True</property> 217 - <property name="tooltip" translatable="yes">Show all options with prompts</property> 158 + <property name="tooltip-text" translatable="yes">Show all options with prompts</property> 218 159 <property name="label" translatable="yes">Show all prompt options</property> 219 160 <property name="use_underline">True</property> 220 161 <property name="active">False</property> 221 162 <property name="group">set_option_mode1</property> 222 - <signal name="activate" handler="on_set_option_mode3_activate"/> 223 - </widget> 163 + </object> 224 164 </child> 225 165 226 - </widget> 166 + </object> 227 167 </child> 228 - </widget> 168 + </object> 229 169 </child> 230 170 231 171 <child> 232 - <widget class="GtkMenuItem" id="help1"> 172 + <object class="GtkMenuItem" id="help1"> 233 173 <property name="visible">True</property> 234 174 <property name="label" translatable="yes">_Help</property> 235 175 <property name="use_underline">True</property> 236 176 237 - <child> 238 - <widget class="GtkMenu" id="help1_menu"> 177 + <child type="submenu"> 178 + <object class="GtkMenu" id="help1_menu"> 239 179 240 180 <child> 241 - <widget class="GtkImageMenuItem" id="introduction1"> 181 + <object class="GtkMenuItem" id="introduction1"> 242 182 <property name="visible">True</property> 243 183 <property name="label" translatable="yes">_Introduction</property> 244 184 <property name="use_underline">True</property> 245 - <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/> 246 185 <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/> 247 - 248 - <child internal-child="image"> 249 - <widget class="GtkImage" id="image43"> 250 - <property name="visible">True</property> 251 - <property name="stock">gtk-dialog-question</property> 252 - <property name="icon_size">1</property> 253 - <property name="xalign">0.5</property> 254 - <property name="yalign">0.5</property> 255 - <property name="xpad">0</property> 256 - <property name="ypad">0</property> 257 - </widget> 258 - </child> 259 - </widget> 186 + </object> 260 187 </child> 261 188 262 189 <child> 263 - <widget class="GtkImageMenuItem" id="about1"> 190 + <object class="GtkMenuItem" id="about1"> 264 191 <property name="visible">True</property> 265 192 <property name="label" translatable="yes">_About</property> 266 193 <property name="use_underline">True</property> 267 - <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/> 268 194 <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/> 269 - 270 - <child internal-child="image"> 271 - <widget class="GtkImage" id="image44"> 272 - <property name="visible">True</property> 273 - <property name="stock">gtk-properties</property> 274 - <property name="icon_size">1</property> 275 - <property name="xalign">0.5</property> 276 - <property name="yalign">0.5</property> 277 - <property name="xpad">0</property> 278 - <property name="ypad">0</property> 279 - </widget> 280 - </child> 281 - </widget> 195 + </object> 282 196 </child> 283 197 284 198 <child> 285 - <widget class="GtkImageMenuItem" id="license1"> 199 + <object class="GtkMenuItem" id="license1"> 286 200 <property name="visible">True</property> 287 201 <property name="label" translatable="yes">_License</property> 288 202 <property name="use_underline">True</property> 289 - <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/> 290 - 291 - <child internal-child="image"> 292 - <widget class="GtkImage" id="image45"> 293 - <property name="visible">True</property> 294 - <property name="stock">gtk-justify-fill</property> 295 - <property name="icon_size">1</property> 296 - <property name="xalign">0.5</property> 297 - <property name="yalign">0.5</property> 298 - <property name="xpad">0</property> 299 - <property name="ypad">0</property> 300 - </widget> 301 - </child> 302 - </widget> 203 + </object> 303 204 </child> 304 - </widget> 205 + </object> 305 206 </child> 306 - </widget> 207 + </object> 307 208 </child> 308 - </widget> 209 + </object> 309 210 <packing> 310 211 <property name="padding">0</property> 311 212 <property name="expand">False</property> ··· 215 314 </child> 216 315 217 316 <child> 218 - <widget class="GtkHandleBox" id="handlebox1"> 219 - <property name="visible">True</property> 220 - <property name="shadow_type">GTK_SHADOW_OUT</property> 221 - <property name="handle_position">GTK_POS_LEFT</property> 222 - <property name="snap_edge">GTK_POS_TOP</property> 223 - 224 - <child> 225 - <widget class="GtkToolbar" id="toolbar1"> 317 + <object class="GtkToolbar" id="toolbar1"> 226 318 <property name="visible">True</property> 227 319 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> 228 320 <property name="toolbar_style">GTK_TOOLBAR_BOTH</property> 229 - <property name="tooltips">True</property> 230 321 <property name="show_arrow">True</property> 231 322 232 323 <child> 233 - <widget class="GtkToolButton" id="button1"> 324 + <object class="GtkToolButton" id="button1"> 234 325 <property name="visible">True</property> 235 - <property name="tooltip" translatable="yes">Goes up of one level (single view)</property> 326 + <property name="tooltip-text" translatable="yes">Goes up one level (single view)</property> 236 327 <property name="label" translatable="yes">Back</property> 237 328 <property name="use_underline">True</property> 238 329 <property name="stock_id">gtk-undo</property> 239 330 <property name="visible_horizontal">True</property> 240 331 <property name="visible_vertical">True</property> 241 332 <property name="is_important">False</property> 242 - <signal name="clicked" handler="on_back_clicked"/> 243 - </widget> 333 + </object> 244 334 <packing> 245 335 <property name="expand">False</property> 246 336 <property name="homogeneous">True</property> ··· 239 347 </child> 240 348 241 349 <child> 242 - <widget class="GtkToolItem" id="toolitem1"> 350 + <object class="GtkToolItem" id="toolitem1"> 243 351 <property name="visible">True</property> 244 352 <property name="visible_horizontal">True</property> 245 353 <property name="visible_vertical">True</property> 246 354 <property name="is_important">False</property> 247 355 248 356 <child> 249 - <widget class="GtkVSeparator" id="vseparator1"> 357 + <object class="GtkVSeparator" id="vseparator1"> 250 358 <property name="visible">True</property> 251 - </widget> 359 + </object> 252 360 </child> 253 - </widget> 361 + </object> 254 362 <packing> 255 363 <property name="expand">False</property> 256 364 <property name="homogeneous">False</property> ··· 258 366 </child> 259 367 260 368 <child> 261 - <widget class="GtkToolButton" id="button2"> 369 + <object class="GtkToolButton" id="button2"> 262 370 <property name="visible">True</property> 263 - <property name="tooltip" translatable="yes">Load a config file</property> 371 + <property name="tooltip-text" translatable="yes">Load a config file</property> 264 372 <property name="label" translatable="yes">Load</property> 265 373 <property name="use_underline">True</property> 266 374 <property name="stock_id">gtk-open</property> 267 375 <property name="visible_horizontal">True</property> 268 376 <property name="visible_vertical">True</property> 269 377 <property name="is_important">False</property> 270 - <signal name="clicked" handler="on_load_clicked"/> 271 - </widget> 378 + </object> 272 379 <packing> 273 380 <property name="expand">False</property> 274 381 <property name="homogeneous">True</property> ··· 275 384 </child> 276 385 277 386 <child> 278 - <widget class="GtkToolButton" id="button3"> 387 + <object class="GtkToolButton" id="button3"> 279 388 <property name="visible">True</property> 280 - <property name="tooltip" translatable="yes">Save a config file</property> 389 + <property name="tooltip-text" translatable="yes">Save a config file</property> 281 390 <property name="label" translatable="yes">Save</property> 282 391 <property name="use_underline">True</property> 283 392 <property name="stock_id">gtk-save</property> 284 393 <property name="visible_horizontal">True</property> 285 394 <property name="visible_vertical">True</property> 286 395 <property name="is_important">False</property> 287 - <signal name="clicked" handler="on_save_activate"/> 288 - </widget> 396 + </object> 289 397 <packing> 290 398 <property name="expand">False</property> 291 399 <property name="homogeneous">True</property> ··· 292 402 </child> 293 403 294 404 <child> 295 - <widget class="GtkToolItem" id="toolitem2"> 405 + <object class="GtkToolItem" id="toolitem2"> 296 406 <property name="visible">True</property> 297 407 <property name="visible_horizontal">True</property> 298 408 <property name="visible_vertical">True</property> 299 409 <property name="is_important">False</property> 300 410 301 411 <child> 302 - <widget class="GtkVSeparator" id="vseparator2"> 412 + <object class="GtkVSeparator" id="vseparator2"> 303 413 <property name="visible">True</property> 304 - </widget> 414 + </object> 305 415 </child> 306 - </widget> 416 + </object> 307 417 <packing> 308 418 <property name="expand">False</property> 309 419 <property name="homogeneous">False</property> ··· 311 421 </child> 312 422 313 423 <child> 314 - <widget class="GtkToolButton" id="button4"> 424 + <object class="GtkToolButton" id="button4"> 315 425 <property name="visible">True</property> 316 - <property name="tooltip" translatable="yes">Single view</property> 426 + <property name="tooltip-text" translatable="yes">Single view</property> 317 427 <property name="label" translatable="yes">Single</property> 318 428 <property name="use_underline">True</property> 319 429 <property name="stock_id">gtk-missing-image</property> 320 430 <property name="visible_horizontal">True</property> 321 431 <property name="visible_vertical">True</property> 322 432 <property name="is_important">False</property> 323 - <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/> 324 - </widget> 433 + </object> 325 434 <packing> 326 435 <property name="expand">False</property> 327 436 <property name="homogeneous">True</property> ··· 328 439 </child> 329 440 330 441 <child> 331 - <widget class="GtkToolButton" id="button5"> 442 + <object class="GtkToolButton" id="button5"> 332 443 <property name="visible">True</property> 333 - <property name="tooltip" translatable="yes">Split view</property> 444 + <property name="tooltip-text" translatable="yes">Split view</property> 334 445 <property name="label" translatable="yes">Split</property> 335 446 <property name="use_underline">True</property> 336 447 <property name="stock_id">gtk-missing-image</property> 337 448 <property name="visible_horizontal">True</property> 338 449 <property name="visible_vertical">True</property> 339 450 <property name="is_important">False</property> 340 - <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/> 341 - </widget> 451 + </object> 342 452 <packing> 343 453 <property name="expand">False</property> 344 454 <property name="homogeneous">True</property> ··· 345 457 </child> 346 458 347 459 <child> 348 - <widget class="GtkToolButton" id="button6"> 460 + <object class="GtkToolButton" id="button6"> 349 461 <property name="visible">True</property> 350 - <property name="tooltip" translatable="yes">Full view</property> 462 + <property name="tooltip-text" translatable="yes">Full view</property> 351 463 <property name="label" translatable="yes">Full</property> 352 464 <property name="use_underline">True</property> 353 465 <property name="stock_id">gtk-missing-image</property> 354 466 <property name="visible_horizontal">True</property> 355 467 <property name="visible_vertical">True</property> 356 468 <property name="is_important">False</property> 357 - <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/> 358 - </widget> 469 + </object> 359 470 <packing> 360 471 <property name="expand">False</property> 361 472 <property name="homogeneous">True</property> ··· 362 475 </child> 363 476 364 477 <child> 365 - <widget class="GtkToolItem" id="toolitem3"> 478 + <object class="GtkToolItem" id="toolitem3"> 366 479 <property name="visible">True</property> 367 480 <property name="visible_horizontal">True</property> 368 481 <property name="visible_vertical">True</property> 369 482 <property name="is_important">False</property> 370 483 371 484 <child> 372 - <widget class="GtkVSeparator" id="vseparator3"> 485 + <object class="GtkVSeparator" id="vseparator3"> 373 486 <property name="visible">True</property> 374 - </widget> 487 + </object> 375 488 </child> 376 - </widget> 489 + </object> 377 490 <packing> 378 491 <property name="expand">False</property> 379 492 <property name="homogeneous">False</property> ··· 381 494 </child> 382 495 383 496 <child> 384 - <widget class="GtkToolButton" id="button7"> 497 + <object class="GtkToolButton" id="button7"> 385 498 <property name="visible">True</property> 386 - <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property> 499 + <property name="tooltip-text" translatable="yes">Collapse the whole tree in the right frame</property> 387 500 <property name="label" translatable="yes">Collapse</property> 388 501 <property name="use_underline">True</property> 389 502 <property name="stock_id">gtk-remove</property> 390 503 <property name="visible_horizontal">True</property> 391 504 <property name="visible_vertical">True</property> 392 505 <property name="is_important">False</property> 393 - <signal name="clicked" handler="on_collapse_clicked"/> 394 - </widget> 506 + </object> 395 507 <packing> 396 508 <property name="expand">False</property> 397 509 <property name="homogeneous">True</property> ··· 398 512 </child> 399 513 400 514 <child> 401 - <widget class="GtkToolButton" id="button8"> 515 + <object class="GtkToolButton" id="button8"> 402 516 <property name="visible">True</property> 403 - <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property> 517 + <property name="tooltip-text" translatable="yes">Expand the whole tree in the right frame</property> 404 518 <property name="label" translatable="yes">Expand</property> 405 519 <property name="use_underline">True</property> 406 520 <property name="stock_id">gtk-add</property> 407 521 <property name="visible_horizontal">True</property> 408 522 <property name="visible_vertical">True</property> 409 523 <property name="is_important">False</property> 410 - <signal name="clicked" handler="on_expand_clicked"/> 411 - </widget> 524 + </object> 412 525 <packing> 413 526 <property name="expand">False</property> 414 527 <property name="homogeneous">True</property> 415 528 </packing> 416 529 </child> 417 - </widget> 418 - </child> 419 - </widget> 530 + </object> 420 531 <packing> 421 532 <property name="padding">0</property> 422 533 <property name="expand">False</property> ··· 422 539 </child> 423 540 424 541 <child> 425 - <widget class="GtkHPaned" id="hpaned1"> 542 + <object class="GtkPaned" id="hpaned1"> 426 543 <property name="width_request">1</property> 427 544 <property name="visible">True</property> 428 545 <property name="can_focus">True</property> 429 - <property name="position">0</property> 430 546 431 547 <child> 432 - <widget class="GtkScrolledWindow" id="scrolledwindow1"> 548 + <object class="GtkScrolledWindow" id="scrolledwindow1"> 433 549 <property name="visible">True</property> 434 550 <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> 435 551 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> ··· 436 554 <property name="window_placement">GTK_CORNER_TOP_LEFT</property> 437 555 438 556 <child> 439 - <widget class="GtkTreeView" id="treeview1"> 557 + <object class="GtkTreeView" id="treeview1"> 440 558 <property name="visible">True</property> 441 559 <property name="can_focus">True</property> 442 560 <property name="headers_visible">True</property> 443 561 <property name="rules_hint">False</property> 444 562 <property name="reorderable">False</property> 445 563 <property name="enable_search">False</property> 446 - <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/> 447 - <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/> 448 - <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/> 449 - </widget> 564 + </object> 450 565 </child> 451 - </widget> 566 + </object> 452 567 <packing> 453 568 <property name="shrink">True</property> 454 569 <property name="resize">False</property> ··· 453 574 </child> 454 575 455 576 <child> 456 - <widget class="GtkVPaned" id="vpaned1"> 577 + <object class="GtkPaned" id="vpaned1"> 578 + <property name="orientation">vertical</property> 457 579 <property name="visible">True</property> 458 580 <property name="can_focus">True</property> 459 - <property name="position">0</property> 460 581 461 582 <child> 462 - <widget class="GtkScrolledWindow" id="scrolledwindow2"> 583 + <object class="GtkScrolledWindow" id="scrolledwindow2"> 463 584 <property name="visible">True</property> 464 585 <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> 465 586 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> ··· 467 588 <property name="window_placement">GTK_CORNER_TOP_LEFT</property> 468 589 469 590 <child> 470 - <widget class="GtkTreeView" id="treeview2"> 591 + <object class="GtkTreeView" id="treeview2"> 471 592 <property name="visible">True</property> 472 593 <property name="can_focus">True</property> 473 594 <property name="has_focus">True</property> ··· 475 596 <property name="rules_hint">False</property> 476 597 <property name="reorderable">False</property> 477 598 <property name="enable_search">False</property> 478 - <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/> 479 - <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/> 480 - <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/> 481 - </widget> 599 + </object> 482 600 </child> 483 - </widget> 601 + </object> 484 602 <packing> 485 603 <property name="shrink">True</property> 486 604 <property name="resize">False</property> ··· 485 609 </child> 486 610 487 611 <child> 488 - <widget class="GtkScrolledWindow" id="scrolledwindow3"> 612 + <object class="GtkScrolledWindow" id="scrolledwindow3"> 489 613 <property name="visible">True</property> 490 614 <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> 491 615 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> ··· 493 617 <property name="window_placement">GTK_CORNER_TOP_LEFT</property> 494 618 495 619 <child> 496 - <widget class="GtkTextView" id="textview3"> 620 + <object class="GtkTextView" id="textview3"> 497 621 <property name="visible">True</property> 498 622 <property name="can_focus">True</property> 499 623 <property name="editable">False</property> ··· 508 632 <property name="left_margin">0</property> 509 633 <property name="right_margin">0</property> 510 634 <property name="indent">0</property> 511 - <property name="text" translatable="yes">Sorry, no help available for this option yet.</property> 512 - </widget> 635 + </object> 513 636 </child> 514 - </widget> 637 + </object> 515 638 <packing> 516 639 <property name="shrink">True</property> 517 640 <property name="resize">True</property> 518 641 </packing> 519 642 </child> 520 - </widget> 643 + </object> 521 644 <packing> 522 645 <property name="shrink">True</property> 523 646 <property name="resize">True</property> 524 647 </packing> 525 648 </child> 526 - </widget> 649 + </object> 527 650 <packing> 528 651 <property name="padding">0</property> 529 652 <property name="expand">True</property> 530 653 <property name="fill">True</property> 531 654 </packing> 532 655 </child> 533 - </widget> 656 + </object> 534 657 </child> 535 - </widget> 658 + </object> 536 659 537 - </glade-interface> 660 + </interface>
+2
scripts/kconfig/lkc.h
··· 98 98 bool menu_has_prompt(const struct menu *menu); 99 99 const char *menu_get_prompt(const struct menu *menu); 100 100 struct menu *menu_get_parent_menu(struct menu *menu); 101 + struct menu *menu_get_menu_or_parent_menu(struct menu *menu); 101 102 int get_jump_key_char(void); 102 103 struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); 103 104 void menu_get_ext_help(struct menu *menu, struct gstr *help); 105 + void menu_dump(void); 104 106 105 107 /* symbol.c */ 106 108 void sym_clear_all_valid(void);
+4 -2
scripts/kconfig/lxdialog/inputbox.c
··· 39 39 40 40 if (!init) 41 41 instr[0] = '\0'; 42 - else 43 - strcpy(instr, init); 42 + else { 43 + strncpy(instr, init, sizeof(dialog_input_result) - 1); 44 + instr[sizeof(dialog_input_result) - 1] = '\0'; 45 + } 44 46 45 47 do_resize: 46 48 if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGHT_MIN))
+1 -1
scripts/kconfig/lxdialog/menubox.c
··· 264 264 if (key < 256 && isalpha(key)) 265 265 key = tolower(key); 266 266 267 - if (strchr("ynmh", key)) 267 + if (strchr("ynmh ", key)) 268 268 i = max_choice; 269 269 else { 270 270 for (i = choice + 1; i < max_choice; i++) {
+1 -2
scripts/kconfig/lxdialog/util.c
··· 345 345 int prompt_len, room, wlen; 346 346 char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0; 347 347 348 - strcpy(tempstr, prompt); 349 - 348 + snprintf(tempstr, sizeof(tempstr), "%s", prompt); 350 349 prompt_len = strlen(tempstr); 351 350 352 351 if (prompt_len <= width - x * 2) { /* If prompt is short */
+94
scripts/kconfig/menu.c
··· 575 575 return NULL; 576 576 } 577 577 578 + /** 579 + * menu_get_parent_menu - return the parent menu or NULL 580 + * @menu: pointer to the menu 581 + * return: the parent menu, or NULL if there is no parent. 582 + */ 578 583 struct menu *menu_get_parent_menu(struct menu *menu) 584 + { 585 + for (menu = menu->parent; menu; menu = menu->parent) 586 + if (menu->type == M_MENU) 587 + return menu; 588 + 589 + return NULL; 590 + } 591 + 592 + /** 593 + * menu_get_menu_or_parent_menu - return the parent menu or the menu itself 594 + * @menu: pointer to the menu 595 + * return: the parent menu. If the given argument is already a menu, return 596 + * itself. 597 + */ 598 + struct menu *menu_get_menu_or_parent_menu(struct menu *menu) 579 599 { 580 600 enum prop_type type; 581 601 ··· 787 767 str_printf(help, "%s\n", help_text); 788 768 if (sym) 789 769 get_symbol_str(help, sym, NULL); 770 + } 771 + 772 + /** 773 + * menu_dump - dump all menu entries in a tree-like format 774 + */ 775 + void menu_dump(void) 776 + { 777 + struct menu *menu = &rootmenu; 778 + unsigned long long bits = 0; 779 + int indent = 0; 780 + 781 + while (menu) { 782 + 783 + for (int i = indent - 1; i >= 0; i--) { 784 + if (bits & (1ULL << i)) { 785 + if (i > 0) 786 + printf("| "); 787 + else 788 + printf("|-- "); 789 + } else { 790 + if (i > 0) 791 + printf(" "); 792 + else 793 + printf("`-- "); 794 + } 795 + } 796 + 797 + switch (menu->type) { 798 + case M_CHOICE: 799 + printf("choice \"%s\"\n", menu->prompt->text); 800 + break; 801 + case M_COMMENT: 802 + printf("comment \"%s\"\n", menu->prompt->text); 803 + break; 804 + case M_IF: 805 + printf("if\n"); 806 + break; 807 + case M_MENU: 808 + printf("menu \"%s\"", menu->prompt->text); 809 + if (!menu->sym) { 810 + printf("\n"); 811 + break; 812 + } 813 + printf(" + "); 814 + /* fallthrough */ 815 + case M_NORMAL: 816 + printf("symbol %s\n", menu->sym->name); 817 + break; 818 + } 819 + if (menu->list) { 820 + bits <<= 1; 821 + menu = menu->list; 822 + if (menu->next) 823 + bits |= 1; 824 + else 825 + bits &= ~1; 826 + indent++; 827 + continue; 828 + } 829 + 830 + while (menu && !menu->next) { 831 + menu = menu->parent; 832 + bits >>= 1; 833 + indent--; 834 + } 835 + 836 + if (menu) { 837 + menu = menu->next; 838 + if (menu->next) 839 + bits |= 1; 840 + else 841 + bits &= ~1; 842 + } 843 + } 790 844 }
+2
scripts/kconfig/nconf.c
··· 593 593 tmp_str, 594 594 sizeof(k_menu_items[index].str)); 595 595 596 + k_menu_items[index].str[sizeof(k_menu_items[index].str) - 1] = '\0'; 597 + 596 598 free_item(curses_menu_items[index]); 597 599 curses_menu_items[index] = new_item( 598 600 k_menu_items[index].str,
+1
scripts/kconfig/nconf.gui.c
··· 359 359 x = (columns-win_cols)/2; 360 360 361 361 strncpy(result, init, *result_len); 362 + result[*result_len - 1] = '\0'; 362 363 363 364 /* create the windows */ 364 365 win = newwin(win_lines, win_cols, y, x);
+24 -12
scripts/kconfig/qconf.cc
··· 37 37 ConfigSettings::ConfigSettings() 38 38 : QSettings("kernel.org", "qconf") 39 39 { 40 + beginGroup("/kconfig/qconf"); 41 + } 42 + 43 + ConfigSettings::~ConfigSettings() 44 + { 45 + endGroup(); 40 46 } 41 47 42 48 /** ··· 98 92 { 99 93 ConfigList* list; 100 94 struct symbol* sym; 101 - struct property *prop; 102 95 QString prompt; 103 96 int type; 104 97 tristate expr; ··· 110 105 } 111 106 112 107 sym = menu->sym; 113 - prop = menu->prompt; 114 108 prompt = menu_get_prompt(menu); 115 109 116 - if (prop) switch (prop->type) { 117 - case P_MENU: 110 + switch (menu->type) { 111 + case M_MENU: 118 112 if (list->mode == singleMode) { 119 113 /* a menuconfig entry is displayed differently 120 114 * depending whether it's at the view root or a child. ··· 127 123 setIcon(promptColIdx, QIcon()); 128 124 } 129 125 goto set_prompt; 130 - case P_COMMENT: 126 + case M_COMMENT: 131 127 setIcon(promptColIdx, QIcon()); 132 128 prompt = "*** " + prompt + " ***"; 129 + goto set_prompt; 130 + case M_CHOICE: 131 + setIcon(promptColIdx, QIcon()); 132 + sym = sym_calc_choice(menu); 133 + if (sym) 134 + setText(dataColIdx, sym->name); 133 135 goto set_prompt; 134 136 default: 135 137 ; ··· 198 188 if (!menu) 199 189 return; 200 190 201 - sym_calc_value(menu->sym); 191 + if (menu->type == M_CHOICE) 192 + sym_calc_choice(menu); 193 + else 194 + sym_calc_value(menu->sym); 195 + 202 196 if (menu->flags & MENU_CHANGED) { 203 197 /* the menu entry changed, so update all list items */ 204 198 menu->flags &= ~MENU_CHANGED; ··· 492 478 while (it.hasNext()) { 493 479 ConfigList *list = it.next(); 494 480 495 - list->updateList(); 481 + list->updateListAll(); 496 482 } 497 483 } 498 484 ··· 583 569 oldroot = rootEntry; 584 570 if (rootEntry == &rootmenu) 585 571 return; 586 - setRootMenu(menu_get_parent_menu(rootEntry->parent)); 572 + setRootMenu(menu_get_menu_or_parent_menu(rootEntry->parent)); 587 573 588 574 QTreeWidgetItemIterator it(this); 589 575 while (*it) { ··· 1546 1532 switch (configList->mode) { 1547 1533 case singleMode: 1548 1534 list = configList; 1549 - parent = menu_get_parent_menu(menu); 1535 + parent = menu_get_menu_or_parent_menu(menu); 1550 1536 if (!parent) 1551 1537 return; 1552 1538 list->setRootMenu(parent); ··· 1557 1543 configList->clearSelection(); 1558 1544 list = configList; 1559 1545 } else { 1560 - parent = menu_get_parent_menu(menu->parent); 1546 + parent = menu_get_menu_or_parent_menu(menu->parent); 1561 1547 if (!parent) 1562 1548 return; 1563 1549 ··· 1835 1821 configApp = new QApplication(ac, av); 1836 1822 1837 1823 configSettings = new ConfigSettings(); 1838 - configSettings->beginGroup("/kconfig/qconf"); 1839 1824 v = new ConfigMainWindow(); 1840 1825 1841 1826 //zconfdump(stdout); ··· 1842 1829 v->show(); 1843 1830 configApp->exec(); 1844 1831 1845 - configSettings->endGroup(); 1846 1832 delete configSettings; 1847 1833 delete v; 1848 1834 delete configApp;
+1
scripts/kconfig/qconf.h
··· 24 24 class ConfigSettings : public QSettings { 25 25 public: 26 26 ConfigSettings(); 27 + ~ConfigSettings(void); 27 28 QList<int> readSizes(const QString& key, bool *ok); 28 29 bool writeSizes(const QString& key, const QList<int>& value); 29 30 };
+4
scripts/kconfig/symbol.c
··· 195 195 196 196 list_for_each_entry(menu, &sym->menus, link) 197 197 menu->flags |= MENU_CHANGED; 198 + 199 + menu = sym_get_choice_menu(sym); 200 + if (menu) 201 + menu->flags |= MENU_CHANGED; 198 202 } 199 203 200 204 static void sym_set_all_changed(void)
+16 -15
scripts/rustdoc_test_gen.rs
··· 85 85 } 86 86 } 87 87 88 - assert!( 89 - valid_paths.len() > 0, 90 - "No path candidates found for `{file}`. This is likely a bug in the build system, or some \ 91 - files went away while compiling." 92 - ); 88 + match valid_paths.as_slice() { 89 + [] => panic!( 90 + "No path candidates found for `{file}`. This is likely a bug in the build system, or \ 91 + some files went away while compiling." 92 + ), 93 + [valid_path] => valid_path.to_str().unwrap(), 94 + valid_paths => { 95 + use std::fmt::Write; 93 96 94 - if valid_paths.len() > 1 { 95 - eprintln!("Several path candidates found:"); 96 - for path in valid_paths { 97 - eprintln!(" {path:?}"); 97 + let mut candidates = String::new(); 98 + for path in valid_paths { 99 + writeln!(&mut candidates, " {path:?}").unwrap(); 100 + } 101 + panic!( 102 + "Several path candidates found for `{file}`, please resolve the ambiguity by \ 103 + renaming a file or folder. Candidates:\n{candidates}", 104 + ); 98 105 } 99 - panic!( 100 - "Several path candidates found for `{file}`, please resolve the ambiguity by renaming \ 101 - a file or folder." 102 - ); 103 106 } 104 - 105 - valid_paths[0].to_str().unwrap() 106 107 } 107 108 108 109 fn main() {
+1
scripts/spelling.txt
··· 1099 1099 notications||notifications 1100 1100 notifcations||notifications 1101 1101 notifed||notified 1102 + notifer||notifier 1102 1103 notity||notify 1103 1104 notfify||notify 1104 1105 nubmer||number
+3 -3
security/apparmor/Makefile
··· 6 6 apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \ 7 7 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ 8 8 resource.o secid.o file.o policy_ns.o label.o mount.o net.o \ 9 - policy_compat.o 9 + policy_compat.o af_unix.o 10 10 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o 11 11 12 12 obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o ··· 28 28 # to 29 29 # #define AA_SFS_AF_MASK "local inet" 30 30 quiet_cmd_make-af = GEN $@ 31 - cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ 31 + cmd_make-af = echo "static const char *const address_family_names[] = {" > $@ ;\ 32 32 sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ 33 33 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ 34 34 echo "};" >> $@ ;\ ··· 43 43 # to 44 44 # [1] = "stream", 45 45 quiet_cmd_make-sock = GEN $@ 46 - cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ 46 + cmd_make-sock = echo "static const char *const sock_type_names[] = {" >> $@ ;\ 47 47 sed $^ >>$@ -r -n \ 48 48 -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ 49 49 echo "};" >> $@
+799
security/apparmor/af_unix.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor af_unix fine grained mediation 6 + * 7 + * Copyright 2023 Canonical Ltd. 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License as 11 + * published by the Free Software Foundation, version 2 of the 12 + * License. 13 + */ 14 + 15 + #include <linux/fs.h> 16 + #include <net/tcp_states.h> 17 + 18 + #include "include/audit.h" 19 + #include "include/af_unix.h" 20 + #include "include/apparmor.h" 21 + #include "include/file.h" 22 + #include "include/label.h" 23 + #include "include/path.h" 24 + #include "include/policy.h" 25 + #include "include/cred.h" 26 + 27 + 28 + static inline struct sock *aa_unix_sk(struct unix_sock *u) 29 + { 30 + return &u->sk; 31 + } 32 + 33 + static int unix_fs_perm(const char *op, u32 mask, const struct cred *subj_cred, 34 + struct aa_label *label, struct path *path) 35 + { 36 + AA_BUG(!label); 37 + AA_BUG(!path); 38 + 39 + if (unconfined(label) || !label_mediates(label, AA_CLASS_FILE)) 40 + return 0; 41 + 42 + mask &= NET_FS_PERMS; 43 + /* if !u->path.dentry socket is being shutdown - implicit delegation 44 + * until obj delegation is supported 45 + */ 46 + if (path->dentry) { 47 + /* the sunpath may not be valid for this ns so use the path */ 48 + struct inode *inode = path->dentry->d_inode; 49 + vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(path->mnt), inode); 50 + struct path_cond cond = { 51 + .uid = vfsuid_into_kuid(vfsuid), 52 + .mode = inode->i_mode, 53 + }; 54 + 55 + return aa_path_perm(op, subj_cred, label, path, 56 + PATH_SOCK_COND, mask, &cond); 57 + } /* else implicitly delegated */ 58 + 59 + return 0; 60 + } 61 + 62 + /* match_addr special constants */ 63 + #define ABSTRACT_ADDR "\x00" /* abstract socket addr */ 64 + #define ANONYMOUS_ADDR "\x01" /* anonymous endpoint, no addr */ 65 + #define DISCONNECTED_ADDR "\x02" /* addr is another namespace */ 66 + #define SHUTDOWN_ADDR "\x03" /* path addr is shutdown and cleared */ 67 + #define FS_ADDR "/" /* path addr in fs */ 68 + 69 + static aa_state_t match_addr(struct aa_dfa *dfa, aa_state_t state, 70 + struct sockaddr_un *addr, int addrlen) 71 + { 72 + if (addr) 73 + /* include leading \0 */ 74 + state = aa_dfa_match_len(dfa, state, addr->sun_path, 75 + unix_addr_len(addrlen)); 76 + else 77 + state = aa_dfa_match_len(dfa, state, ANONYMOUS_ADDR, 1); 78 + /* todo: could change to out of band for cleaner separation */ 79 + state = aa_dfa_null_transition(dfa, state); 80 + 81 + return state; 82 + } 83 + 84 + static aa_state_t match_to_local(struct aa_policydb *policy, 85 + aa_state_t state, u32 request, 86 + int type, int protocol, 87 + struct sockaddr_un *addr, int addrlen, 88 + struct aa_perms **p, 89 + const char **info) 90 + { 91 + state = aa_match_to_prot(policy, state, request, PF_UNIX, type, 92 + protocol, NULL, info); 93 + if (state) { 94 + state = match_addr(policy->dfa, state, addr, addrlen); 95 + if (state) { 96 + /* todo: local label matching */ 97 + state = aa_dfa_null_transition(policy->dfa, state); 98 + if (!state) 99 + *info = "failed local label match"; 100 + } else { 101 + *info = "failed local address match"; 102 + } 103 + } 104 + 105 + return state; 106 + } 107 + 108 + struct sockaddr_un *aa_sunaddr(const struct unix_sock *u, int *addrlen) 109 + { 110 + struct unix_address *addr; 111 + 112 + /* memory barrier is sufficient see note in net/unix/af_unix.c */ 113 + addr = smp_load_acquire(&u->addr); 114 + if (addr) { 115 + *addrlen = addr->len; 116 + return addr->name; 117 + } 118 + *addrlen = 0; 119 + return NULL; 120 + } 121 + 122 + static aa_state_t match_to_sk(struct aa_policydb *policy, 123 + aa_state_t state, u32 request, 124 + struct unix_sock *u, struct aa_perms **p, 125 + const char **info) 126 + { 127 + int addrlen; 128 + struct sockaddr_un *addr = aa_sunaddr(u, &addrlen); 129 + 130 + return match_to_local(policy, state, request, u->sk.sk_type, 131 + u->sk.sk_protocol, addr, addrlen, p, info); 132 + } 133 + 134 + #define CMD_ADDR 1 135 + #define CMD_LISTEN 2 136 + #define CMD_OPT 4 137 + 138 + static aa_state_t match_to_cmd(struct aa_policydb *policy, aa_state_t state, 139 + u32 request, struct unix_sock *u, 140 + char cmd, struct aa_perms **p, 141 + const char **info) 142 + { 143 + AA_BUG(!p); 144 + 145 + state = match_to_sk(policy, state, request, u, p, info); 146 + if (state && !*p) { 147 + state = aa_dfa_match_len(policy->dfa, state, &cmd, 1); 148 + if (!state) 149 + *info = "failed cmd selection match"; 150 + } 151 + 152 + return state; 153 + } 154 + 155 + static aa_state_t match_to_peer(struct aa_policydb *policy, aa_state_t state, 156 + u32 request, struct unix_sock *u, 157 + struct sockaddr_un *peer_addr, int peer_addrlen, 158 + struct aa_perms **p, const char **info) 159 + { 160 + AA_BUG(!p); 161 + 162 + state = match_to_cmd(policy, state, request, u, CMD_ADDR, p, info); 163 + if (state && !*p) { 164 + state = match_addr(policy->dfa, state, peer_addr, peer_addrlen); 165 + if (!state) 166 + *info = "failed peer address match"; 167 + } 168 + 169 + return state; 170 + } 171 + 172 + static aa_state_t match_label(struct aa_profile *profile, 173 + struct aa_ruleset *rule, aa_state_t state, 174 + u32 request, struct aa_profile *peer, 175 + struct aa_perms *p, 176 + struct apparmor_audit_data *ad) 177 + { 178 + AA_BUG(!profile); 179 + AA_BUG(!peer); 180 + 181 + ad->peer = &peer->label; 182 + 183 + if (state && !p) { 184 + state = aa_dfa_match(rule->policy->dfa, state, 185 + peer->base.hname); 186 + if (!state) 187 + ad->info = "failed peer label match"; 188 + 189 + } 190 + 191 + return aa_do_perms(profile, rule->policy, state, request, p, ad); 192 + } 193 + 194 + 195 + /* unix sock creation comes before we know if the socket will be an fs 196 + * socket 197 + * v6 - semantics are handled by mapping in profile load 198 + * v7 - semantics require sock create for tasks creating an fs socket. 199 + * v8 - same as v7 200 + */ 201 + static int profile_create_perm(struct aa_profile *profile, int family, 202 + int type, int protocol, 203 + struct apparmor_audit_data *ad) 204 + { 205 + struct aa_ruleset *rules = profile->label.rules[0]; 206 + aa_state_t state; 207 + 208 + AA_BUG(!profile); 209 + AA_BUG(profile_unconfined(profile)); 210 + 211 + state = RULE_MEDIATES_v9NET(rules); 212 + if (state) { 213 + state = aa_match_to_prot(rules->policy, state, AA_MAY_CREATE, 214 + PF_UNIX, type, protocol, NULL, 215 + &ad->info); 216 + 217 + return aa_do_perms(profile, rules->policy, state, AA_MAY_CREATE, 218 + NULL, ad); 219 + } 220 + 221 + return aa_profile_af_perm(profile, ad, AA_MAY_CREATE, family, type, 222 + protocol); 223 + } 224 + 225 + static int profile_sk_perm(struct aa_profile *profile, 226 + struct apparmor_audit_data *ad, 227 + u32 request, struct sock *sk, struct path *path) 228 + { 229 + struct aa_ruleset *rules = profile->label.rules[0]; 230 + struct aa_perms *p = NULL; 231 + aa_state_t state; 232 + 233 + AA_BUG(!profile); 234 + AA_BUG(!sk); 235 + AA_BUG(profile_unconfined(profile)); 236 + 237 + state = RULE_MEDIATES_v9NET(rules); 238 + if (state) { 239 + if (is_unix_fs(sk)) 240 + return unix_fs_perm(ad->op, request, ad->subj_cred, 241 + &profile->label, 242 + &unix_sk(sk)->path); 243 + 244 + state = match_to_sk(rules->policy, state, request, unix_sk(sk), 245 + &p, &ad->info); 246 + 247 + return aa_do_perms(profile, rules->policy, state, request, p, 248 + ad); 249 + } 250 + 251 + return aa_profile_af_sk_perm(profile, ad, request, sk); 252 + } 253 + 254 + static int profile_bind_perm(struct aa_profile *profile, struct sock *sk, 255 + struct apparmor_audit_data *ad) 256 + { 257 + struct aa_ruleset *rules = profile->label.rules[0]; 258 + struct aa_perms *p = NULL; 259 + aa_state_t state; 260 + 261 + AA_BUG(!profile); 262 + AA_BUG(!sk); 263 + AA_BUG(!ad); 264 + AA_BUG(profile_unconfined(profile)); 265 + 266 + state = RULE_MEDIATES_v9NET(rules); 267 + if (state) { 268 + if (is_unix_addr_fs(ad->net.addr, ad->net.addrlen)) 269 + /* under v7-9 fs hook handles bind */ 270 + return 0; 271 + /* bind for abstract socket */ 272 + state = match_to_local(rules->policy, state, AA_MAY_BIND, 273 + sk->sk_type, sk->sk_protocol, 274 + unix_addr(ad->net.addr), 275 + ad->net.addrlen, 276 + &p, &ad->info); 277 + 278 + return aa_do_perms(profile, rules->policy, state, AA_MAY_BIND, 279 + p, ad); 280 + } 281 + 282 + return aa_profile_af_sk_perm(profile, ad, AA_MAY_BIND, sk); 283 + } 284 + 285 + static int profile_listen_perm(struct aa_profile *profile, struct sock *sk, 286 + int backlog, struct apparmor_audit_data *ad) 287 + { 288 + struct aa_ruleset *rules = profile->label.rules[0]; 289 + struct aa_perms *p = NULL; 290 + aa_state_t state; 291 + 292 + AA_BUG(!profile); 293 + AA_BUG(!sk); 294 + AA_BUG(!ad); 295 + AA_BUG(profile_unconfined(profile)); 296 + 297 + state = RULE_MEDIATES_v9NET(rules); 298 + if (state) { 299 + __be16 b = cpu_to_be16(backlog); 300 + 301 + if (is_unix_fs(sk)) 302 + return unix_fs_perm(ad->op, AA_MAY_LISTEN, 303 + ad->subj_cred, &profile->label, 304 + &unix_sk(sk)->path); 305 + 306 + state = match_to_cmd(rules->policy, state, AA_MAY_LISTEN, 307 + unix_sk(sk), CMD_LISTEN, &p, &ad->info); 308 + if (state && !p) { 309 + state = aa_dfa_match_len(rules->policy->dfa, state, 310 + (char *) &b, 2); 311 + if (!state) 312 + ad->info = "failed listen backlog match"; 313 + } 314 + return aa_do_perms(profile, rules->policy, state, AA_MAY_LISTEN, 315 + p, ad); 316 + } 317 + 318 + return aa_profile_af_sk_perm(profile, ad, AA_MAY_LISTEN, sk); 319 + } 320 + 321 + static int profile_accept_perm(struct aa_profile *profile, 322 + struct sock *sk, 323 + struct apparmor_audit_data *ad) 324 + { 325 + struct aa_ruleset *rules = profile->label.rules[0]; 326 + struct aa_perms *p = NULL; 327 + aa_state_t state; 328 + 329 + AA_BUG(!profile); 330 + AA_BUG(!sk); 331 + AA_BUG(!ad); 332 + AA_BUG(profile_unconfined(profile)); 333 + 334 + state = RULE_MEDIATES_v9NET(rules); 335 + if (state) { 336 + if (is_unix_fs(sk)) 337 + return unix_fs_perm(ad->op, AA_MAY_ACCEPT, 338 + ad->subj_cred, &profile->label, 339 + &unix_sk(sk)->path); 340 + 341 + state = match_to_sk(rules->policy, state, AA_MAY_ACCEPT, 342 + unix_sk(sk), &p, &ad->info); 343 + 344 + return aa_do_perms(profile, rules->policy, state, AA_MAY_ACCEPT, 345 + p, ad); 346 + } 347 + 348 + return aa_profile_af_sk_perm(profile, ad, AA_MAY_ACCEPT, sk); 349 + } 350 + 351 + static int profile_opt_perm(struct aa_profile *profile, u32 request, 352 + struct sock *sk, int optname, 353 + struct apparmor_audit_data *ad) 354 + { 355 + struct aa_ruleset *rules = profile->label.rules[0]; 356 + struct aa_perms *p = NULL; 357 + aa_state_t state; 358 + 359 + AA_BUG(!profile); 360 + AA_BUG(!sk); 361 + AA_BUG(!ad); 362 + AA_BUG(profile_unconfined(profile)); 363 + 364 + state = RULE_MEDIATES_v9NET(rules); 365 + if (state) { 366 + __be16 b = cpu_to_be16(optname); 367 + if (is_unix_fs(sk)) 368 + return unix_fs_perm(ad->op, request, 369 + ad->subj_cred, &profile->label, 370 + &unix_sk(sk)->path); 371 + 372 + state = match_to_cmd(rules->policy, state, request, unix_sk(sk), 373 + CMD_OPT, &p, &ad->info); 374 + if (state && !p) { 375 + state = aa_dfa_match_len(rules->policy->dfa, state, 376 + (char *) &b, 2); 377 + if (!state) 378 + ad->info = "failed sockopt match"; 379 + } 380 + return aa_do_perms(profile, rules->policy, state, request, p, 381 + ad); 382 + } 383 + 384 + return aa_profile_af_sk_perm(profile, ad, request, sk); 385 + } 386 + 387 + /* null peer_label is allowed, in which case the peer_sk label is used */ 388 + static int profile_peer_perm(struct aa_profile *profile, u32 request, 389 + struct sock *sk, struct path *path, 390 + struct sockaddr_un *peer_addr, 391 + int peer_addrlen, struct path *peer_path, 392 + struct aa_label *peer_label, 393 + struct apparmor_audit_data *ad) 394 + { 395 + struct aa_ruleset *rules = profile->label.rules[0]; 396 + struct aa_perms *p = NULL; 397 + aa_state_t state; 398 + 399 + AA_BUG(!profile); 400 + AA_BUG(profile_unconfined(profile)); 401 + AA_BUG(!sk); 402 + AA_BUG(!peer_label); 403 + AA_BUG(!ad); 404 + 405 + state = RULE_MEDIATES_v9NET(rules); 406 + if (state) { 407 + struct aa_profile *peerp; 408 + 409 + if (peer_path) 410 + return unix_fs_perm(ad->op, request, ad->subj_cred, 411 + &profile->label, peer_path); 412 + else if (path) 413 + return unix_fs_perm(ad->op, request, ad->subj_cred, 414 + &profile->label, path); 415 + state = match_to_peer(rules->policy, state, request, 416 + unix_sk(sk), 417 + peer_addr, peer_addrlen, &p, &ad->info); 418 + 419 + return fn_for_each_in_ns(peer_label, peerp, 420 + match_label(profile, rules, state, request, 421 + peerp, p, ad)); 422 + } 423 + 424 + return aa_profile_af_sk_perm(profile, ad, request, sk); 425 + } 426 + 427 + /* -------------------------------- */ 428 + 429 + int aa_unix_create_perm(struct aa_label *label, int family, int type, 430 + int protocol) 431 + { 432 + if (!unconfined(label)) { 433 + struct aa_profile *profile; 434 + DEFINE_AUDIT_NET(ad, OP_CREATE, current_cred(), NULL, family, 435 + type, protocol); 436 + 437 + return fn_for_each_confined(label, profile, 438 + profile_create_perm(profile, family, type, 439 + protocol, &ad)); 440 + } 441 + 442 + return 0; 443 + } 444 + 445 + static int aa_unix_label_sk_perm(const struct cred *subj_cred, 446 + struct aa_label *label, 447 + const char *op, u32 request, struct sock *sk, 448 + struct path *path) 449 + { 450 + if (!unconfined(label)) { 451 + struct aa_profile *profile; 452 + DEFINE_AUDIT_SK(ad, op, subj_cred, sk); 453 + 454 + return fn_for_each_confined(label, profile, 455 + profile_sk_perm(profile, &ad, request, sk, 456 + path)); 457 + } 458 + return 0; 459 + } 460 + 461 + /* revalidation, get/set attr, shutdown */ 462 + int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock) 463 + { 464 + struct aa_label *label; 465 + int error; 466 + 467 + label = begin_current_label_crit_section(); 468 + error = aa_unix_label_sk_perm(current_cred(), label, op, 469 + request, sock->sk, 470 + is_unix_fs(sock->sk) ? &unix_sk(sock->sk)->path : NULL); 471 + end_current_label_crit_section(label); 472 + 473 + return error; 474 + } 475 + 476 + static int valid_addr(struct sockaddr *addr, int addr_len) 477 + { 478 + struct sockaddr_un *sunaddr = unix_addr(addr); 479 + 480 + /* addr_len == offsetof(struct sockaddr_un, sun_path) is autobind */ 481 + if (addr_len < offsetof(struct sockaddr_un, sun_path) || 482 + addr_len > sizeof(*sunaddr)) 483 + return -EINVAL; 484 + return 0; 485 + } 486 + 487 + int aa_unix_bind_perm(struct socket *sock, struct sockaddr *addr, 488 + int addrlen) 489 + { 490 + struct aa_profile *profile; 491 + struct aa_label *label; 492 + int error = 0; 493 + 494 + error = valid_addr(addr, addrlen); 495 + if (error) 496 + return error; 497 + 498 + label = begin_current_label_crit_section(); 499 + /* fs bind is handled by mknod */ 500 + if (!unconfined(label)) { 501 + DEFINE_AUDIT_SK(ad, OP_BIND, current_cred(), sock->sk); 502 + 503 + ad.net.addr = unix_addr(addr); 504 + ad.net.addrlen = addrlen; 505 + 506 + error = fn_for_each_confined(label, profile, 507 + profile_bind_perm(profile, sock->sk, &ad)); 508 + } 509 + end_current_label_crit_section(label); 510 + 511 + return error; 512 + } 513 + 514 + /* 515 + * unix connections are covered by the 516 + * - unix_stream_connect (stream) and unix_may_send hooks (dgram) 517 + * - fs connect is handled by open 518 + * This is just here to document this is not needed for af_unix 519 + * 520 + int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, 521 + int addrlen) 522 + { 523 + return 0; 524 + } 525 + */ 526 + 527 + int aa_unix_listen_perm(struct socket *sock, int backlog) 528 + { 529 + struct aa_profile *profile; 530 + struct aa_label *label; 531 + int error = 0; 532 + 533 + label = begin_current_label_crit_section(); 534 + if (!unconfined(label)) { 535 + DEFINE_AUDIT_SK(ad, OP_LISTEN, current_cred(), sock->sk); 536 + 537 + error = fn_for_each_confined(label, profile, 538 + profile_listen_perm(profile, sock->sk, 539 + backlog, &ad)); 540 + } 541 + end_current_label_crit_section(label); 542 + 543 + return error; 544 + } 545 + 546 + 547 + /* ability of sock to connect, not peer address binding */ 548 + int aa_unix_accept_perm(struct socket *sock, struct socket *newsock) 549 + { 550 + struct aa_profile *profile; 551 + struct aa_label *label; 552 + int error = 0; 553 + 554 + label = begin_current_label_crit_section(); 555 + if (!unconfined(label)) { 556 + DEFINE_AUDIT_SK(ad, OP_ACCEPT, current_cred(), sock->sk); 557 + 558 + error = fn_for_each_confined(label, profile, 559 + profile_accept_perm(profile, sock->sk, &ad)); 560 + } 561 + end_current_label_crit_section(label); 562 + 563 + return error; 564 + } 565 + 566 + 567 + /* 568 + * dgram handled by unix_may_sendmsg, right to send on stream done at connect 569 + * could do per msg unix_stream here, but connect + socket transfer is 570 + * sufficient. This is just here to document this is not needed for af_unix 571 + * 572 + * sendmsg, recvmsg 573 + int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, 574 + struct msghdr *msg, int size) 575 + { 576 + return 0; 577 + } 578 + */ 579 + 580 + int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, 581 + int level, int optname) 582 + { 583 + struct aa_profile *profile; 584 + struct aa_label *label; 585 + int error = 0; 586 + 587 + label = begin_current_label_crit_section(); 588 + if (!unconfined(label)) { 589 + DEFINE_AUDIT_SK(ad, op, current_cred(), sock->sk); 590 + 591 + error = fn_for_each_confined(label, profile, 592 + profile_opt_perm(profile, request, sock->sk, 593 + optname, &ad)); 594 + } 595 + end_current_label_crit_section(label); 596 + 597 + return error; 598 + } 599 + 600 + static int unix_peer_perm(const struct cred *subj_cred, 601 + struct aa_label *label, const char *op, u32 request, 602 + struct sock *sk, struct path *path, 603 + struct sockaddr_un *peer_addr, int peer_addrlen, 604 + struct path *peer_path, struct aa_label *peer_label) 605 + { 606 + struct aa_profile *profile; 607 + DEFINE_AUDIT_SK(ad, op, subj_cred, sk); 608 + 609 + ad.net.peer.addr = peer_addr; 610 + ad.net.peer.addrlen = peer_addrlen; 611 + 612 + return fn_for_each_confined(label, profile, 613 + profile_peer_perm(profile, request, sk, path, 614 + peer_addr, peer_addrlen, peer_path, 615 + peer_label, &ad)); 616 + } 617 + 618 + /** 619 + * 620 + * Requires: lock held on both @sk and @peer_sk 621 + * called by unix_stream_connect, unix_may_send 622 + */ 623 + int aa_unix_peer_perm(const struct cred *subj_cred, 624 + struct aa_label *label, const char *op, u32 request, 625 + struct sock *sk, struct sock *peer_sk, 626 + struct aa_label *peer_label) 627 + { 628 + struct unix_sock *peeru = unix_sk(peer_sk); 629 + struct unix_sock *u = unix_sk(sk); 630 + int plen; 631 + struct sockaddr_un *paddr = aa_sunaddr(unix_sk(peer_sk), &plen); 632 + 633 + AA_BUG(!label); 634 + AA_BUG(!sk); 635 + AA_BUG(!peer_sk); 636 + AA_BUG(!peer_label); 637 + 638 + return unix_peer_perm(subj_cred, label, op, request, sk, 639 + is_unix_fs(sk) ? &u->path : NULL, 640 + paddr, plen, 641 + is_unix_fs(peer_sk) ? &peeru->path : NULL, 642 + peer_label); 643 + } 644 + 645 + /* sk_plabel for comparison only */ 646 + static void update_sk_ctx(struct sock *sk, struct aa_label *label, 647 + struct aa_label *plabel) 648 + { 649 + struct aa_label *l, *old; 650 + struct aa_sk_ctx *ctx = aa_sock(sk); 651 + bool update_sk; 652 + 653 + rcu_read_lock(); 654 + update_sk = (plabel && 655 + (plabel != rcu_access_pointer(ctx->peer_lastupdate) || 656 + !aa_label_is_subset(plabel, rcu_dereference(ctx->peer)))) || 657 + !__aa_subj_label_is_cached(label, rcu_dereference(ctx->label)); 658 + rcu_read_unlock(); 659 + if (!update_sk) 660 + return; 661 + 662 + spin_lock(&unix_sk(sk)->lock); 663 + old = rcu_dereference_protected(ctx->label, 664 + lockdep_is_held(&unix_sk(sk)->lock)); 665 + l = aa_label_merge(old, label, GFP_ATOMIC); 666 + if (l) { 667 + if (l != old) { 668 + rcu_assign_pointer(ctx->label, l); 669 + aa_put_label(old); 670 + } else 671 + aa_put_label(l); 672 + } 673 + if (plabel && rcu_access_pointer(ctx->peer_lastupdate) != plabel) { 674 + old = rcu_dereference_protected(ctx->peer, lockdep_is_held(&unix_sk(sk)->lock)); 675 + 676 + if (old == plabel) { 677 + rcu_assign_pointer(ctx->peer_lastupdate, plabel); 678 + } else if (aa_label_is_subset(plabel, old)) { 679 + rcu_assign_pointer(ctx->peer_lastupdate, plabel); 680 + rcu_assign_pointer(ctx->peer, aa_get_label(plabel)); 681 + aa_put_label(old); 682 + } /* else race or a subset - don't update */ 683 + } 684 + spin_unlock(&unix_sk(sk)->lock); 685 + } 686 + 687 + static void update_peer_ctx(struct sock *sk, struct aa_sk_ctx *ctx, 688 + struct aa_label *label) 689 + { 690 + struct aa_label *l, *old; 691 + 692 + spin_lock(&unix_sk(sk)->lock); 693 + old = rcu_dereference_protected(ctx->peer, 694 + lockdep_is_held(&unix_sk(sk)->lock)); 695 + l = aa_label_merge(old, label, GFP_ATOMIC); 696 + if (l) { 697 + if (l != old) { 698 + rcu_assign_pointer(ctx->peer, l); 699 + aa_put_label(old); 700 + } else 701 + aa_put_label(l); 702 + } 703 + spin_unlock(&unix_sk(sk)->lock); 704 + } 705 + 706 + /* This fn is only checked if something has changed in the security 707 + * boundaries. Otherwise cached info off file is sufficient 708 + */ 709 + int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label, 710 + const char *op, u32 request, struct file *file) 711 + { 712 + struct socket *sock = (struct socket *) file->private_data; 713 + struct sockaddr_un *addr, *peer_addr; 714 + int addrlen, peer_addrlen; 715 + struct aa_label *plabel = NULL; 716 + struct sock *peer_sk = NULL; 717 + u32 sk_req = request & ~NET_PEER_MASK; 718 + struct path path; 719 + bool is_sk_fs; 720 + int error = 0; 721 + 722 + AA_BUG(!label); 723 + AA_BUG(!sock); 724 + AA_BUG(!sock->sk); 725 + AA_BUG(sock->sk->sk_family != PF_UNIX); 726 + 727 + /* investigate only using lock via unix_peer_get() 728 + * addr only needs the memory barrier, but need to investigate 729 + * path 730 + */ 731 + unix_state_lock(sock->sk); 732 + peer_sk = unix_peer(sock->sk); 733 + if (peer_sk) 734 + sock_hold(peer_sk); 735 + 736 + is_sk_fs = is_unix_fs(sock->sk); 737 + addr = aa_sunaddr(unix_sk(sock->sk), &addrlen); 738 + path = unix_sk(sock->sk)->path; 739 + unix_state_unlock(sock->sk); 740 + 741 + if (is_sk_fs && peer_sk) 742 + sk_req = request; 743 + if (sk_req) { 744 + error = aa_unix_label_sk_perm(subj_cred, label, op, 745 + sk_req, sock->sk, 746 + is_sk_fs ? &path : NULL); 747 + } 748 + if (!peer_sk) 749 + goto out; 750 + 751 + peer_addr = aa_sunaddr(unix_sk(peer_sk), &peer_addrlen); 752 + 753 + struct path peer_path; 754 + 755 + peer_path = unix_sk(peer_sk)->path; 756 + if (!is_sk_fs && is_unix_fs(peer_sk)) { 757 + last_error(error, 758 + unix_fs_perm(op, request, subj_cred, label, 759 + is_unix_fs(peer_sk) ? &peer_path : NULL)); 760 + } else if (!is_sk_fs) { 761 + struct aa_label *plabel; 762 + struct aa_sk_ctx *pctx = aa_sock(peer_sk); 763 + 764 + rcu_read_lock(); 765 + plabel = aa_get_label_rcu(&pctx->label); 766 + rcu_read_unlock(); 767 + /* no fs check of aa_unix_peer_perm because conditions above 768 + * ensure they will never be done 769 + */ 770 + last_error(error, 771 + xcheck(unix_peer_perm(subj_cred, label, op, 772 + MAY_READ | MAY_WRITE, sock->sk, 773 + is_sk_fs ? &path : NULL, 774 + peer_addr, peer_addrlen, 775 + is_unix_fs(peer_sk) ? 776 + &peer_path : NULL, 777 + plabel), 778 + unix_peer_perm(file->f_cred, plabel, op, 779 + MAY_READ | MAY_WRITE, peer_sk, 780 + is_unix_fs(peer_sk) ? 781 + &peer_path : NULL, 782 + addr, addrlen, 783 + is_sk_fs ? &path : NULL, 784 + label))); 785 + if (!error && !__aa_subj_label_is_cached(plabel, label)) 786 + update_peer_ctx(peer_sk, pctx, label); 787 + } 788 + sock_put(peer_sk); 789 + 790 + out: 791 + 792 + /* update peer cache to latest successful perm check */ 793 + if (error == 0) 794 + update_sk_ctx(sock->sk, label, plabel); 795 + aa_put_label(plabel); 796 + 797 + return error; 798 + } 799 +
+28 -11
security/apparmor/apparmorfs.c
··· 43 43 * The interface is split into two main components based on their function 44 44 * a securityfs component: 45 45 * used for static files that are always available, and which allows 46 - * userspace to specificy the location of the security filesystem. 46 + * userspace to specify the location of the security filesystem. 47 47 * 48 48 * fns and data are prefixed with 49 49 * aa_sfs_ ··· 204 204 /** 205 205 * __aafs_setup_d_inode - basic inode setup for apparmorfs 206 206 * @dir: parent directory for the dentry 207 - * @dentry: dentry we are seting the inode up for 207 + * @dentry: dentry we are setting the inode up for 208 208 * @mode: permissions the file should have 209 209 * @data: data to store on inode.i_private, available in open() 210 210 * @link: if symlink, symlink target string ··· 612 612 static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, 613 613 const char *match_str, size_t match_len) 614 614 { 615 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 616 - typeof(*rules), list); 615 + struct aa_ruleset *rules = profile->label.rules[0]; 617 616 struct aa_perms tmp = { }; 618 617 aa_state_t state = DFA_NOMATCH; 619 618 ··· 625 626 if (state) { 626 627 struct path_cond cond = { }; 627 628 628 - tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 629 + tmp = *(aa_lookup_condperms(current_fsuid(), 630 + rules->file, state, &cond)); 629 631 } 630 632 } else if (rules->policy->dfa) { 631 633 if (!RULE_MEDIATES(rules, *match_str)) 632 634 return; /* no change to current perms */ 635 + /* old user space does not correctly detect dbus mediation 636 + * support so we may get dbus policy and requests when 637 + * the abi doesn't support it. This can cause mediation 638 + * regressions, so explicitly test for this situation. 639 + */ 640 + if (*match_str == AA_CLASS_DBUS && 641 + !RULE_MEDIATES_v9NET(rules)) 642 + return; /* no change to current perms */ 633 643 state = aa_dfa_match_len(rules->policy->dfa, 634 644 rules->policy->start[0], 635 645 match_str, match_len); ··· 1005 997 1006 998 switch (fs_file->v_type) { 1007 999 case AA_SFS_TYPE_BOOLEAN: 1008 - seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no"); 1000 + seq_printf(seq, "%s\n", str_yes_no(fs_file->v.boolean)); 1009 1001 break; 1010 1002 case AA_SFS_TYPE_STRING: 1011 1003 seq_printf(seq, "%s\n", fs_file->v.string); ··· 1014 1006 seq_printf(seq, "%#08lx\n", fs_file->v.u64); 1015 1007 break; 1016 1008 default: 1017 - /* Ignore unpritable entry types. */ 1009 + /* Ignore unprintable entry types. */ 1018 1010 break; 1019 1011 } 1020 1012 ··· 1160 1152 struct aa_label *label; 1161 1153 1162 1154 label = begin_current_label_crit_section(); 1163 - seq_printf(seq, "%s\n", label->size > 1 ? "yes" : "no"); 1155 + seq_printf(seq, "%s\n", str_yes_no(label->size > 1)); 1164 1156 end_current_label_crit_section(label); 1165 1157 1166 1158 return 0; ··· 1183 1175 } 1184 1176 } 1185 1177 1186 - seq_printf(seq, "%s\n", count > 1 ? "yes" : "no"); 1178 + seq_printf(seq, "%s\n", str_yes_no(count > 1)); 1187 1179 end_current_label_crit_section(label); 1188 1180 1189 1181 return 0; ··· 2252 2244 /** 2253 2245 * p_stop - stop depth first traversal 2254 2246 * @f: seq_file we are filling 2255 - * @p: the last profile writen 2247 + * @p: the last profile written 2256 2248 * 2257 2249 * Release all locking done by p_start/p_next on namespace tree 2258 2250 */ ··· 2340 2332 static struct aa_sfs_entry aa_sfs_entry_domain[] = { 2341 2333 AA_SFS_FILE_BOOLEAN("change_hat", 1), 2342 2334 AA_SFS_FILE_BOOLEAN("change_hatv", 1), 2335 + AA_SFS_FILE_BOOLEAN("unconfined_allowed_children", 1), 2343 2336 AA_SFS_FILE_BOOLEAN("change_onexec", 1), 2344 2337 AA_SFS_FILE_BOOLEAN("change_profile", 1), 2345 2338 AA_SFS_FILE_BOOLEAN("stack", 1), ··· 2349 2340 AA_SFS_FILE_BOOLEAN("computed_longest_left", 1), 2350 2341 AA_SFS_DIR("attach_conditions", aa_sfs_entry_attach), 2351 2342 AA_SFS_FILE_BOOLEAN("disconnected.path", 1), 2343 + AA_SFS_FILE_BOOLEAN("kill.signal", 1), 2352 2344 AA_SFS_FILE_STRING("version", "1.2"), 2353 2345 { } 2354 2346 }; ··· 2374 2364 AA_SFS_FILE_BOOLEAN("set_load", 1), 2375 2365 /* number of out of band transitions supported */ 2376 2366 AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED), 2377 - AA_SFS_FILE_U64("permstable32_version", 1), 2367 + AA_SFS_FILE_U64("permstable32_version", 3), 2378 2368 AA_SFS_FILE_STRING("permstable32", PERMS32STR), 2379 2369 AA_SFS_FILE_U64("state32", 1), 2380 2370 AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined), ··· 2391 2381 AA_SFS_FILE_BOOLEAN("profile", 1), 2392 2382 AA_SFS_FILE_BOOLEAN("pivot_root", 0), 2393 2383 AA_SFS_FILE_STRING("mask", "userns_create"), 2384 + { } 2385 + }; 2386 + 2387 + static struct aa_sfs_entry aa_sfs_entry_dbus[] = { 2388 + AA_SFS_FILE_STRING("mask", "acquire send receive"), 2394 2389 { } 2395 2390 }; 2396 2391 ··· 2421 2406 AA_SFS_DIR("domain", aa_sfs_entry_domain), 2422 2407 AA_SFS_DIR("file", aa_sfs_entry_file), 2423 2408 AA_SFS_DIR("network_v8", aa_sfs_entry_network), 2409 + AA_SFS_DIR("network_v9", aa_sfs_entry_networkv9), 2424 2410 AA_SFS_DIR("mount", aa_sfs_entry_mount), 2425 2411 AA_SFS_DIR("namespaces", aa_sfs_entry_ns), 2426 2412 AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), ··· 2429 2413 AA_SFS_DIR("caps", aa_sfs_entry_caps), 2430 2414 AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace), 2431 2415 AA_SFS_DIR("signal", aa_sfs_entry_signal), 2416 + AA_SFS_DIR("dbus", aa_sfs_entry_dbus), 2432 2417 AA_SFS_DIR("query", aa_sfs_entry_query), 2433 2418 AA_SFS_DIR("io_uring", aa_sfs_entry_io_uring), 2434 2419 { }
+1 -1
security/apparmor/audit.c
··· 192 192 aa_audit_msg(type, ad, cb); 193 193 194 194 if (ad->type == AUDIT_APPARMOR_KILL) 195 - (void)send_sig_info(SIGKILL, NULL, 195 + (void)send_sig_info(profile->signal, NULL, 196 196 ad->common.type == LSM_AUDIT_DATA_TASK && 197 197 ad->common.u.tsk ? ad->common.u.tsk : current); 198 198
+57 -4
security/apparmor/capability.c
··· 27 27 28 28 struct aa_sfs_entry aa_sfs_entry_caps[] = { 29 29 AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK), 30 + AA_SFS_FILE_BOOLEAN("extended", 1), 30 31 { } 31 32 }; 32 33 ··· 69 68 { 70 69 const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */ 71 70 72 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 73 - typeof(*rules), list); 71 + struct aa_ruleset *rules = profile->label.rules[0]; 74 72 struct audit_cache *ent; 75 73 int type = AUDIT_APPARMOR_AUTO; 76 74 ··· 121 121 static int profile_capable(struct aa_profile *profile, int cap, 122 122 unsigned int opts, struct apparmor_audit_data *ad) 123 123 { 124 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 125 - typeof(*rules), list); 124 + struct aa_ruleset *rules = profile->label.rules[0]; 125 + aa_state_t state; 126 126 int error; 127 127 128 + state = RULE_MEDIATES(rules, ad->class); 129 + if (state) { 130 + struct aa_perms perms = { }; 131 + u32 request; 132 + 133 + /* caps broken into 256 x 32 bit permission chunks */ 134 + state = aa_dfa_next(rules->policy->dfa, state, cap >> 5); 135 + request = 1 << (cap & 0x1f); 136 + perms = *aa_lookup_perms(rules->policy, state); 137 + aa_apply_modes_to_perms(profile, &perms); 138 + 139 + if (opts & CAP_OPT_NOAUDIT) { 140 + if (perms.complain & request) 141 + ad->info = "optional: no audit"; 142 + else 143 + ad = NULL; 144 + } 145 + return aa_check_perms(profile, &perms, request, ad, 146 + audit_cb); 147 + } 148 + 149 + /* fallback to old caps mediation that doesn't support conditionals */ 128 150 if (cap_raised(rules->caps.allow, cap) && 129 151 !cap_raised(rules->caps.denied, cap)) 130 152 error = 0; ··· 189 167 profile_capable(profile, cap, opts, &ad)); 190 168 191 169 return error; 170 + } 171 + 172 + kernel_cap_t aa_profile_capget(struct aa_profile *profile) 173 + { 174 + struct aa_ruleset *rules = profile->label.rules[0]; 175 + aa_state_t state; 176 + 177 + state = RULE_MEDIATES(rules, AA_CLASS_CAP); 178 + if (state) { 179 + kernel_cap_t caps = CAP_EMPTY_SET; 180 + int i; 181 + 182 + /* caps broken into up to 256, 32 bit permission chunks */ 183 + for (i = 0; i < (CAP_LAST_CAP >> 5); i++) { 184 + struct aa_perms perms = { }; 185 + aa_state_t tmp; 186 + 187 + tmp = aa_dfa_next(rules->policy->dfa, state, i); 188 + perms = *aa_lookup_perms(rules->policy, tmp); 189 + aa_apply_modes_to_perms(profile, &perms); 190 + caps.val |= ((u64)(perms.allow)) << (i * 5); 191 + caps.val |= ((u64)(perms.complain)) << (i * 5); 192 + } 193 + return caps; 194 + } 195 + 196 + /* fallback to old caps */ 197 + if (COMPLAIN_MODE(profile)) 198 + return CAP_FULL_SET; 199 + 200 + return rules->caps.allow; 192 201 }
+137 -66
security/apparmor/domain.c
··· 28 28 #include "include/policy.h" 29 29 #include "include/policy_ns.h" 30 30 31 + static const char * const CONFLICTING_ATTACH_STR = "conflicting profile attachments"; 32 + static const char * const CONFLICTING_ATTACH_STR_IX = 33 + "conflicting profile attachments - ix fallback"; 34 + static const char * const CONFLICTING_ATTACH_STR_UX = 35 + "conflicting profile attachments - ux fallback"; 36 + 31 37 /** 32 38 * may_change_ptraced_domain - check if can change profile on ptraced task 33 39 * @to_cred: cred of task changing domain ··· 93 87 struct aa_profile *tp, 94 88 bool stack, aa_state_t state) 95 89 { 96 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 97 - typeof(*rules), list); 90 + struct aa_ruleset *rules = profile->label.rules[0]; 98 91 const char *ns_name; 99 92 100 93 if (stack) ··· 130 125 aa_state_t state, bool subns, u32 request, 131 126 struct aa_perms *perms) 132 127 { 133 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 134 - typeof(*rules), list); 128 + struct aa_ruleset *rules = profile->label.rules[0]; 135 129 struct aa_profile *tp; 136 130 struct label_it i; 137 131 struct path_cond cond = { }; ··· 158 154 if (!state) 159 155 goto fail; 160 156 } 161 - *perms = *(aa_lookup_fperms(rules->file, state, &cond)); 157 + *perms = *(aa_lookup_condperms(current_fsuid(), rules->file, state, 158 + &cond)); 162 159 aa_apply_modes_to_perms(profile, perms); 163 160 if ((perms->allow & request) != request) 164 161 return -EACCES; ··· 192 187 aa_state_t start, bool subns, u32 request, 193 188 struct aa_perms *perms) 194 189 { 195 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 196 - typeof(*rules), list); 190 + struct aa_ruleset *rules = profile->label.rules[0]; 197 191 struct aa_profile *tp; 198 192 struct label_it i; 199 193 struct aa_perms tmp; ··· 213 209 return 0; 214 210 215 211 next: 216 - tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 212 + tmp = *(aa_lookup_condperms(current_fsuid(), rules->file, state, 213 + &cond)); 217 214 aa_apply_modes_to_perms(profile, &tmp); 218 215 aa_perms_accum(perms, &tmp); 219 216 label_for_each_cont(i, label, tp) { ··· 223 218 state = match_component(profile, tp, stack, start); 224 219 if (!state) 225 220 goto fail; 226 - tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 221 + tmp = *(aa_lookup_condperms(current_fsuid(), rules->file, state, 222 + &cond)); 227 223 aa_apply_modes_to_perms(profile, &tmp); 228 224 aa_perms_accum(perms, &tmp); 229 225 } ··· 329 323 size = vfs_getxattr_alloc(&nop_mnt_idmap, d, attach->xattrs[i], 330 324 &value, value_size, GFP_KERNEL); 331 325 if (size >= 0) { 332 - u32 index, perm; 326 + struct aa_perms *perms; 333 327 334 328 /* 335 329 * Check the xattr presence before value. This ensure ··· 341 335 /* Check xattr value */ 342 336 state = aa_dfa_match_len(attach->xmatch->dfa, state, 343 337 value, size); 344 - index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; 345 - perm = attach->xmatch->perms[index].allow; 346 - if (!(perm & MAY_EXEC)) { 338 + perms = aa_lookup_perms(attach->xmatch, state); 339 + if (!(perms->allow & MAY_EXEC)) { 347 340 ret = -EINVAL; 348 341 goto out; 349 342 } ··· 420 415 if (attach->xmatch->dfa) { 421 416 unsigned int count; 422 417 aa_state_t state; 423 - u32 index, perm; 418 + struct aa_perms *perms; 424 419 425 420 state = aa_dfa_leftmatch(attach->xmatch->dfa, 426 421 attach->xmatch->start[AA_CLASS_XMATCH], 427 422 name, &count); 428 - index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; 429 - perm = attach->xmatch->perms[index].allow; 423 + perms = aa_lookup_perms(attach->xmatch, state); 430 424 /* any accepting state means a valid match. */ 431 - if (perm & MAY_EXEC) { 425 + if (perms->allow & MAY_EXEC) { 432 426 int ret = 0; 433 427 434 428 if (count < candidate_len) ··· 488 484 489 485 if (!candidate || conflict) { 490 486 if (conflict) 491 - *info = "conflicting profile attachments"; 487 + *info = CONFLICTING_ATTACH_STR; 492 488 rcu_read_unlock(); 493 489 return NULL; 494 490 } ··· 512 508 * @name: returns: name tested to find label (NOT NULL) 513 509 * 514 510 * Returns: refcounted label, or NULL on failure (MAYBE NULL) 511 + * @name will always be set with the last name tried 515 512 */ 516 513 struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, 517 514 const char **name) 518 515 { 519 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 520 - typeof(*rules), list); 516 + struct aa_ruleset *rules = profile->label.rules[0]; 521 517 struct aa_label *label = NULL; 522 518 u32 xtype = xindex & AA_X_TYPE_MASK; 523 519 int index = xindex & AA_X_INDEX_MASK; 520 + const char *next; 524 521 525 522 AA_BUG(!name); 526 523 ··· 529 524 /* TODO: move lookup parsing to unpack time so this is a straight 530 525 * index into the resultant label 531 526 */ 532 - for (*name = rules->file->trans.table[index]; !label && *name; 533 - *name = next_name(xtype, *name)) { 527 + for (next = rules->file->trans.table[index]; next; 528 + next = next_name(xtype, next)) { 529 + const char *lookup = (*next == '&') ? next + 1 : next; 530 + *name = next; 534 531 if (xindex & AA_X_CHILD) { 535 - struct aa_profile *new_profile; 536 - /* release by caller */ 537 - new_profile = aa_find_child(profile, *name); 538 - if (new_profile) 539 - label = &new_profile->label; 532 + /* TODO: switich to parse to get stack of child */ 533 + struct aa_profile *new = aa_find_child(profile, lookup); 534 + 535 + if (new) 536 + /* release by caller */ 537 + return &new->label; 540 538 continue; 541 539 } 542 - label = aa_label_parse(&profile->label, *name, GFP_KERNEL, 540 + label = aa_label_parse(&profile->label, lookup, GFP_KERNEL, 543 541 true, false); 544 - if (IS_ERR(label)) 545 - label = NULL; 542 + if (!IS_ERR_OR_NULL(label)) 543 + /* release by caller */ 544 + return label; 546 545 } 547 546 548 - /* released by caller */ 549 - 550 - return label; 547 + return NULL; 551 548 } 552 549 553 550 /** ··· 571 564 const char **lookupname, 572 565 const char **info) 573 566 { 574 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 575 - typeof(*rules), list); 576 567 struct aa_label *new = NULL; 568 + struct aa_label *stack = NULL; 577 569 struct aa_ns *ns = profile->ns; 578 570 u32 xtype = xindex & AA_X_TYPE_MASK; 579 - const char *stack = NULL; 571 + /* Used for info checks during fallback handling */ 572 + const char *old_info = NULL; 580 573 581 574 switch (xtype) { 582 575 case AA_X_NONE: ··· 585 578 break; 586 579 case AA_X_TABLE: 587 580 /* TODO: fix when perm mapping done at unload */ 588 - stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK]; 589 - if (*stack != '&') { 590 - /* released by caller */ 591 - new = x_table_lookup(profile, xindex, lookupname); 592 - stack = NULL; 581 + /* released by caller 582 + * if null for both stack and direct want to try fallback 583 + */ 584 + new = x_table_lookup(profile, xindex, lookupname); 585 + if (!new || **lookupname != '&') 593 586 break; 594 - } 587 + stack = new; 588 + new = NULL; 595 589 fallthrough; /* to X_NAME */ 596 590 case AA_X_NAME: 597 591 if (xindex & AA_X_CHILD) ··· 607 599 break; 608 600 } 609 601 602 + /* fallback transition check */ 610 603 if (!new) { 611 604 if (xindex & AA_X_INHERIT) { 612 605 /* (p|c|n)ix - don't change profile but do 613 606 * use the newest version 614 607 */ 615 - *info = "ix fallback"; 608 + if (*info == CONFLICTING_ATTACH_STR) { 609 + *info = CONFLICTING_ATTACH_STR_IX; 610 + } else { 611 + old_info = *info; 612 + *info = "ix fallback"; 613 + } 616 614 /* no profile && no error */ 617 615 new = aa_get_newest_label(&profile->label); 618 616 } else if (xindex & AA_X_UNCONFINED) { 619 617 new = aa_get_newest_label(ns_unconfined(profile->ns)); 620 - *info = "ux fallback"; 618 + if (*info == CONFLICTING_ATTACH_STR) { 619 + *info = CONFLICTING_ATTACH_STR_UX; 620 + } else { 621 + old_info = *info; 622 + *info = "ux fallback"; 623 + } 624 + } 625 + /* We set old_info on the code paths above where overwriting 626 + * could have happened, so now check if info was set by 627 + * find_attach as well (i.e. whether we actually overwrote) 628 + * and warn accordingly. 629 + */ 630 + if (old_info && old_info != CONFLICTING_ATTACH_STR) { 631 + pr_warn_ratelimited( 632 + "AppArmor: find_attach (from profile %s) audit info \"%s\" dropped", 633 + profile->base.hname, old_info); 621 634 } 622 635 } 623 636 ··· 646 617 /* base the stack on post domain transition */ 647 618 struct aa_label *base = new; 648 619 649 - new = aa_label_parse(base, stack, GFP_KERNEL, true, false); 650 - if (IS_ERR(new)) 651 - new = NULL; 620 + new = aa_label_merge(base, stack, GFP_KERNEL); 621 + /* null on error */ 652 622 aa_put_label(base); 653 623 } 654 624 625 + aa_put_label(stack); 655 626 /* released by caller */ 656 627 return new; 657 628 } ··· 662 633 char *buffer, struct path_cond *cond, 663 634 bool *secure_exec) 664 635 { 665 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 666 - typeof(*rules), list); 636 + struct aa_ruleset *rules = profile->label.rules[0]; 667 637 struct aa_label *new = NULL; 668 638 struct aa_profile *new_profile = NULL; 669 639 const char *info = NULL, *name = NULL, *target = NULL; ··· 680 652 if (error) { 681 653 if (profile_unconfined(profile) || 682 654 (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) { 683 - AA_DEBUG("name lookup ix on error"); 655 + AA_DEBUG(DEBUG_DOMAIN, "name lookup ix on error"); 684 656 error = 0; 685 657 new = aa_get_newest_label(&profile->label); 686 658 } ··· 691 663 if (profile_unconfined(profile)) { 692 664 new = find_attach(bprm, profile->ns, 693 665 &profile->ns->base.profiles, name, &info); 666 + /* info set -> something unusual that we should report 667 + * Currently this is only conflicting attachments, but other 668 + * infos added in the future should also be logged by default 669 + * and only excluded on a case-by-case basis 670 + */ 671 + if (info) { 672 + /* Because perms is never used again after this audit 673 + * we don't need to care about clobbering it 674 + */ 675 + perms.audit |= MAY_EXEC; 676 + perms.allow |= MAY_EXEC; 677 + /* Don't cause error if auditing fails */ 678 + (void) aa_audit_file(subj_cred, profile, &perms, 679 + OP_EXEC, MAY_EXEC, name, target, new, cond->uid, 680 + info, error); 681 + } 694 682 if (new) { 695 - AA_DEBUG("unconfined attached to new label"); 683 + AA_DEBUG(DEBUG_DOMAIN, "unconfined attached to new label"); 696 684 return new; 697 685 } 698 - AA_DEBUG("unconfined exec no attachment"); 686 + AA_DEBUG(DEBUG_DOMAIN, "unconfined exec no attachment"); 699 687 return aa_get_newest_label(&profile->label); 700 688 } 701 689 ··· 722 678 new = x_to_label(profile, bprm, name, perms.xindex, &target, 723 679 &info); 724 680 if (new && new->proxy == profile->label.proxy && info) { 681 + /* Force audit on conflicting attachment fallback 682 + * Because perms is never used again after this audit 683 + * we don't need to care about clobbering it 684 + */ 685 + if (info == CONFLICTING_ATTACH_STR_IX 686 + || info == CONFLICTING_ATTACH_STR_UX) 687 + perms.audit |= MAY_EXEC; 725 688 /* hack ix fallback - improve how this is detected */ 726 689 goto audit; 727 690 } else if (!new) { 691 + if (info) { 692 + pr_warn_ratelimited( 693 + "AppArmor: %s (from profile %s) audit info \"%s\" dropped on missing transition", 694 + __func__, profile->base.hname, info); 695 + } 728 696 info = "profile transition not found"; 729 697 /* remove MAY_EXEC to audit as failure or complaint */ 730 698 perms.allow &= ~MAY_EXEC; ··· 795 739 char *buffer, struct path_cond *cond, 796 740 bool *secure_exec) 797 741 { 798 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 799 - typeof(*rules), list); 742 + struct aa_ruleset *rules = profile->label.rules[0]; 800 743 aa_state_t state = rules->file->start[AA_CLASS_FILE]; 801 744 struct aa_perms perms = {}; 802 745 const char *xname = NULL, *info = "change_profile onexec"; ··· 810 755 /* change_profile on exec already granted */ 811 756 /* 812 757 * NOTE: Domain transitions from unconfined are allowed 813 - * even when no_new_privs is set because this aways results 758 + * even when no_new_privs is set because this always results 814 759 * in a further reduction of permissions. 815 760 */ 816 761 return 0; ··· 821 766 if (error) { 822 767 if (profile_unconfined(profile) || 823 768 (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) { 824 - AA_DEBUG("name lookup ix on error"); 769 + AA_DEBUG(DEBUG_DOMAIN, "name lookup ix on error"); 825 770 error = 0; 826 771 } 827 772 xname = bprm->filename; ··· 981 926 * 982 927 * NOTE: Domain transitions from unconfined and to stacked 983 928 * subsets are allowed even when no_new_privs is set because this 984 - * aways results in a further reduction of permissions. 929 + * always results in a further reduction of permissions. 985 930 */ 986 931 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && 987 932 !unconfined(label) && ··· 1243 1188 if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp) 1244 1189 ctx->nnp = aa_get_label(label); 1245 1190 1191 + /* return -EPERM when unconfined doesn't have children to avoid 1192 + * changing the traditional error code for unconfined. 1193 + */ 1246 1194 if (unconfined(label)) { 1247 - info = "unconfined can not change_hat"; 1248 - error = -EPERM; 1249 - goto fail; 1195 + struct label_it i; 1196 + bool empty = true; 1197 + 1198 + rcu_read_lock(); 1199 + label_for_each_in_ns(i, labels_ns(label), label, profile) { 1200 + empty &= list_empty(&profile->base.profiles); 1201 + } 1202 + rcu_read_unlock(); 1203 + 1204 + if (empty) { 1205 + info = "unconfined can not change_hat"; 1206 + error = -EPERM; 1207 + goto fail; 1208 + } 1250 1209 } 1251 1210 1252 1211 if (count) { ··· 1285 1216 if (task_no_new_privs(current) && !unconfined(label) && 1286 1217 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1287 1218 /* not an apparmor denial per se, so don't log it */ 1288 - AA_DEBUG("no_new_privs - change_hat denied"); 1219 + AA_DEBUG(DEBUG_DOMAIN, 1220 + "no_new_privs - change_hat denied"); 1289 1221 error = -EPERM; 1290 1222 goto out; 1291 1223 } ··· 1307 1237 if (task_no_new_privs(current) && !unconfined(label) && 1308 1238 !aa_label_is_unconfined_subset(previous, ctx->nnp)) { 1309 1239 /* not an apparmor denial per se, so don't log it */ 1310 - AA_DEBUG("no_new_privs - change_hat denied"); 1240 + AA_DEBUG(DEBUG_DOMAIN, 1241 + "no_new_privs - change_hat denied"); 1311 1242 error = -EPERM; 1312 1243 goto out; 1313 1244 } ··· 1353 1282 struct aa_label *target, bool stack, 1354 1283 u32 request, struct aa_perms *perms) 1355 1284 { 1356 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 1357 - typeof(*rules), list); 1285 + struct aa_ruleset *rules = profile->label.rules[0]; 1358 1286 const char *info = NULL; 1359 1287 int error = 0; 1360 1288 ··· 1413 1343 1414 1344 if (!fqname || !*fqname) { 1415 1345 aa_put_label(label); 1416 - AA_DEBUG("no profile name"); 1346 + AA_DEBUG(DEBUG_DOMAIN, "no profile name"); 1417 1347 return -EINVAL; 1418 1348 } 1419 1349 ··· 1532 1462 if (task_no_new_privs(current) && !unconfined(label) && 1533 1463 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1534 1464 /* not an apparmor denial per se, so don't log it */ 1535 - AA_DEBUG("no_new_privs - change_hat denied"); 1465 + AA_DEBUG(DEBUG_DOMAIN, 1466 + "no_new_privs - change_hat denied"); 1536 1467 error = -EPERM; 1537 1468 goto out; 1538 1469 }
+63 -29
security/apparmor/file.c
··· 14 14 #include <linux/fs.h> 15 15 #include <linux/mount.h> 16 16 17 + #include "include/af_unix.h" 17 18 #include "include/apparmor.h" 18 19 #include "include/audit.h" 19 20 #include "include/cred.h" ··· 169 168 170 169 struct aa_perms default_perms = {}; 171 170 /** 172 - * aa_lookup_fperms - convert dfa compressed perms to internal perms 173 - * @file_rules: the aa_policydb to lookup perms for (NOT NULL) 171 + * aa_lookup_condperms - convert dfa compressed perms to internal perms 172 + * @subj_uid: uid to use for subject owner test 173 + * @rules: the aa_policydb to lookup perms for (NOT NULL) 174 174 * @state: state in dfa 175 175 * @cond: conditions to consider (NOT NULL) 176 176 * ··· 179 177 * 180 178 * Returns: a pointer to a file permission set 181 179 */ 182 - struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules, 183 - aa_state_t state, struct path_cond *cond) 180 + struct aa_perms *aa_lookup_condperms(kuid_t subj_uid, struct aa_policydb *rules, 181 + aa_state_t state, struct path_cond *cond) 184 182 { 185 - unsigned int index = ACCEPT_TABLE(file_rules->dfa)[state]; 183 + unsigned int index = ACCEPT_TABLE(rules->dfa)[state]; 186 184 187 - if (!(file_rules->perms)) 185 + if (!(rules->perms)) 188 186 return &default_perms; 189 187 190 - if (uid_eq(current_fsuid(), cond->uid)) 191 - return &(file_rules->perms[index]); 188 + if ((ACCEPT_TABLE2(rules->dfa)[state] & ACCEPT_FLAG_OWNER)) { 189 + if (uid_eq(subj_uid, cond->uid)) 190 + return &(rules->perms[index]); 191 + return &(rules->perms[index + 1]); 192 + } 192 193 193 - return &(file_rules->perms[index + 1]); 194 + return &(rules->perms[index]); 194 195 } 195 196 196 197 /** ··· 212 207 { 213 208 aa_state_t state; 214 209 state = aa_dfa_match(file_rules->dfa, start, name); 215 - *perms = *(aa_lookup_fperms(file_rules, state, cond)); 210 + *perms = *(aa_lookup_condperms(current_fsuid(), file_rules, state, 211 + cond)); 216 212 217 213 return state; 218 214 } 219 215 220 - static int __aa_path_perm(const char *op, const struct cred *subj_cred, 221 - struct aa_profile *profile, const char *name, 222 - u32 request, struct path_cond *cond, int flags, 223 - struct aa_perms *perms) 216 + int __aa_path_perm(const char *op, const struct cred *subj_cred, 217 + struct aa_profile *profile, const char *name, 218 + u32 request, struct path_cond *cond, int flags, 219 + struct aa_perms *perms) 224 220 { 225 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 226 - typeof(*rules), list); 221 + struct aa_ruleset *rules = profile->label.rules[0]; 227 222 int e = 0; 228 223 229 - if (profile_unconfined(profile)) 224 + if (profile_unconfined(profile) || 225 + ((flags & PATH_SOCK_COND) && !RULE_MEDIATES_v9NET(rules))) 230 226 return 0; 231 227 aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE], 232 228 name, cond, perms); ··· 322 316 const struct path *target, char *buffer2, 323 317 struct path_cond *cond) 324 318 { 325 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 326 - typeof(*rules), list); 319 + struct aa_ruleset *rules = profile->label.rules[0]; 327 320 const char *lname, *tname = NULL; 328 321 struct aa_perms lperms = {}, perms; 329 322 const char *info = NULL; ··· 428 423 { 429 424 struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; 430 425 struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; 426 + struct inode *inode = d_backing_inode(old_dentry); 427 + vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(target.mnt), inode); 431 428 struct path_cond cond = { 432 - d_backing_inode(old_dentry)->i_uid, 433 - d_backing_inode(old_dentry)->i_mode 429 + .uid = vfsuid_into_kuid(vfsuid), 430 + .mode = inode->i_mode, 434 431 }; 435 432 char *buffer = NULL, *buffer2 = NULL; 436 433 struct aa_profile *profile; ··· 541 534 struct aa_label *flabel, struct file *file, 542 535 u32 request, u32 denied) 543 536 { 544 - struct socket *sock = (struct socket *) file->private_data; 545 537 int error; 546 - 547 - AA_BUG(!sock); 548 538 549 539 /* revalidation due to label out of date. No revocation at this time */ 550 540 if (!denied && aa_label_is_subset(flabel, label)) 551 541 return 0; 552 542 553 543 /* TODO: improve to skip profiles cached in flabel */ 554 - error = aa_sock_file_perm(subj_cred, label, op, request, sock); 544 + error = aa_sock_file_perm(subj_cred, label, op, request, file); 555 545 if (denied) { 556 546 /* TODO: improve to skip profiles checked above */ 557 547 /* check every profile in file label to is cached */ 558 548 last_error(error, aa_sock_file_perm(subj_cred, flabel, op, 559 - request, sock)); 549 + request, file)); 560 550 } 561 551 if (!error) 562 552 update_file_ctx(file_ctx(file), label, request); 563 553 564 554 return error; 555 + } 556 + 557 + /* for now separate fn to indicate semantics of the check */ 558 + static bool __file_is_delegated(struct aa_label *obj_label) 559 + { 560 + return unconfined(obj_label); 561 + } 562 + 563 + static bool __unix_needs_revalidation(struct file *file, struct aa_label *label, 564 + u32 request) 565 + { 566 + struct socket *sock = (struct socket *) file->private_data; 567 + 568 + lockdep_assert_in_rcu_read_lock(); 569 + 570 + if (!S_ISSOCK(file_inode(file)->i_mode)) 571 + return false; 572 + if (request & NET_PEER_MASK) 573 + return false; 574 + if (sock->sk->sk_family == PF_UNIX) { 575 + struct aa_sk_ctx *ctx = aa_sock(sock->sk); 576 + 577 + if (rcu_access_pointer(ctx->peer) != 578 + rcu_access_pointer(ctx->peer_lastupdate)) 579 + return true; 580 + return !__aa_subj_label_is_cached(rcu_dereference(ctx->label), 581 + label); 582 + } 583 + return false; 565 584 } 566 585 567 586 /** ··· 627 594 * delegation from unconfined tasks 628 595 */ 629 596 denied = request & ~fctx->allow; 630 - if (unconfined(label) || unconfined(flabel) || 631 - (!denied && aa_label_is_subset(flabel, label))) { 597 + if (unconfined(label) || __file_is_delegated(flabel) || 598 + __unix_needs_revalidation(file, label, request) || 599 + (!denied && __aa_subj_label_is_cached(label, flabel))) { 632 600 rcu_read_unlock(); 633 601 goto done; 634 602 } 635 603 604 + /* slow path - revalidate access */ 636 605 flabel = aa_get_newest_label(flabel); 637 606 rcu_read_unlock(); 638 - /* TODO: label cross check */ 639 607 640 608 if (path_mediated_fs(file->f_path.dentry)) 641 609 error = __file_path_perm(op, subj_cred, label, flabel, file,
+55
security/apparmor/include/af_unix.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor af_unix fine grained mediation 6 + * 7 + * Copyright 2023 Canonical Ltd. 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License as 11 + * published by the Free Software Foundation, version 2 of the 12 + * License. 13 + */ 14 + #ifndef __AA_AF_UNIX_H 15 + 16 + #include <net/af_unix.h> 17 + 18 + #include "label.h" 19 + 20 + #define unix_addr(A) ((struct sockaddr_un *)(A)) 21 + #define unix_addr_len(L) ((L) - sizeof(sa_family_t)) 22 + #define unix_peer(sk) (unix_sk(sk)->peer) 23 + #define is_unix_addr_abstract_name(B) ((B)[0] == 0) 24 + #define is_unix_addr_anon(A, L) ((A) && unix_addr_len(L) <= 0) 25 + #define is_unix_addr_fs(A, L) (!is_unix_addr_anon(A, L) && \ 26 + !is_unix_addr_abstract_name(unix_addr(A)->sun_path)) 27 + 28 + #define is_unix_anonymous(U) (!unix_sk(U)->addr) 29 + #define is_unix_fs(U) (!is_unix_anonymous(U) && \ 30 + unix_sk(U)->addr->name->sun_path[0]) 31 + #define is_unix_connected(S) ((S)->state == SS_CONNECTED) 32 + 33 + 34 + struct sockaddr_un *aa_sunaddr(const struct unix_sock *u, int *addrlen); 35 + int aa_unix_peer_perm(const struct cred *subj_cred, 36 + struct aa_label *label, const char *op, u32 request, 37 + struct sock *sk, struct sock *peer_sk, 38 + struct aa_label *peer_label); 39 + int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock); 40 + int aa_unix_create_perm(struct aa_label *label, int family, int type, 41 + int protocol); 42 + int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address, 43 + int addrlen); 44 + int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, 45 + int addrlen); 46 + int aa_unix_listen_perm(struct socket *sock, int backlog); 47 + int aa_unix_accept_perm(struct socket *sock, struct socket *newsock); 48 + int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, 49 + struct msghdr *msg, int size); 50 + int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, int level, 51 + int optname); 52 + int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label, 53 + const char *op, u32 request, struct file *file); 54 + 55 + #endif /* __AA_AF_UNIX_H */
+3 -1
security/apparmor/include/apparmor.h
··· 28 28 #define AA_CLASS_SIGNAL 10 29 29 #define AA_CLASS_XMATCH 11 30 30 #define AA_CLASS_NET 14 31 + #define AA_CLASS_NETV9 15 31 32 #define AA_CLASS_LABEL 16 32 33 #define AA_CLASS_POSIX_MQUEUE 17 33 34 #define AA_CLASS_MODULE 19 ··· 39 38 #define AA_CLASS_X 31 40 39 #define AA_CLASS_DBUS 32 41 40 41 + /* NOTE: if AA_CLASS_LAST > 63 need to update label->mediates */ 42 42 #define AA_CLASS_LAST AA_CLASS_DBUS 43 43 44 44 /* Control parameters settable through module/boot flags */ 45 45 extern enum audit_mode aa_g_audit; 46 46 extern bool aa_g_audit_header; 47 - extern bool aa_g_debug; 47 + extern int aa_g_debug; 48 48 extern bool aa_g_hash_policy; 49 49 extern bool aa_g_export_binary; 50 50 extern int aa_g_rawdata_compression_level;
+4 -1
security/apparmor/include/audit.h
··· 138 138 }; 139 139 struct { 140 140 int type, protocol; 141 - struct sock *peer_sk; 142 141 void *addr; 143 142 int addrlen; 143 + struct { 144 + void *addr; 145 + int addrlen; 146 + } peer; 144 147 } net; 145 148 }; 146 149 };
+1
security/apparmor/include/capability.h
··· 36 36 37 37 extern struct aa_sfs_entry aa_sfs_entry_caps[]; 38 38 39 + kernel_cap_t aa_profile_capget(struct aa_profile *profile); 39 40 int aa_capable(const struct cred *subj_cred, struct aa_label *label, 40 41 int cap, unsigned int opts); 41 42
+24 -7
security/apparmor/include/cred.h
··· 114 114 return aa_get_label(l); 115 115 } 116 116 117 - #define __end_current_label_crit_section(X) end_current_label_crit_section(X) 117 + /** 118 + * __end_current_label_crit_section - end crit section begun with __begin_... 119 + * @label: label obtained from __begin_current_label_crit_section 120 + * @needput: output: bool set by __begin_current_label_crit_section 121 + * 122 + * Returns: label to use for this crit section 123 + */ 124 + static inline void __end_current_label_crit_section(struct aa_label *label, 125 + bool needput) 126 + { 127 + if (unlikely(needput)) 128 + aa_put_label(label); 129 + } 118 130 119 131 /** 120 - * end_label_crit_section - put a reference found with begin_current_label.. 132 + * end_current_label_crit_section - put a reference found with begin_current_label.. 121 133 * @label: label reference to put 122 134 * 123 135 * Should only be used with a reference obtained with ··· 144 132 145 133 /** 146 134 * __begin_current_label_crit_section - current's confining label 135 + * @needput: store whether the label needs to be put when ending crit section 147 136 * 148 137 * Returns: up to date confining label or the ns unconfined label (NOT NULL) 149 138 * ··· 155 142 * critical section between __begin_current_label_crit_section() .. 156 143 * __end_current_label_crit_section() 157 144 */ 158 - static inline struct aa_label *__begin_current_label_crit_section(void) 145 + static inline struct aa_label *__begin_current_label_crit_section(bool *needput) 159 146 { 160 147 struct aa_label *label = aa_current_raw_label(); 161 148 162 - if (label_is_stale(label)) 163 - label = aa_get_newest_label(label); 149 + if (label_is_stale(label)) { 150 + *needput = true; 151 + return aa_get_newest_label(label); 152 + } 164 153 154 + *needput = false; 165 155 return label; 166 156 } 167 157 ··· 200 184 { 201 185 struct aa_label *label; 202 186 struct aa_ns *ns; 187 + bool needput; 203 188 204 - label = __begin_current_label_crit_section(); 189 + label = __begin_current_label_crit_section(&needput); 205 190 ns = aa_get_ns(labels_ns(label)); 206 - __end_current_label_crit_section(label); 191 + __end_current_label_crit_section(label, needput); 207 192 208 193 return ns; 209 194 }
+8 -3
security/apparmor/include/file.h
··· 77 77 const char *target, struct aa_label *tlabel, kuid_t ouid, 78 78 const char *info, int error); 79 79 80 - struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules, 81 - aa_state_t state, struct path_cond *cond); 80 + struct aa_perms *aa_lookup_condperms(kuid_t subj_uid, 81 + struct aa_policydb *file_rules, 82 + aa_state_t state, struct path_cond *cond); 82 83 aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, 83 84 const char *name, struct path_cond *cond, 84 85 struct aa_perms *perms); 85 86 87 + int __aa_path_perm(const char *op, const struct cred *subj_cred, 88 + struct aa_profile *profile, const char *name, 89 + u32 request, struct path_cond *cond, int flags, 90 + struct aa_perms *perms); 86 91 int aa_path_perm(const char *op, const struct cred *subj_cred, 87 92 struct aa_label *label, const struct path *path, 88 93 int flags, u32 request, struct path_cond *cond); ··· 104 99 105 100 106 101 /** 107 - * aa_map_file_perms - map file flags to AppArmor permissions 102 + * aa_map_file_to_perms - map file flags to AppArmor permissions 108 103 * @file: open file to map flags to AppArmor permissions 109 104 * 110 105 * Returns: apparmor permission set for the file
+3
security/apparmor/include/ipc.h
··· 13 13 14 14 #include <linux/sched.h> 15 15 16 + #define SIGUNKNOWN 0 17 + #define MAXMAPPED_SIG 35 18 + 16 19 int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender, 17 20 const struct cred *target_cred, struct aa_label *target, 18 21 int sig);
+35 -16
security/apparmor/include/label.h
··· 19 19 #include "lib.h" 20 20 21 21 struct aa_ns; 22 + struct aa_ruleset; 22 23 23 24 #define LOCAL_VEC_ENTRIES 8 24 25 #define DEFINE_VEC(T, V) \ ··· 110 109 int i, j; 111 110 }; 112 111 113 - /* struct aa_label - lazy labeling struct 112 + /* struct aa_label_base - base info of label 114 113 * @count: ref count of active users 115 114 * @node: rbtree position 116 115 * @rcu: rcu callback struct ··· 119 118 * @flags: stale and other flags - values may change under label set lock 120 119 * @secid: secid that references this label 121 120 * @size: number of entries in @ent[] 122 - * @ent: set of profiles for label, actual size determined by @size 121 + * @mediates: bitmask for label_mediates 122 + * profile: label vec when embedded in a profile FLAG_PROFILE is set 123 + * rules: variable length rules in a profile FLAG_PROFILE is set 124 + * vec: vector of profiles comprising the compound label 123 125 */ 124 126 struct aa_label { 125 127 struct kref count; ··· 133 129 long flags; 134 130 u32 secid; 135 131 int size; 136 - struct aa_profile *vec[]; 132 + u64 mediates; 133 + union { 134 + struct { 135 + /* only used is the label is a profile, size of 136 + * rules[] is determined by the profile 137 + * profile[1] is poison or null as guard 138 + */ 139 + struct aa_profile *profile[2]; 140 + DECLARE_FLEX_ARRAY(struct aa_ruleset *, rules); 141 + }; 142 + DECLARE_FLEX_ARRAY(struct aa_profile *, vec); 143 + }; 137 144 }; 138 145 139 146 #define last_error(E, FN) \ ··· 246 231 #define fn_for_each_not_in_set(L1, L2, P, FN) \ 247 232 fn_for_each2_XXX((L1), (L2), P, FN, _not_in_set) 248 233 249 - #define LABEL_MEDIATES(L, C) \ 250 - ({ \ 251 - struct aa_profile *profile; \ 252 - struct label_it i; \ 253 - int ret = 0; \ 254 - label_for_each(i, (L), profile) { \ 255 - if (RULE_MEDIATES(&profile->rules, (C))) { \ 256 - ret = 1; \ 257 - break; \ 258 - } \ 259 - } \ 260 - ret; \ 261 - }) 234 + static inline bool label_mediates(struct aa_label *L, unsigned char C) 235 + { 236 + return (L)->mediates & (((u64) 1) << (C)); 237 + } 262 238 239 + static inline bool label_mediates_safe(struct aa_label *L, unsigned char C) 240 + { 241 + if (C > AA_CLASS_LAST) 242 + return false; 243 + return label_mediates(L, C); 244 + } 263 245 264 246 void aa_labelset_destroy(struct aa_labelset *ls); 265 247 void aa_labelset_init(struct aa_labelset *ls); ··· 427 415 { 428 416 if (l) 429 417 kref_put(&l->count, aa_label_kref); 418 + } 419 + 420 + /* wrapper fn to indicate semantics of the check */ 421 + static inline bool __aa_subj_label_is_cached(struct aa_label *subj_label, 422 + struct aa_label *obj_label) 423 + { 424 + return aa_label_is_subset(obj_label, subj_label); 430 425 } 431 426 432 427
+33 -13
security/apparmor/include/lib.h
··· 19 19 extern struct aa_dfa *stacksplitdfa; 20 20 21 21 /* 22 - * DEBUG remains global (no per profile flag) since it is mostly used in sysctl 23 - * which is not related to profile accesses. 24 - */ 25 - 26 - #define DEBUG_ON (aa_g_debug) 27 - /* 28 22 * split individual debug cases out in preparation for finer grained 29 23 * debug controls in the future. 30 24 */ 31 - #define AA_DEBUG_LABEL DEBUG_ON 32 25 #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args) 33 - #define AA_DEBUG(fmt, args...) \ 26 + 27 + #define DEBUG_NONE 0 28 + #define DEBUG_LABEL_ABS_ROOT 1 29 + #define DEBUG_LABEL 2 30 + #define DEBUG_DOMAIN 4 31 + #define DEBUG_POLICY 8 32 + #define DEBUG_INTERFACE 0x10 33 + 34 + #define DEBUG_ALL 0x1f /* update if new DEBUG_X added */ 35 + #define DEBUG_PARSE_ERROR (-1) 36 + 37 + #define DEBUG_ON (aa_g_debug != DEBUG_NONE) 38 + #define DEBUG_ABS_ROOT (aa_g_debug & DEBUG_LABEL_ABS_ROOT) 39 + 40 + #define AA_DEBUG(opt, fmt, args...) \ 34 41 do { \ 35 - if (DEBUG_ON) \ 36 - pr_debug_ratelimited("AppArmor: " fmt, ##args); \ 42 + if (aa_g_debug & opt) \ 43 + pr_warn_ratelimited("%s: " fmt, __func__, ##args); \ 37 44 } while (0) 45 + #define AA_DEBUG_LABEL(LAB, X, fmt, args...) \ 46 + do { \ 47 + if ((LAB)->flags & FLAG_DEBUG1) \ 48 + AA_DEBUG(X, fmt, args); \ 49 + } while (0) 38 50 39 51 #define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X) 40 52 ··· 60 48 #define AA_BUG_FMT(X, fmt, args...) \ 61 49 WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args) 62 50 #else 63 - #define AA_BUG_FMT(X, fmt, args...) no_printk(fmt, ##args) 51 + #define AA_BUG_FMT(X, fmt, args...) \ 52 + do { \ 53 + BUILD_BUG_ON_INVALID(X); \ 54 + no_printk(fmt, ##args); \ 55 + } while (0) 64 56 #endif 57 + 58 + int aa_parse_debug_params(const char *str); 59 + int aa_print_debug_params(char *buffer); 65 60 66 61 #define AA_ERROR(fmt, args...) \ 67 62 pr_err_ratelimited("AppArmor: " fmt, ##args) ··· 125 106 }; 126 107 127 108 void aa_free_str_table(struct aa_str_table *table); 109 + bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp); 128 110 129 111 struct counted_str { 130 112 struct kref count; ··· 171 151 172 152 /** 173 153 * basename - find the last component of an hname 174 - * @name: hname to find the base profile name component of (NOT NULL) 154 + * @hname: hname to find the base profile name component of (NOT NULL) 175 155 * 176 156 * Returns: the tail (base profile name) name component of an hname 177 157 */ ··· 301 281 } \ 302 282 __done: \ 303 283 if (!__new_) \ 304 - AA_DEBUG("label build failed\n"); \ 284 + AA_DEBUG(DEBUG_LABEL, "label build failed\n"); \ 305 285 (__new_); \ 306 286 }) 307 287
+4 -6
security/apparmor/include/match.h
··· 17 17 #define DFA_START 1 18 18 19 19 20 - /** 20 + /* 21 21 * The format used for transition tables is based on the GNU flex table 22 22 * file format (--tables-file option; see Table File Format in the flex 23 23 * info pages and the flex sources for documentation). The magic number ··· 137 137 138 138 void aa_dfa_free_kref(struct kref *kref); 139 139 140 - #define WB_HISTORY_SIZE 24 140 + /* This needs to be a power of 2 */ 141 + #define WB_HISTORY_SIZE 32 141 142 struct match_workbuf { 142 - unsigned int count; 143 143 unsigned int pos; 144 144 unsigned int len; 145 - unsigned int size; /* power of 2, same as history size */ 146 - unsigned int history[WB_HISTORY_SIZE]; 145 + aa_state_t history[WB_HISTORY_SIZE]; 147 146 }; 148 147 #define DEFINE_MATCH_WB(N) \ 149 148 struct match_workbuf N = { \ 150 - .count = 0, \ 151 149 .pos = 0, \ 152 150 .len = 0, \ 153 151 }
+18 -18
security/apparmor/include/net.h
··· 47 47 #define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ 48 48 AA_MAY_ACCEPT) 49 49 struct aa_sk_ctx { 50 - struct aa_label *label; 51 - struct aa_label *peer; 50 + struct aa_label __rcu *label; 51 + struct aa_label __rcu *peer; 52 + struct aa_label __rcu *peer_lastupdate; /* ptr cmp only, no deref */ 52 53 }; 53 54 54 55 static inline struct aa_sk_ctx *aa_sock(const struct sock *sk) ··· 57 56 return sk->sk_security + apparmor_blob_sizes.lbs_sock; 58 57 } 59 58 60 - #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \ 59 + #define DEFINE_AUDIT_NET(NAME, OP, CRED, SK, F, T, P) \ 61 60 struct lsm_network_audit NAME ## _net = { .sk = (SK), \ 62 61 .family = (F)}; \ 63 62 DEFINE_AUDIT_DATA(NAME, \ ··· 66 65 AA_CLASS_NET, \ 67 66 OP); \ 68 67 NAME.common.u.net = &(NAME ## _net); \ 68 + NAME.subj_cred = (CRED); \ 69 69 NAME.net.type = (T); \ 70 70 NAME.net.protocol = (P) 71 71 72 - #define DEFINE_AUDIT_SK(NAME, OP, SK) \ 73 - DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ 72 + #define DEFINE_AUDIT_SK(NAME, OP, CRED, SK) \ 73 + DEFINE_AUDIT_NET(NAME, OP, CRED, SK, (SK)->sk_family, (SK)->sk_type, \ 74 74 (SK)->sk_protocol) 75 75 76 - 77 - #define af_select(FAMILY, FN, DEF_FN) \ 78 - ({ \ 79 - int __e; \ 80 - switch ((FAMILY)) { \ 81 - default: \ 82 - __e = DEF_FN; \ 83 - } \ 84 - __e; \ 85 - }) 86 76 87 77 struct aa_secmark { 88 78 u8 audit; ··· 83 91 }; 84 92 85 93 extern struct aa_sfs_entry aa_sfs_entry_network[]; 94 + extern struct aa_sfs_entry aa_sfs_entry_networkv9[]; 86 95 96 + int aa_do_perms(struct aa_profile *profile, struct aa_policydb *policy, 97 + aa_state_t state, u32 request, struct aa_perms *p, 98 + struct apparmor_audit_data *ad); 99 + /* passing in state returned by XXX_mediates_AF() */ 100 + aa_state_t aa_match_to_prot(struct aa_policydb *policy, aa_state_t state, 101 + u32 request, u16 af, int type, int protocol, 102 + struct aa_perms **p, const char **info); 87 103 void audit_net_cb(struct audit_buffer *ab, void *va); 88 104 int aa_profile_af_perm(struct aa_profile *profile, 89 105 struct apparmor_audit_data *ad, 90 - u32 request, u16 family, int type); 106 + u32 request, u16 family, int type, int protocol); 91 107 int aa_af_perm(const struct cred *subj_cred, struct aa_label *label, 92 108 const char *op, u32 request, u16 family, 93 109 int type, int protocol); ··· 105 105 struct sock *sk) 106 106 { 107 107 return aa_profile_af_perm(profile, ad, request, sk->sk_family, 108 - sk->sk_type); 108 + sk->sk_type, sk->sk_protocol); 109 109 } 110 110 int aa_sk_perm(const char *op, u32 request, struct sock *sk); 111 111 112 112 int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, 113 113 const char *op, u32 request, 114 - struct socket *sock); 114 + struct file *file); 115 115 116 116 int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, 117 117 u32 secid, const struct sock *sk);
+1
security/apparmor/include/path.h
··· 13 13 14 14 enum path_flags { 15 15 PATH_IS_DIR = 0x1, /* path is a directory */ 16 + PATH_SOCK_COND = 0x2, 16 17 PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */ 17 18 PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */ 18 19 PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
+4 -4
security/apparmor/include/perms.h
··· 101 101 102 102 /** 103 103 * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 104 - * @accum - perms struct to accumulate into 105 - * @addend - perms struct to add to @accum 104 + * @accum: perms struct to accumulate into 105 + * @addend: perms struct to add to @accum 106 106 */ 107 107 static inline void aa_perms_accum_raw(struct aa_perms *accum, 108 108 struct aa_perms *addend) ··· 128 128 129 129 /** 130 130 * aa_perms_accum - accumulate perms, masking off overlapping perms 131 - * @accum - perms struct to accumulate into 132 - * @addend - perms struct to add to @accum 131 + * @accum: perms struct to accumulate into 132 + * @addend: perms struct to add to @accum 133 133 */ 134 134 static inline void aa_perms_accum(struct aa_perms *accum, 135 135 struct aa_perms *addend)
+45 -18
security/apparmor/include/policy.h
··· 59 59 60 60 #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) 61 61 62 + /* flags in the dfa accept2 table */ 63 + enum dfa_accept_flags { 64 + ACCEPT_FLAG_OWNER = 1, 65 + }; 66 + 62 67 /* 63 68 * FIXME: currently need a clean way to replace and remove profiles as a 64 69 * set. It should be done at the namespace level. ··· 129 124 kref_put(&pdb->count, aa_pdb_free_kref); 130 125 } 131 126 127 + /* lookup perm that doesn't have and object conditional */ 132 128 static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy, 133 129 aa_state_t state) 134 130 { ··· 140 134 141 135 return &(policy->perms[index]); 142 136 } 143 - 144 137 145 138 /* struct aa_data - generic data structure 146 139 * key: name for retrieving this data ··· 165 160 * @secmark: secmark label match info 166 161 */ 167 162 struct aa_ruleset { 168 - struct list_head list; 169 - 170 163 int size; 171 164 172 165 /* TODO: merge policy and file */ ··· 177 174 int secmark_count; 178 175 struct aa_secmark *secmark; 179 176 }; 177 + 180 178 181 179 /* struct aa_attachment - data and rules for a profiles attachment 182 180 * @list: ··· 197 193 198 194 /* struct aa_profile - basic confinement data 199 195 * @base - base components of the profile (name, refcount, lists, lock ...) 200 - * @label - label this profile is an extension of 201 196 * @parent: parent of profile 202 197 * @ns: namespace the profile is in 203 198 * @rename: optional profile name that this profile renamed ··· 204 201 * @audit: the auditing mode of the profile 205 202 * @mode: the enforcement mode of the profile 206 203 * @path_flags: flags controlling path generation behavior 204 + * @signal: the signal that should be used when kill is used 207 205 * @disconnected: what to prepend if attach_disconnected is specified 208 206 * @attach: attachment rules for the profile 209 207 * @rules: rules to be enforced 210 208 * 209 + * learning_cache: the accesses learned in complain mode 210 + * raw_data: rawdata of the loaded profile policy 211 + * hash: cryptographic hash of the profile 211 212 * @dents: dentries for the profiles file entries in apparmorfs 212 213 * @dirname: name of the profile dir in apparmorfs 214 + * @dents: set of dentries associated with the profile 213 215 * @data: hashtable for free-form policy aa_data 216 + * @label - label this profile is an extension of 217 + * @rules - label with the rule vec on its end 214 218 * 215 219 * The AppArmor profile contains the basic confinement data. Each profile 216 220 * has a name, and exists in a namespace. The @name and @exec_match are ··· 241 231 enum audit_mode audit; 242 232 long mode; 243 233 u32 path_flags; 234 + int signal; 244 235 const char *disconnected; 245 236 246 237 struct aa_attachment attach; 247 - struct list_head rules; 248 238 249 239 struct aa_loaddata *rawdata; 250 240 unsigned char *hash; 251 241 char *dirname; 252 242 struct dentry *dents[AAFS_PROF_SIZEOF]; 253 243 struct rhashtable *data; 244 + 245 + int n_rules; 246 + /* special - variable length must be last entry in profile */ 254 247 struct aa_label label; 255 248 }; 256 249 ··· 311 298 rules->policy->start[0], &class, 1); 312 299 } 313 300 314 - static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) 301 + static inline aa_state_t RULE_MEDIATES_v9NET(struct aa_ruleset *rules) 315 302 { 316 - aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NET); 317 - __be16 be_af = cpu_to_be16(AF); 318 - 319 - if (!state) 320 - return DFA_NOMATCH; 321 - return aa_dfa_match_len(rules->policy->dfa, state, (char *) &be_af, 2); 303 + return RULE_MEDIATES(rules, AA_CLASS_NETV9); 322 304 } 323 305 324 - static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head, 325 - unsigned char class) 306 + static inline aa_state_t RULE_MEDIATES_NET(struct aa_ruleset *rules) 326 307 { 327 - struct aa_ruleset *rule; 308 + /* can not use RULE_MEDIATE_v9AF here, because AF match fail 309 + * can not be distiguished from class match fail, and we only 310 + * fallback to checking older class on class match failure 311 + */ 312 + aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NETV9); 328 313 329 - /* TODO: change to list walk */ 330 - rule = list_first_entry(head, typeof(*rule), list); 331 - return RULE_MEDIATES(rule, class); 314 + /* fallback and check v7/8 if v9 is NOT mediated */ 315 + if (!state) 316 + state = RULE_MEDIATES(rules, AA_CLASS_NET); 317 + 318 + return state; 319 + } 320 + 321 + 322 + void aa_compute_profile_mediates(struct aa_profile *profile); 323 + static inline bool profile_mediates(struct aa_profile *profile, 324 + unsigned char class) 325 + { 326 + return label_mediates(&profile->label, class); 327 + } 328 + 329 + static inline bool profile_mediates_safe(struct aa_profile *profile, 330 + unsigned char class) 331 + { 332 + return label_mediates_safe(&profile->label, class); 332 333 } 333 334 334 335 /**
+1 -5
security/apparmor/include/sig_names.h
··· 1 1 #include <linux/signal.h> 2 - 3 - #define SIGUNKNOWN 0 4 - #define MAXMAPPED_SIG 35 5 - #define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1) 6 - #define SIGRT_BASE 128 2 + #include "signal.h" 7 3 8 4 /* provide a mapping of arch signal to internal signal # for mediation 9 5 * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
+19
security/apparmor/include/signal.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor ipc mediation function definitions. 6 + * 7 + * Copyright 2023 Canonical Ltd. 8 + */ 9 + 10 + #ifndef __AA_SIGNAL_H 11 + #define __AA_SIGNAL_H 12 + 13 + #define SIGUNKNOWN 0 14 + #define MAXMAPPED_SIG 35 15 + 16 + #define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1) 17 + #define SIGRT_BASE 128 18 + 19 + #endif /* __AA_SIGNAL_H */
+6 -7
security/apparmor/ipc.c
··· 80 80 struct aa_label *peer, u32 request, 81 81 struct apparmor_audit_data *ad) 82 82 { 83 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 84 - typeof(*rules), list); 83 + struct aa_ruleset *rules = profile->label.rules[0]; 85 84 struct aa_perms perms; 86 85 aa_state_t state; 87 86 88 - if (profile_unconfined(profile) || 89 - !ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL)) 87 + if (profile_unconfined(profile)) 90 88 return 0; 91 89 92 90 ad->subj_cred = cred; 93 91 ad->peer = peer; 94 92 /* TODO: secondary cache check <profile, profile, perm> */ 95 - state = aa_dfa_next(rules->policy->dfa, 96 - rules->policy->start[AA_CLASS_SIGNAL], 97 - ad->signal); 93 + state = RULE_MEDIATES(rules, AA_CLASS_SIGNAL); 94 + if (!state) 95 + return 0; 96 + state = aa_dfa_next(rules->policy->dfa, state, ad->signal); 98 97 aa_label_match(profile, rules, peer, state, false, request, &perms); 99 98 aa_apply_modes_to_perms(profile, &perms); 100 99 return aa_check_perms(profile, &perms, request, ad, audit_signal_cb);
+21 -16
security/apparmor/label.c
··· 198 198 return false; 199 199 } 200 200 201 - static long accum_vec_flags(struct aa_profile **vec, int n) 201 + static void accum_label_info(struct aa_label *new) 202 202 { 203 203 long u = FLAG_UNCONFINED; 204 204 int i; 205 205 206 - AA_BUG(!vec); 206 + AA_BUG(!new); 207 207 208 - for (i = 0; i < n; i++) { 209 - u |= vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 | 210 - FLAG_STALE); 211 - if (!(u & vec[i]->label.flags & FLAG_UNCONFINED)) 208 + /* size == 1 is a profile and flags must be set as part of creation */ 209 + if (new->size == 1) 210 + return; 211 + 212 + for (i = 0; i < new->size; i++) { 213 + u |= new->vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 | 214 + FLAG_STALE); 215 + if (!(u & new->vec[i]->label.flags & FLAG_UNCONFINED)) 212 216 u &= ~FLAG_UNCONFINED; 217 + new->mediates |= new->vec[i]->label.mediates; 213 218 } 214 - 215 - return u; 219 + new->flags |= u; 216 220 } 217 221 218 222 static int sort_cmp(const void *a, const void *b) ··· 435 431 436 432 /* + 1 for null terminator entry on vec */ 437 433 new = kzalloc(struct_size(new, vec, size + 1), gfp); 438 - AA_DEBUG("%s (%p)\n", __func__, new); 434 + AA_DEBUG(DEBUG_LABEL, "%s (%p)\n", __func__, new); 439 435 if (!new) 440 436 goto fail; 441 437 ··· 649 645 rb_replace_node(&old->node, &new->node, &ls->root); 650 646 old->flags &= ~FLAG_IN_TREE; 651 647 new->flags |= FLAG_IN_TREE; 648 + accum_label_info(new); 652 649 return true; 653 650 } 654 651 ··· 710 705 rb_link_node(&label->node, parent, new); 711 706 rb_insert_color(&label->node, &ls->root); 712 707 label->flags |= FLAG_IN_TREE; 708 + accum_label_info(label); 713 709 714 710 return aa_get_label(label); 715 711 } ··· 1091 1085 else if (k == b->size) 1092 1086 return aa_get_label(b); 1093 1087 } 1094 - new->flags |= accum_vec_flags(new->vec, new->size); 1095 1088 ls = labels_set(new); 1096 1089 write_lock_irqsave(&ls->lock, flags); 1097 1090 label = __label_insert(labels_set(new), new, false); ··· 1461 1456 1462 1457 /* 1463 1458 * cached label name is present and visible 1464 - * @label->hname only exists if label is namespace hierachical 1459 + * @label->hname only exists if label is namespace hierarchical 1465 1460 */ 1466 1461 static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label, 1467 1462 int flags) ··· 1622 1617 AA_BUG(!str && size != 0); 1623 1618 AA_BUG(!label); 1624 1619 1625 - if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) { 1620 + if (DEBUG_ABS_ROOT && (flags & FLAG_ABS_ROOT)) { 1626 1621 ns = root_ns; 1627 1622 len = snprintf(str, size, "_"); 1628 1623 update_for_len(total, len, size, str); ··· 1736 1731 display_mode(ns, label, flags)) { 1737 1732 len = aa_label_asxprint(&name, ns, label, flags, gfp); 1738 1733 if (len < 0) { 1739 - AA_DEBUG("label print error"); 1734 + AA_DEBUG(DEBUG_LABEL, "label print error"); 1740 1735 return; 1741 1736 } 1742 1737 str = name; ··· 1764 1759 1765 1760 len = aa_label_asxprint(&str, ns, label, flags, gfp); 1766 1761 if (len < 0) { 1767 - AA_DEBUG("label print error"); 1762 + AA_DEBUG(DEBUG_LABEL, "label print error"); 1768 1763 return; 1769 1764 } 1770 1765 seq_puts(f, str); ··· 1787 1782 1788 1783 len = aa_label_asxprint(&str, ns, label, flags, gfp); 1789 1784 if (len < 0) { 1790 - AA_DEBUG("label print error"); 1785 + AA_DEBUG(DEBUG_LABEL, "label print error"); 1791 1786 return; 1792 1787 } 1793 1788 pr_info("%s", str); ··· 1870 1865 AA_BUG(!str); 1871 1866 1872 1867 str = skipn_spaces(str, n); 1873 - if (str == NULL || (AA_DEBUG_LABEL && *str == '_' && 1868 + if (str == NULL || (DEBUG_ABS_ROOT && *str == '_' && 1874 1869 base != &root_ns->unconfined->label)) 1875 1870 return ERR_PTR(-EINVAL); 1876 1871
+114
security/apparmor/lib.c
··· 25 25 .quiet = ALL_PERMS_MASK, 26 26 .hide = ALL_PERMS_MASK }; 27 27 28 + struct val_table_ent { 29 + const char *str; 30 + int value; 31 + }; 32 + 33 + static struct val_table_ent debug_values_table[] = { 34 + { "N", DEBUG_NONE }, 35 + { "none", DEBUG_NONE }, 36 + { "n", DEBUG_NONE }, 37 + { "0", DEBUG_NONE }, 38 + { "all", DEBUG_ALL }, 39 + { "Y", DEBUG_ALL }, 40 + { "y", DEBUG_ALL }, 41 + { "1", DEBUG_ALL }, 42 + { "abs_root", DEBUG_LABEL_ABS_ROOT }, 43 + { "label", DEBUG_LABEL }, 44 + { "domain", DEBUG_DOMAIN }, 45 + { "policy", DEBUG_POLICY }, 46 + { "interface", DEBUG_INTERFACE }, 47 + { NULL, 0 } 48 + }; 49 + 50 + static struct val_table_ent *val_table_find_ent(struct val_table_ent *table, 51 + const char *name, size_t len) 52 + { 53 + struct val_table_ent *entry; 54 + 55 + for (entry = table; entry->str != NULL; entry++) { 56 + if (strncmp(entry->str, name, len) == 0 && 57 + strlen(entry->str) == len) 58 + return entry; 59 + } 60 + return NULL; 61 + } 62 + 63 + int aa_parse_debug_params(const char *str) 64 + { 65 + struct val_table_ent *ent; 66 + const char *next; 67 + int val = 0; 68 + 69 + do { 70 + size_t n = strcspn(str, "\r\n,"); 71 + 72 + next = str + n; 73 + ent = val_table_find_ent(debug_values_table, str, next - str); 74 + if (ent) 75 + val |= ent->value; 76 + else 77 + AA_DEBUG(DEBUG_INTERFACE, "unknown debug type '%.*s'", 78 + (int)(next - str), str); 79 + str = next + 1; 80 + } while (*next != 0); 81 + return val; 82 + } 83 + 84 + /** 85 + * val_mask_to_str - convert a perm mask to its short string 86 + * @str: character buffer to store string in (at least 10 characters) 87 + * @size: size of the @str buffer 88 + * @table: NUL-terminated character buffer of permission characters (NOT NULL) 89 + * @mask: permission mask to convert 90 + */ 91 + static int val_mask_to_str(char *str, size_t size, 92 + const struct val_table_ent *table, u32 mask) 93 + { 94 + const struct val_table_ent *ent; 95 + int total = 0; 96 + 97 + for (ent = table; ent->str; ent++) { 98 + if (ent->value && (ent->value & mask) == ent->value) { 99 + int len = scnprintf(str, size, "%s%s", total ? "," : "", 100 + ent->str); 101 + size -= len; 102 + str += len; 103 + total += len; 104 + mask &= ~ent->value; 105 + } 106 + } 107 + 108 + return total; 109 + } 110 + 111 + int aa_print_debug_params(char *buffer) 112 + { 113 + if (!aa_g_debug) 114 + return sprintf(buffer, "N"); 115 + return val_mask_to_str(buffer, PAGE_SIZE, debug_values_table, 116 + aa_g_debug); 117 + } 118 + 119 + bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp) 120 + { 121 + char **n; 122 + int i; 123 + 124 + if (t->size == newsize) 125 + return true; 126 + n = kcalloc(newsize, sizeof(*n), gfp); 127 + if (!n) 128 + return false; 129 + for (i = 0; i < min(t->size, newsize); i++) 130 + n[i] = t->table[i]; 131 + for (; i < t->size; i++) 132 + kfree_sensitive(t->table[i]); 133 + if (newsize > t->size) 134 + memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n)); 135 + kfree_sensitive(t->table); 136 + t->table = n; 137 + t->size = newsize; 138 + 139 + return true; 140 + } 141 + 28 142 /** 29 143 * aa_free_str_table - free entries str table 30 144 * @t: the string table to free (MAYBE NULL)
+374 -94
security/apparmor/lsm.c
··· 26 26 #include <uapi/linux/mount.h> 27 27 #include <uapi/linux/lsm.h> 28 28 29 + #include "include/af_unix.h" 29 30 #include "include/apparmor.h" 30 31 #include "include/apparmorfs.h" 31 32 #include "include/audit.h" ··· 127 126 struct aa_label *tracer, *tracee; 128 127 const struct cred *cred; 129 128 int error; 129 + bool needput; 130 130 131 131 cred = get_task_cred(child); 132 132 tracee = cred_label(cred); /* ref count on cred */ 133 - tracer = __begin_current_label_crit_section(); 133 + tracer = __begin_current_label_crit_section(&needput); 134 134 error = aa_may_ptrace(current_cred(), tracer, cred, tracee, 135 135 (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ 136 136 : AA_PTRACE_TRACE); 137 - __end_current_label_crit_section(tracer); 137 + __end_current_label_crit_section(tracer, needput); 138 138 put_cred(cred); 139 139 140 140 return error; ··· 146 144 struct aa_label *tracer, *tracee; 147 145 const struct cred *cred; 148 146 int error; 147 + bool needput; 149 148 150 - tracee = __begin_current_label_crit_section(); 149 + tracee = __begin_current_label_crit_section(&needput); 151 150 cred = get_task_cred(parent); 152 151 tracer = cred_label(cred); /* ref count on cred */ 153 152 error = aa_may_ptrace(cred, tracer, current_cred(), tracee, 154 153 AA_PTRACE_TRACE); 155 154 put_cred(cred); 156 - __end_current_label_crit_section(tracee); 155 + __end_current_label_crit_section(tracee, needput); 157 156 158 157 return error; 159 158 } ··· 179 176 struct label_it i; 180 177 181 178 label_for_each_confined(i, label, profile) { 182 - struct aa_ruleset *rules; 183 - if (COMPLAIN_MODE(profile)) 184 - continue; 185 - rules = list_first_entry(&profile->rules, 186 - typeof(*rules), list); 187 - *effective = cap_intersect(*effective, 188 - rules->caps.allow); 189 - *permitted = cap_intersect(*permitted, 190 - rules->caps.allow); 179 + kernel_cap_t allowed; 180 + 181 + allowed = aa_profile_capget(profile); 182 + *effective = cap_intersect(*effective, allowed); 183 + *permitted = cap_intersect(*permitted, allowed); 191 184 } 192 185 } 193 186 rcu_read_unlock(); ··· 220 221 { 221 222 struct aa_label *label; 222 223 int error = 0; 224 + bool needput; 223 225 224 - label = __begin_current_label_crit_section(); 226 + label = __begin_current_label_crit_section(&needput); 225 227 if (!unconfined(label)) 226 228 error = aa_path_perm(op, current_cred(), label, path, 0, mask, 227 229 cond); 228 - __end_current_label_crit_section(label); 230 + __end_current_label_crit_section(label, needput); 229 231 230 232 return error; 231 233 } ··· 524 524 { 525 525 struct aa_label *label; 526 526 int error = 0; 527 + bool needput; 527 528 528 529 /* don't reaudit files closed during inheritance */ 529 - if (file->f_path.dentry == aa_null.dentry) 530 + if (unlikely(file->f_path.dentry == aa_null.dentry)) 530 531 return -EACCES; 531 532 532 - label = __begin_current_label_crit_section(); 533 + label = __begin_current_label_crit_section(&needput); 533 534 error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic); 534 - __end_current_label_crit_section(label); 535 + __end_current_label_crit_section(label, needput); 535 536 536 537 return error; 537 538 } ··· 634 633 635 634 AA_BUG(!profile); 636 635 637 - rules = list_first_entry(&profile->rules, typeof(*rules), list); 636 + rules = profile->label.rules[0]; 638 637 state = RULE_MEDIATES(rules, AA_CLASS_IO_URING); 639 638 if (state) { 640 639 struct aa_perms perms = { }; ··· 665 664 struct aa_profile *profile; 666 665 struct aa_label *label; 667 666 int error; 667 + bool needput; 668 668 DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING, 669 669 OP_URING_OVERRIDE); 670 670 671 671 ad.uring.target = cred_label(new); 672 - label = __begin_current_label_crit_section(); 672 + label = __begin_current_label_crit_section(&needput); 673 673 error = fn_for_each(label, profile, 674 674 profile_uring(profile, AA_MAY_OVERRIDE_CRED, 675 675 cred_label(new), CAP_SYS_ADMIN, &ad)); 676 - __end_current_label_crit_section(label); 676 + __end_current_label_crit_section(label, needput); 677 677 678 678 return error; 679 679 } ··· 690 688 struct aa_profile *profile; 691 689 struct aa_label *label; 692 690 int error; 691 + bool needput; 693 692 DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING, 694 693 OP_URING_SQPOLL); 695 694 696 - label = __begin_current_label_crit_section(); 695 + label = __begin_current_label_crit_section(&needput); 697 696 error = fn_for_each(label, profile, 698 697 profile_uring(profile, AA_MAY_CREATE_SQPOLL, 699 698 NULL, CAP_SYS_ADMIN, &ad)); 700 - __end_current_label_crit_section(label); 699 + __end_current_label_crit_section(label, needput); 701 700 702 701 return error; 703 702 } ··· 709 706 { 710 707 struct aa_label *label; 711 708 int error = 0; 709 + bool needput; 712 710 713 711 /* Discard magic */ 714 712 if ((flags & MS_MGC_MSK) == MS_MGC_VAL) ··· 717 713 718 714 flags &= ~AA_MS_IGNORE_MASK; 719 715 720 - label = __begin_current_label_crit_section(); 716 + label = __begin_current_label_crit_section(&needput); 721 717 if (!unconfined(label)) { 722 718 if (flags & MS_REMOUNT) 723 719 error = aa_remount(current_cred(), label, path, flags, ··· 736 732 error = aa_new_mount(current_cred(), label, dev_name, 737 733 path, type, flags, data); 738 734 } 739 - __end_current_label_crit_section(label); 735 + __end_current_label_crit_section(label, needput); 740 736 741 737 return error; 742 738 } ··· 746 742 { 747 743 struct aa_label *label; 748 744 int error = 0; 745 + bool needput; 749 746 750 - label = __begin_current_label_crit_section(); 747 + label = __begin_current_label_crit_section(&needput); 751 748 if (!unconfined(label)) 752 749 error = aa_move_mount(current_cred(), label, from_path, 753 750 to_path); 754 - __end_current_label_crit_section(label); 751 + __end_current_label_crit_section(label, needput); 755 752 756 753 return error; 757 754 } ··· 761 756 { 762 757 struct aa_label *label; 763 758 int error = 0; 759 + bool needput; 764 760 765 - label = __begin_current_label_crit_section(); 761 + label = __begin_current_label_crit_section(&needput); 766 762 if (!unconfined(label)) 767 763 error = aa_umount(current_cred(), label, mnt, flags); 768 - __end_current_label_crit_section(label); 764 + __end_current_label_crit_section(label, needput); 769 765 770 766 return error; 771 767 } ··· 990 984 991 985 static void apparmor_current_getlsmprop_subj(struct lsm_prop *prop) 992 986 { 993 - struct aa_label *label = __begin_current_label_crit_section(); 987 + struct aa_label *label; 988 + bool needput; 994 989 990 + label = __begin_current_label_crit_section(&needput); 995 991 prop->apparmor.label = label; 996 - __end_current_label_crit_section(label); 992 + __end_current_label_crit_section(label, needput); 997 993 } 998 994 999 995 static void apparmor_task_getlsmprop_obj(struct task_struct *p, ··· 1010 1002 static int apparmor_task_setrlimit(struct task_struct *task, 1011 1003 unsigned int resource, struct rlimit *new_rlim) 1012 1004 { 1013 - struct aa_label *label = __begin_current_label_crit_section(); 1005 + struct aa_label *label; 1014 1006 int error = 0; 1007 + bool needput; 1008 + 1009 + label = __begin_current_label_crit_section(&needput); 1015 1010 1016 1011 if (!unconfined(label)) 1017 1012 error = aa_task_setrlimit(current_cred(), label, task, 1018 1013 resource, new_rlim); 1019 - __end_current_label_crit_section(label); 1014 + __end_current_label_crit_section(label, needput); 1020 1015 1021 1016 return error; 1022 1017 } ··· 1030 1019 const struct cred *tc; 1031 1020 struct aa_label *cl, *tl; 1032 1021 int error; 1022 + bool needput; 1033 1023 1034 1024 tc = get_task_cred(target); 1035 1025 tl = aa_get_newest_cred_label(tc); ··· 1042 1030 error = aa_may_signal(cred, cl, tc, tl, sig); 1043 1031 aa_put_label(cl); 1044 1032 } else { 1045 - cl = __begin_current_label_crit_section(); 1033 + cl = __begin_current_label_crit_section(&needput); 1046 1034 error = aa_may_signal(current_cred(), cl, tc, tl, sig); 1047 - __end_current_label_crit_section(cl); 1035 + __end_current_label_crit_section(cl, needput); 1048 1036 } 1049 1037 aa_put_label(tl); 1050 1038 put_cred(tc); ··· 1073 1061 return error; 1074 1062 } 1075 1063 1064 + static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t gfp) 1065 + { 1066 + struct aa_sk_ctx *ctx = aa_sock(sk); 1067 + struct aa_label *label; 1068 + bool needput; 1069 + 1070 + label = __begin_current_label_crit_section(&needput); 1071 + //spin_lock_init(&ctx->lock); 1072 + rcu_assign_pointer(ctx->label, aa_get_label(label)); 1073 + rcu_assign_pointer(ctx->peer, NULL); 1074 + rcu_assign_pointer(ctx->peer_lastupdate, NULL); 1075 + __end_current_label_crit_section(label, needput); 1076 + return 0; 1077 + } 1078 + 1076 1079 static void apparmor_sk_free_security(struct sock *sk) 1077 1080 { 1078 1081 struct aa_sk_ctx *ctx = aa_sock(sk); 1079 1082 1080 - aa_put_label(ctx->label); 1081 - aa_put_label(ctx->peer); 1083 + /* dead these won't be updated any more */ 1084 + aa_put_label(rcu_dereference_protected(ctx->label, true)); 1085 + aa_put_label(rcu_dereference_protected(ctx->peer, true)); 1086 + aa_put_label(rcu_dereference_protected(ctx->peer_lastupdate, true)); 1082 1087 } 1083 1088 1084 1089 /** ··· 1109 1080 struct aa_sk_ctx *ctx = aa_sock(sk); 1110 1081 struct aa_sk_ctx *new = aa_sock(newsk); 1111 1082 1112 - if (new->label) 1113 - aa_put_label(new->label); 1114 - new->label = aa_get_label(ctx->label); 1083 + /* not actually in use yet */ 1084 + if (rcu_access_pointer(ctx->label) != rcu_access_pointer(new->label)) { 1085 + aa_put_label(rcu_dereference_protected(new->label, true)); 1086 + rcu_assign_pointer(new->label, aa_get_label_rcu(&ctx->label)); 1087 + } 1115 1088 1116 - if (new->peer) 1117 - aa_put_label(new->peer); 1118 - new->peer = aa_get_label(ctx->peer); 1089 + if (rcu_access_pointer(ctx->peer) != rcu_access_pointer(new->peer)) { 1090 + aa_put_label(rcu_dereference_protected(new->peer, true)); 1091 + rcu_assign_pointer(new->peer, aa_get_label_rcu(&ctx->peer)); 1092 + } 1093 + 1094 + if (rcu_access_pointer(ctx->peer_lastupdate) != rcu_access_pointer(new->peer_lastupdate)) { 1095 + aa_put_label(rcu_dereference_protected(new->peer_lastupdate, true)); 1096 + rcu_assign_pointer(new->peer_lastupdate, 1097 + aa_get_label_rcu(&ctx->peer_lastupdate)); 1098 + } 1099 + } 1100 + 1101 + static int unix_connect_perm(const struct cred *cred, struct aa_label *label, 1102 + struct sock *sk, struct sock *peer_sk) 1103 + { 1104 + struct aa_sk_ctx *peer_ctx = aa_sock(peer_sk); 1105 + int error; 1106 + 1107 + error = aa_unix_peer_perm(cred, label, OP_CONNECT, 1108 + (AA_MAY_CONNECT | AA_MAY_SEND | AA_MAY_RECEIVE), 1109 + sk, peer_sk, 1110 + rcu_dereference_protected(peer_ctx->label, 1111 + lockdep_is_held(&unix_sk(peer_sk)->lock))); 1112 + if (!is_unix_fs(peer_sk)) { 1113 + last_error(error, 1114 + aa_unix_peer_perm(cred, 1115 + rcu_dereference_protected(peer_ctx->label, 1116 + lockdep_is_held(&unix_sk(peer_sk)->lock)), 1117 + OP_CONNECT, 1118 + (AA_MAY_ACCEPT | AA_MAY_SEND | AA_MAY_RECEIVE), 1119 + peer_sk, sk, label)); 1120 + } 1121 + 1122 + return error; 1123 + } 1124 + 1125 + /* lockdep check in unix_connect_perm - push sks here to check */ 1126 + static void unix_connect_peers(struct aa_sk_ctx *sk_ctx, 1127 + struct aa_sk_ctx *peer_ctx) 1128 + { 1129 + /* Cross reference the peer labels for SO_PEERSEC */ 1130 + struct aa_label *label = rcu_dereference_protected(sk_ctx->label, true); 1131 + 1132 + aa_get_label(label); 1133 + aa_put_label(rcu_dereference_protected(peer_ctx->peer, 1134 + true)); 1135 + rcu_assign_pointer(peer_ctx->peer, label); /* transfer cnt */ 1136 + 1137 + label = aa_get_label(rcu_dereference_protected(peer_ctx->label, 1138 + true)); 1139 + //spin_unlock(&peer_ctx->lock); 1140 + 1141 + //spin_lock(&sk_ctx->lock); 1142 + aa_put_label(rcu_dereference_protected(sk_ctx->peer, 1143 + true)); 1144 + aa_put_label(rcu_dereference_protected(sk_ctx->peer_lastupdate, 1145 + true)); 1146 + 1147 + rcu_assign_pointer(sk_ctx->peer, aa_get_label(label)); 1148 + rcu_assign_pointer(sk_ctx->peer_lastupdate, label); /* transfer cnt */ 1149 + //spin_unlock(&sk_ctx->lock); 1150 + } 1151 + 1152 + /** 1153 + * apparmor_unix_stream_connect - check perms before making unix domain conn 1154 + * @sk: sk attempting to connect 1155 + * @peer_sk: sk that is accepting the connection 1156 + * @newsk: new sk created for this connection 1157 + * peer is locked when this hook is called 1158 + * 1159 + * Return: 1160 + * 0 if connection is permitted 1161 + * error code on denial or failure 1162 + */ 1163 + static int apparmor_unix_stream_connect(struct sock *sk, struct sock *peer_sk, 1164 + struct sock *newsk) 1165 + { 1166 + struct aa_sk_ctx *sk_ctx = aa_sock(sk); 1167 + struct aa_sk_ctx *peer_ctx = aa_sock(peer_sk); 1168 + struct aa_sk_ctx *new_ctx = aa_sock(newsk); 1169 + struct aa_label *label; 1170 + int error; 1171 + bool needput; 1172 + 1173 + label = __begin_current_label_crit_section(&needput); 1174 + error = unix_connect_perm(current_cred(), label, sk, peer_sk); 1175 + __end_current_label_crit_section(label, needput); 1176 + 1177 + if (error) 1178 + return error; 1179 + 1180 + /* newsk doesn't go through post_create, but does go through 1181 + * security_sk_alloc() 1182 + */ 1183 + rcu_assign_pointer(new_ctx->label, 1184 + aa_get_label(rcu_dereference_protected(peer_ctx->label, 1185 + true))); 1186 + 1187 + /* Cross reference the peer labels for SO_PEERSEC */ 1188 + unix_connect_peers(sk_ctx, new_ctx); 1189 + 1190 + return 0; 1191 + } 1192 + 1193 + /** 1194 + * apparmor_unix_may_send - check perms before conn or sending unix dgrams 1195 + * @sock: socket sending the message 1196 + * @peer: socket message is being send to 1197 + * 1198 + * Performs bidirectional permission checks for Unix domain socket communication: 1199 + * 1. Verifies sender has AA_MAY_SEND to target socket 1200 + * 2. Verifies receiver has AA_MAY_RECEIVE from source socket 1201 + * 1202 + * sock and peer are locked when this hook is called 1203 + * called by: dgram_connect peer setup but path not copied to newsk 1204 + * 1205 + * Return: 1206 + * 0 if transmission is permitted 1207 + * error code on denial or failure 1208 + */ 1209 + static int apparmor_unix_may_send(struct socket *sock, struct socket *peer) 1210 + { 1211 + struct aa_sk_ctx *peer_ctx = aa_sock(peer->sk); 1212 + struct aa_label *label; 1213 + int error; 1214 + bool needput; 1215 + 1216 + label = __begin_current_label_crit_section(&needput); 1217 + error = xcheck(aa_unix_peer_perm(current_cred(), 1218 + label, OP_SENDMSG, AA_MAY_SEND, 1219 + sock->sk, peer->sk, 1220 + rcu_dereference_protected(peer_ctx->label, 1221 + true)), 1222 + aa_unix_peer_perm(peer->file ? peer->file->f_cred : NULL, 1223 + rcu_dereference_protected(peer_ctx->label, 1224 + true), 1225 + OP_SENDMSG, AA_MAY_RECEIVE, peer->sk, 1226 + sock->sk, label)); 1227 + __end_current_label_crit_section(label, needput); 1228 + 1229 + return error; 1119 1230 } 1120 1231 1121 1232 static int apparmor_socket_create(int family, int type, int protocol, int kern) ··· 1265 1096 1266 1097 AA_BUG(in_interrupt()); 1267 1098 1099 + if (kern) 1100 + return 0; 1101 + 1268 1102 label = begin_current_label_crit_section(); 1269 - if (!(kern || unconfined(label))) 1270 - error = af_select(family, 1271 - create_perm(label, family, type, protocol), 1272 - aa_af_perm(current_cred(), label, 1273 - OP_CREATE, AA_MAY_CREATE, 1274 - family, type, protocol)); 1103 + if (!unconfined(label)) { 1104 + if (family == PF_UNIX) 1105 + error = aa_unix_create_perm(label, family, type, 1106 + protocol); 1107 + else 1108 + error = aa_af_perm(current_cred(), label, OP_CREATE, 1109 + AA_MAY_CREATE, family, type, 1110 + protocol); 1111 + } 1275 1112 end_current_label_crit_section(label); 1276 1113 1277 1114 return error; ··· 1310 1135 if (sock->sk) { 1311 1136 struct aa_sk_ctx *ctx = aa_sock(sock->sk); 1312 1137 1313 - aa_put_label(ctx->label); 1314 - ctx->label = aa_get_label(label); 1138 + /* still not live */ 1139 + aa_put_label(rcu_dereference_protected(ctx->label, true)); 1140 + rcu_assign_pointer(ctx->label, aa_get_label(label)); 1315 1141 } 1316 1142 aa_put_label(label); 1317 1143 1318 1144 return 0; 1319 1145 } 1320 1146 1147 + static int apparmor_socket_socketpair(struct socket *socka, 1148 + struct socket *sockb) 1149 + { 1150 + struct aa_sk_ctx *a_ctx = aa_sock(socka->sk); 1151 + struct aa_sk_ctx *b_ctx = aa_sock(sockb->sk); 1152 + struct aa_label *label; 1153 + 1154 + /* socks not live yet - initial values set in sk_alloc */ 1155 + label = begin_current_label_crit_section(); 1156 + if (rcu_access_pointer(a_ctx->label) != label) { 1157 + AA_BUG("a_ctx != label"); 1158 + aa_put_label(rcu_dereference_protected(a_ctx->label, true)); 1159 + rcu_assign_pointer(a_ctx->label, aa_get_label(label)); 1160 + } 1161 + if (rcu_access_pointer(b_ctx->label) != label) { 1162 + AA_BUG("b_ctx != label"); 1163 + aa_put_label(rcu_dereference_protected(b_ctx->label, true)); 1164 + rcu_assign_pointer(b_ctx->label, aa_get_label(label)); 1165 + } 1166 + 1167 + if (socka->sk->sk_family == PF_UNIX) { 1168 + /* unix socket pairs by-pass unix_stream_connect */ 1169 + unix_connect_peers(a_ctx, b_ctx); 1170 + } 1171 + end_current_label_crit_section(label); 1172 + 1173 + return 0; 1174 + } 1175 + 1176 + /** 1177 + * apparmor_socket_bind - check perms before bind addr to socket 1178 + * @sock: socket to bind the address to (must be non-NULL) 1179 + * @address: address that is being bound (must be non-NULL) 1180 + * @addrlen: length of @address 1181 + * 1182 + * Performs security checks before allowing a socket to bind to an address. 1183 + * Handles Unix domain sockets specially through aa_unix_bind_perm(). 1184 + * For other socket families, uses generic permission check via aa_sk_perm(). 1185 + * 1186 + * Return: 1187 + * 0 if binding is permitted 1188 + * error code on denial or invalid parameters 1189 + */ 1321 1190 static int apparmor_socket_bind(struct socket *sock, 1322 1191 struct sockaddr *address, int addrlen) 1323 1192 { ··· 1370 1151 AA_BUG(!address); 1371 1152 AA_BUG(in_interrupt()); 1372 1153 1373 - return af_select(sock->sk->sk_family, 1374 - bind_perm(sock, address, addrlen), 1375 - aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk)); 1154 + if (sock->sk->sk_family == PF_UNIX) 1155 + return aa_unix_bind_perm(sock, address, addrlen); 1156 + return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk); 1376 1157 } 1377 1158 1378 1159 static int apparmor_socket_connect(struct socket *sock, ··· 1383 1164 AA_BUG(!address); 1384 1165 AA_BUG(in_interrupt()); 1385 1166 1386 - return af_select(sock->sk->sk_family, 1387 - connect_perm(sock, address, addrlen), 1388 - aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk)); 1167 + /* PF_UNIX goes through unix_stream_connect && unix_may_send */ 1168 + if (sock->sk->sk_family == PF_UNIX) 1169 + return 0; 1170 + return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk); 1389 1171 } 1390 1172 1391 1173 static int apparmor_socket_listen(struct socket *sock, int backlog) ··· 1395 1175 AA_BUG(!sock->sk); 1396 1176 AA_BUG(in_interrupt()); 1397 1177 1398 - return af_select(sock->sk->sk_family, 1399 - listen_perm(sock, backlog), 1400 - aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk)); 1178 + if (sock->sk->sk_family == PF_UNIX) 1179 + return aa_unix_listen_perm(sock, backlog); 1180 + return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk); 1401 1181 } 1402 1182 1403 1183 /* ··· 1411 1191 AA_BUG(!newsock); 1412 1192 AA_BUG(in_interrupt()); 1413 1193 1414 - return af_select(sock->sk->sk_family, 1415 - accept_perm(sock, newsock), 1416 - aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk)); 1194 + if (sock->sk->sk_family == PF_UNIX) 1195 + return aa_unix_accept_perm(sock, newsock); 1196 + return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk); 1417 1197 } 1418 1198 1419 1199 static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, ··· 1424 1204 AA_BUG(!msg); 1425 1205 AA_BUG(in_interrupt()); 1426 1206 1427 - return af_select(sock->sk->sk_family, 1428 - msg_perm(op, request, sock, msg, size), 1429 - aa_sk_perm(op, request, sock->sk)); 1207 + /* PF_UNIX goes through unix_may_send */ 1208 + if (sock->sk->sk_family == PF_UNIX) 1209 + return 0; 1210 + return aa_sk_perm(op, request, sock->sk); 1430 1211 } 1431 1212 1432 1213 static int apparmor_socket_sendmsg(struct socket *sock, ··· 1449 1228 AA_BUG(!sock->sk); 1450 1229 AA_BUG(in_interrupt()); 1451 1230 1452 - return af_select(sock->sk->sk_family, 1453 - sock_perm(op, request, sock), 1454 - aa_sk_perm(op, request, sock->sk)); 1231 + if (sock->sk->sk_family == PF_UNIX) 1232 + return aa_unix_sock_perm(op, request, sock); 1233 + return aa_sk_perm(op, request, sock->sk); 1455 1234 } 1456 1235 1457 1236 static int apparmor_socket_getsockname(struct socket *sock) ··· 1472 1251 AA_BUG(!sock->sk); 1473 1252 AA_BUG(in_interrupt()); 1474 1253 1475 - return af_select(sock->sk->sk_family, 1476 - opt_perm(op, request, sock, level, optname), 1477 - aa_sk_perm(op, request, sock->sk)); 1254 + if (sock->sk->sk_family == PF_UNIX) 1255 + return aa_unix_opt_perm(op, request, sock, level, optname); 1256 + return aa_sk_perm(op, request, sock->sk); 1478 1257 } 1479 1258 1480 1259 static int apparmor_socket_getsockopt(struct socket *sock, int level, ··· 1510 1289 static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 1511 1290 { 1512 1291 struct aa_sk_ctx *ctx = aa_sock(sk); 1292 + int error; 1513 1293 1514 1294 if (!skb->secmark) 1515 1295 return 0; ··· 1519 1297 * If reach here before socket_post_create hook is called, in which 1520 1298 * case label is null, drop the packet. 1521 1299 */ 1522 - if (!ctx->label) 1300 + if (!rcu_access_pointer(ctx->label)) 1523 1301 return -EACCES; 1524 1302 1525 - return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE, 1526 - skb->secmark, sk); 1303 + rcu_read_lock(); 1304 + error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_RECVMSG, 1305 + AA_MAY_RECEIVE, skb->secmark, sk); 1306 + rcu_read_unlock(); 1307 + 1308 + return error; 1527 1309 } 1528 1310 #endif 1529 1311 1530 1312 1531 - static struct aa_label *sk_peer_label(struct sock *sk) 1313 + static struct aa_label *sk_peer_get_label(struct sock *sk) 1532 1314 { 1533 1315 struct aa_sk_ctx *ctx = aa_sock(sk); 1316 + struct aa_label *label = ERR_PTR(-ENOPROTOOPT); 1534 1317 1535 - if (ctx->peer) 1536 - return ctx->peer; 1318 + if (rcu_access_pointer(ctx->peer)) 1319 + return aa_get_label_rcu(&ctx->peer); 1537 1320 1538 - return ERR_PTR(-ENOPROTOOPT); 1321 + if (sk->sk_family != PF_UNIX) 1322 + return ERR_PTR(-ENOPROTOOPT); 1323 + 1324 + return label; 1539 1325 } 1540 1326 1541 1327 /** ··· 1565 1335 struct aa_label *label; 1566 1336 struct aa_label *peer; 1567 1337 1568 - label = begin_current_label_crit_section(); 1569 - peer = sk_peer_label(sock->sk); 1338 + peer = sk_peer_get_label(sock->sk); 1570 1339 if (IS_ERR(peer)) { 1571 1340 error = PTR_ERR(peer); 1572 1341 goto done; 1573 1342 } 1343 + label = begin_current_label_crit_section(); 1574 1344 slen = aa_label_asxprint(&name, labels_ns(label), peer, 1575 1345 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 1576 1346 FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); 1577 1347 /* don't include terminating \0 in slen, it breaks some apps */ 1578 1348 if (slen < 0) { 1579 1349 error = -ENOMEM; 1580 - goto done; 1350 + goto done_put; 1581 1351 } 1582 1352 if (slen > len) { 1583 1353 error = -ERANGE; ··· 1589 1359 done_len: 1590 1360 if (copy_to_sockptr(optlen, &slen, sizeof(slen))) 1591 1361 error = -EFAULT; 1592 - done: 1362 + 1363 + done_put: 1593 1364 end_current_label_crit_section(label); 1365 + aa_put_label(peer); 1366 + done: 1594 1367 kfree(name); 1595 1368 return error; 1596 1369 } ··· 1629 1396 { 1630 1397 struct aa_sk_ctx *ctx = aa_sock(sk); 1631 1398 1632 - if (!ctx->label) 1633 - ctx->label = aa_get_current_label(); 1399 + /* setup - not live */ 1400 + if (!rcu_access_pointer(ctx->label)) 1401 + rcu_assign_pointer(ctx->label, aa_get_current_label()); 1634 1402 } 1635 1403 1636 1404 #ifdef CONFIG_NETWORK_SECMARK ··· 1639 1405 struct request_sock *req) 1640 1406 { 1641 1407 struct aa_sk_ctx *ctx = aa_sock(sk); 1408 + int error; 1642 1409 1643 1410 if (!skb->secmark) 1644 1411 return 0; 1645 1412 1646 - return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT, 1647 - skb->secmark, sk); 1413 + rcu_read_lock(); 1414 + error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_CONNECT, 1415 + AA_MAY_CONNECT, skb->secmark, sk); 1416 + rcu_read_unlock(); 1417 + 1418 + return error; 1648 1419 } 1649 1420 #endif 1650 1421 ··· 1706 1467 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), 1707 1468 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), 1708 1469 1470 + LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), 1709 1471 LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), 1710 1472 LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), 1711 1473 1474 + LSM_HOOK_INIT(unix_stream_connect, apparmor_unix_stream_connect), 1475 + LSM_HOOK_INIT(unix_may_send, apparmor_unix_may_send), 1476 + 1712 1477 LSM_HOOK_INIT(socket_create, apparmor_socket_create), 1713 1478 LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), 1479 + LSM_HOOK_INIT(socket_socketpair, apparmor_socket_socketpair), 1714 1480 LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), 1715 1481 LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), 1716 1482 LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), ··· 1815 1571 .get = param_get_aalockpolicy 1816 1572 }; 1817 1573 1574 + static int param_set_debug(const char *val, const struct kernel_param *kp); 1575 + static int param_get_debug(char *buffer, const struct kernel_param *kp); 1576 + 1818 1577 static int param_set_audit(const char *val, const struct kernel_param *kp); 1819 1578 static int param_get_audit(char *buffer, const struct kernel_param *kp); 1820 1579 ··· 1851 1604 aacompressionlevel, 0400); 1852 1605 1853 1606 /* Debug mode */ 1854 - bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES); 1855 - module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); 1607 + int aa_g_debug; 1608 + module_param_call(debug, param_set_debug, param_get_debug, 1609 + &aa_g_debug, 0600); 1856 1610 1857 1611 /* Audit mode */ 1858 1612 enum audit_mode aa_g_audit; ··· 2044 1796 if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 2045 1797 return -EPERM; 2046 1798 return param_get_int(buffer, kp); 1799 + } 1800 + 1801 + static int param_get_debug(char *buffer, const struct kernel_param *kp) 1802 + { 1803 + if (!apparmor_enabled) 1804 + return -EINVAL; 1805 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1806 + return -EPERM; 1807 + return aa_print_debug_params(buffer); 1808 + } 1809 + 1810 + static int param_set_debug(const char *val, const struct kernel_param *kp) 1811 + { 1812 + int i; 1813 + 1814 + if (!apparmor_enabled) 1815 + return -EINVAL; 1816 + if (!val) 1817 + return -EINVAL; 1818 + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 1819 + return -EPERM; 1820 + 1821 + i = aa_parse_debug_params(val); 1822 + if (i == DEBUG_PARSE_ERROR) 1823 + return -EINVAL; 1824 + 1825 + aa_g_debug = i; 1826 + return 0; 2047 1827 } 2048 1828 2049 1829 static int param_get_audit(char *buffer, const struct kernel_param *kp) ··· 2282 2006 * two should be enough, with more CPUs it is possible that more 2283 2007 * buffers will be used simultaneously. The preallocated pool may grow. 2284 2008 * This preallocation has also the side-effect that AppArmor will be 2285 - * disabled early at boot if aa_g_path_max is extremly high. 2009 + * disabled early at boot if aa_g_path_max is extremely high. 2286 2010 */ 2287 2011 if (num_online_cpus() > 1) 2288 2012 num = 4 + RESERVE_COUNT; ··· 2358 2082 { 2359 2083 struct aa_sk_ctx *ctx; 2360 2084 struct sock *sk; 2085 + int error; 2361 2086 2362 2087 if (!skb->secmark) 2363 2088 return NF_ACCEPT; ··· 2368 2091 return NF_ACCEPT; 2369 2092 2370 2093 ctx = aa_sock(sk); 2371 - if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND, 2372 - skb->secmark, sk)) 2094 + rcu_read_lock(); 2095 + error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_SENDMSG, 2096 + AA_MAY_SEND, skb->secmark, sk); 2097 + rcu_read_unlock(); 2098 + if (!error) 2373 2099 return NF_ACCEPT; 2374 2100 2375 2101 return NF_DROP_ERR(-ECONNREFUSED); ··· 2429 2149 __initcall(apparmor_nf_ip_init); 2430 2150 #endif 2431 2151 2432 - static char nulldfa_src[] = { 2152 + static char nulldfa_src[] __aligned(8) = { 2433 2153 #include "nulldfa.in" 2434 2154 }; 2435 2155 static struct aa_dfa *nulldfa; 2436 2156 2437 - static char stacksplitdfa_src[] = { 2157 + static char stacksplitdfa_src[] __aligned(8) = { 2438 2158 #include "stacksplitdfa.in" 2439 2159 }; 2440 2160 struct aa_dfa *stacksplitdfa;
+12 -11
security/apparmor/match.c
··· 679 679 return state; 680 680 } 681 681 682 - #define inc_wb_pos(wb) \ 683 - do { \ 682 + #define inc_wb_pos(wb) \ 683 + do { \ 684 + BUILD_BUG_ON_NOT_POWER_OF_2(WB_HISTORY_SIZE); \ 684 685 wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1); \ 685 - wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1); \ 686 + wb->len = (wb->len + 1) > WB_HISTORY_SIZE ? WB_HISTORY_SIZE : \ 687 + wb->len + 1; \ 686 688 } while (0) 687 689 688 690 /* For DFAs that don't support extended tagging of states */ 691 + /* adjust is only set if is_loop returns true */ 689 692 static bool is_loop(struct match_workbuf *wb, aa_state_t state, 690 693 unsigned int *adjust) 691 694 { 692 - aa_state_t pos = wb->pos; 693 - aa_state_t i; 695 + int pos = wb->pos; 696 + int i; 694 697 695 698 if (wb->history[pos] < state) 696 699 return false; 697 700 698 - for (i = 0; i <= wb->len; i++) { 701 + for (i = 0; i < wb->len; i++) { 699 702 if (wb->history[pos] == state) { 700 703 *adjust = i; 701 704 return true; 702 705 } 703 - if (pos == 0) 704 - pos = WB_HISTORY_SIZE; 705 - pos--; 706 + /* -1 wraps to WB_HISTORY_SIZE - 1 */ 707 + pos = (pos - 1) & (WB_HISTORY_SIZE - 1); 706 708 } 707 709 708 - *adjust = i; 709 - return true; 710 + return false; 710 711 } 711 712 712 713 static aa_state_t leftmatch_fb(struct aa_dfa *dfa, aa_state_t start,
+4 -8
security/apparmor/mount.c
··· 311 311 { 312 312 struct aa_perms perms = { }; 313 313 const char *mntpnt = NULL, *info = NULL; 314 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 315 - typeof(*rules), list); 314 + struct aa_ruleset *rules = profile->label.rules[0]; 316 315 int pos, error; 317 316 318 317 AA_BUG(!profile); ··· 370 371 bool binary) 371 372 { 372 373 const char *devname = NULL, *info = NULL; 373 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 374 - typeof(*rules), list); 374 + struct aa_ruleset *rules = profile->label.rules[0]; 375 375 int error = -EACCES; 376 376 377 377 AA_BUG(!profile); ··· 602 604 struct aa_profile *profile, const struct path *path, 603 605 char *buffer) 604 606 { 605 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 606 - typeof(*rules), list); 607 + struct aa_ruleset *rules = profile->label.rules[0]; 607 608 struct aa_perms perms = { }; 608 609 const char *name = NULL, *info = NULL; 609 610 aa_state_t state; ··· 665 668 const struct path *old_path, 666 669 char *old_buffer) 667 670 { 668 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 669 - typeof(*rules), list); 671 + struct aa_ruleset *rules = profile->label.rules[0]; 670 672 const char *old_name, *new_name = NULL, *info = NULL; 671 673 const char *trans_name = NULL; 672 674 struct aa_perms perms = { };
+163 -26
security/apparmor/net.c
··· 8 8 * Copyright 2009-2017 Canonical Ltd. 9 9 */ 10 10 11 + #include "include/af_unix.h" 11 12 #include "include/apparmor.h" 12 13 #include "include/audit.h" 13 14 #include "include/cred.h" ··· 22 21 23 22 struct aa_sfs_entry aa_sfs_entry_network[] = { 24 23 AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 24 + { } 25 + }; 26 + 27 + struct aa_sfs_entry aa_sfs_entry_networkv9[] = { 28 + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 29 + AA_SFS_FILE_BOOLEAN("af_unix", 1), 25 30 { } 26 31 }; 27 32 ··· 73 66 "unknown", 74 67 }; 75 68 69 + static void audit_unix_addr(struct audit_buffer *ab, const char *str, 70 + struct sockaddr_un *addr, int addrlen) 71 + { 72 + int len = unix_addr_len(addrlen); 73 + 74 + if (!addr || len <= 0) { 75 + audit_log_format(ab, " %s=none", str); 76 + } else if (addr->sun_path[0]) { 77 + audit_log_format(ab, " %s=", str); 78 + audit_log_untrustedstring(ab, addr->sun_path); 79 + } else { 80 + audit_log_format(ab, " %s=\"@", str); 81 + if (audit_string_contains_control(&addr->sun_path[1], len - 1)) 82 + audit_log_n_hex(ab, &addr->sun_path[1], len - 1); 83 + else 84 + audit_log_format(ab, "%.*s", len - 1, 85 + &addr->sun_path[1]); 86 + audit_log_format(ab, "\""); 87 + } 88 + } 89 + 90 + static void audit_unix_sk_addr(struct audit_buffer *ab, const char *str, 91 + const struct sock *sk) 92 + { 93 + const struct unix_sock *u = unix_sk(sk); 94 + 95 + if (u && u->addr) { 96 + int addrlen; 97 + struct sockaddr_un *addr = aa_sunaddr(u, &addrlen); 98 + 99 + audit_unix_addr(ab, str, addr, addrlen); 100 + } else { 101 + audit_unix_addr(ab, str, NULL, 0); 102 + 103 + } 104 + } 76 105 77 106 /* audit callback for net specific fields */ 78 107 void audit_net_cb(struct audit_buffer *ab, void *va) ··· 116 73 struct common_audit_data *sa = va; 117 74 struct apparmor_audit_data *ad = aad(sa); 118 75 119 - if (address_family_names[sa->u.net->family]) 76 + if (address_family_names[ad->common.u.net->family]) 120 77 audit_log_format(ab, " family=\"%s\"", 121 - address_family_names[sa->u.net->family]); 78 + address_family_names[ad->common.u.net->family]); 122 79 else 123 80 audit_log_format(ab, " family=\"unknown(%d)\"", 124 - sa->u.net->family); 81 + ad->common.u.net->family); 125 82 if (sock_type_names[ad->net.type]) 126 83 audit_log_format(ab, " sock_type=\"%s\"", 127 84 sock_type_names[ad->net.type]); ··· 141 98 net_mask_names, NET_PERMS_MASK); 142 99 } 143 100 } 101 + if (ad->common.u.net->family == PF_UNIX) { 102 + if (ad->net.addr || !ad->common.u.net->sk) 103 + audit_unix_addr(ab, "addr", 104 + unix_addr(ad->net.addr), 105 + ad->net.addrlen); 106 + else 107 + audit_unix_sk_addr(ab, "addr", ad->common.u.net->sk); 108 + if (ad->request & NET_PEER_MASK) { 109 + audit_unix_addr(ab, "peer_addr", 110 + unix_addr(ad->net.peer.addr), 111 + ad->net.peer.addrlen); 112 + } 113 + } 144 114 if (ad->peer) { 145 115 audit_log_format(ab, " peer="); 146 116 aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, ··· 161 105 } 162 106 } 163 107 108 + /* standard permission lookup pattern - supports early bailout */ 109 + int aa_do_perms(struct aa_profile *profile, struct aa_policydb *policy, 110 + aa_state_t state, u32 request, 111 + struct aa_perms *p, struct apparmor_audit_data *ad) 112 + { 113 + struct aa_perms perms; 114 + 115 + AA_BUG(!profile); 116 + AA_BUG(!policy); 117 + 118 + 119 + if (state || !p) 120 + p = aa_lookup_perms(policy, state); 121 + perms = *p; 122 + aa_apply_modes_to_perms(profile, &perms); 123 + return aa_check_perms(profile, &perms, request, ad, 124 + audit_net_cb); 125 + } 126 + 127 + /* only continue match if 128 + * insufficient current perms at current state 129 + * indicates there are more perms in later state 130 + * Returns: perms struct if early match 131 + */ 132 + static struct aa_perms *early_match(struct aa_policydb *policy, 133 + aa_state_t state, u32 request) 134 + { 135 + struct aa_perms *p; 136 + 137 + p = aa_lookup_perms(policy, state); 138 + if (((p->allow & request) != request) && (p->allow & AA_CONT_MATCH)) 139 + return NULL; 140 + return p; 141 + } 142 + 143 + static aa_state_t aa_dfa_match_be16(struct aa_dfa *dfa, aa_state_t state, 144 + u16 data) 145 + { 146 + __be16 buffer = cpu_to_be16(data); 147 + 148 + return aa_dfa_match_len(dfa, state, (char *) &buffer, 2); 149 + } 150 + 151 + /** 152 + * aa_match_to_prot - match the af, type, protocol triplet 153 + * @policy: policy being matched 154 + * @state: state to start in 155 + * @request: permissions being requested, ignored if @p == NULL 156 + * @af: socket address family 157 + * @type: socket type 158 + * @protocol: socket protocol 159 + * @p: output - pointer to permission associated with match 160 + * @info: output - pointer to string describing failure 161 + * 162 + * RETURNS: state match stopped in. 163 + * 164 + * If @(p) is assigned a value the returned state will be the 165 + * corresponding state. Will not set @p on failure or if match completes 166 + * only if an early match occurs 167 + */ 168 + aa_state_t aa_match_to_prot(struct aa_policydb *policy, aa_state_t state, 169 + u32 request, u16 af, int type, int protocol, 170 + struct aa_perms **p, const char **info) 171 + { 172 + state = aa_dfa_match_be16(policy->dfa, state, (u16)af); 173 + if (!state) { 174 + *info = "failed af match"; 175 + return state; 176 + } 177 + state = aa_dfa_match_be16(policy->dfa, state, (u16)type); 178 + if (state) { 179 + if (p) 180 + *p = early_match(policy, state, request); 181 + if (!p || !*p) { 182 + state = aa_dfa_match_be16(policy->dfa, state, (u16)protocol); 183 + if (!state) 184 + *info = "failed protocol match"; 185 + } 186 + } else { 187 + *info = "failed type match"; 188 + } 189 + 190 + return state; 191 + } 192 + 164 193 /* Generic af perm */ 165 194 int aa_profile_af_perm(struct aa_profile *profile, 166 195 struct apparmor_audit_data *ad, u32 request, u16 family, 167 - int type) 196 + int type, int protocol) 168 197 { 169 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 170 - typeof(*rules), list); 171 - struct aa_perms perms = { }; 198 + struct aa_ruleset *rules = profile->label.rules[0]; 199 + struct aa_perms *p = NULL; 172 200 aa_state_t state; 173 - __be16 buffer[2]; 174 201 175 202 AA_BUG(family >= AF_MAX); 176 203 AA_BUG(type < 0 || type >= SOCK_MAX); 204 + AA_BUG(profile_unconfined(profile)); 177 205 178 206 if (profile_unconfined(profile)) 179 207 return 0; 180 - state = RULE_MEDIATES(rules, AA_CLASS_NET); 208 + state = RULE_MEDIATES_NET(rules); 181 209 if (!state) 182 210 return 0; 183 - 184 - buffer[0] = cpu_to_be16(family); 185 - buffer[1] = cpu_to_be16((u16) type); 186 - state = aa_dfa_match_len(rules->policy->dfa, state, (char *) &buffer, 187 - 4); 188 - perms = *aa_lookup_perms(rules->policy, state); 189 - aa_apply_modes_to_perms(profile, &perms); 190 - 191 - return aa_check_perms(profile, &perms, request, ad, audit_net_cb); 211 + state = aa_match_to_prot(rules->policy, state, request, family, type, 212 + protocol, &p, &ad->info); 213 + return aa_do_perms(profile, rules->policy, state, request, p, ad); 192 214 } 193 215 194 216 int aa_af_perm(const struct cred *subj_cred, struct aa_label *label, 195 217 const char *op, u32 request, u16 family, int type, int protocol) 196 218 { 197 219 struct aa_profile *profile; 198 - DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol); 220 + DEFINE_AUDIT_NET(ad, op, subj_cred, NULL, family, type, protocol); 199 221 200 222 return fn_for_each_confined(label, profile, 201 223 aa_profile_af_perm(profile, &ad, request, family, 202 - type)); 224 + type, protocol)); 203 225 } 204 226 205 227 static int aa_label_sk_perm(const struct cred *subj_cred, ··· 291 157 AA_BUG(!label); 292 158 AA_BUG(!sk); 293 159 294 - if (ctx->label != kernel_t && !unconfined(label)) { 160 + if (rcu_access_pointer(ctx->label) != kernel_t && !unconfined(label)) { 295 161 struct aa_profile *profile; 296 - DEFINE_AUDIT_SK(ad, op, sk); 162 + DEFINE_AUDIT_SK(ad, op, subj_cred, sk); 297 163 298 164 ad.subj_cred = subj_cred; 299 165 error = fn_for_each_confined(label, profile, ··· 321 187 322 188 323 189 int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, 324 - const char *op, u32 request, struct socket *sock) 190 + const char *op, u32 request, struct file *file) 325 191 { 192 + struct socket *sock = (struct socket *) file->private_data; 193 + 326 194 AA_BUG(!label); 327 195 AA_BUG(!sock); 328 196 AA_BUG(!sock->sk); 329 197 198 + if (sock->sk->sk_family == PF_UNIX) 199 + return aa_unix_file_perm(subj_cred, label, op, request, file); 330 200 return aa_label_sk_perm(subj_cred, label, op, request, sock->sk); 331 201 } 332 202 ··· 361 223 { 362 224 int i, ret; 363 225 struct aa_perms perms = { }; 364 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 365 - typeof(*rules), list); 226 + struct aa_ruleset *rules = profile->label.rules[0]; 366 227 367 228 if (rules->secmark_count == 0) 368 229 return 0; ··· 394 257 u32 secid, const struct sock *sk) 395 258 { 396 259 struct aa_profile *profile; 397 - DEFINE_AUDIT_SK(ad, op, sk); 260 + DEFINE_AUDIT_SK(ad, op, NULL, sk); 398 261 399 262 return fn_for_each_confined(label, profile, 400 263 aa_secmark_perm(profile, request, secid,
+65 -28
security/apparmor/policy.c
··· 243 243 { 244 244 int i; 245 245 246 + if (!rules) 247 + return; 248 + 246 249 aa_put_pdb(rules->file); 247 250 aa_put_pdb(rules->policy); 248 251 aa_free_cap_rules(&rules->caps); ··· 262 259 struct aa_ruleset *rules; 263 260 264 261 rules = kzalloc(sizeof(*rules), gfp); 265 - if (rules) 266 - INIT_LIST_HEAD(&rules->list); 267 262 268 263 return rules; 269 264 } ··· 278 277 */ 279 278 void aa_free_profile(struct aa_profile *profile) 280 279 { 281 - struct aa_ruleset *rule, *tmp; 282 280 struct rhashtable *rht; 283 281 284 - AA_DEBUG("%s(%p)\n", __func__, profile); 282 + AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, profile); 285 283 286 284 if (!profile) 287 285 return; ··· 299 299 * at this point there are no tasks that can have a reference 300 300 * to rules 301 301 */ 302 - list_for_each_entry_safe(rule, tmp, &profile->rules, list) { 303 - list_del_init(&rule->list); 304 - free_ruleset(rule); 305 - } 302 + for (int i = 0; i < profile->n_rules; i++) 303 + free_ruleset(profile->label.rules[i]); 304 + 306 305 kfree_sensitive(profile->dirname); 307 306 308 307 if (profile->data) { ··· 330 331 gfp_t gfp) 331 332 { 332 333 struct aa_profile *profile; 333 - struct aa_ruleset *rules; 334 334 335 - /* freed by free_profile - usually through aa_put_profile */ 336 - profile = kzalloc(struct_size(profile, label.vec, 2), gfp); 335 + /* freed by free_profile - usually through aa_put_profile 336 + * this adds space for a single ruleset in the rules section of the 337 + * label 338 + */ 339 + profile = kzalloc(struct_size(profile, label.rules, 1), gfp); 337 340 if (!profile) 338 341 return NULL; 339 342 ··· 344 343 if (!aa_label_init(&profile->label, 1, gfp)) 345 344 goto fail; 346 345 347 - INIT_LIST_HEAD(&profile->rules); 348 - 349 346 /* allocate the first ruleset, but leave it empty */ 350 - rules = aa_alloc_ruleset(gfp); 351 - if (!rules) 347 + profile->label.rules[0] = aa_alloc_ruleset(gfp); 348 + if (!profile->label.rules[0]) 352 349 goto fail; 353 - list_add(&rules->list, &profile->rules); 350 + profile->n_rules = 1; 354 351 355 352 /* update being set needed by fs interface */ 356 353 if (!proxy) { ··· 363 364 profile->label.flags |= FLAG_PROFILE; 364 365 profile->label.vec[0] = profile; 365 366 367 + profile->signal = SIGKILL; 366 368 /* refcount released by caller */ 367 369 return profile; 368 370 ··· 371 371 aa_free_profile(profile); 372 372 373 373 return NULL; 374 + } 375 + 376 + static inline bool ANY_RULE_MEDIATES(struct aa_profile *profile, 377 + unsigned char class) 378 + { 379 + int i; 380 + 381 + for (i = 0; i < profile->n_rules; i++) { 382 + if (RULE_MEDIATES(profile->label.rules[i], class)) 383 + return true; 384 + } 385 + return false; 386 + } 387 + 388 + /* set of rules that are mediated by unconfined */ 389 + static int unconfined_mediates[] = { AA_CLASS_NS, AA_CLASS_IO_URING, 0 }; 390 + 391 + /* must be called after profile rulesets and start information is setup */ 392 + void aa_compute_profile_mediates(struct aa_profile *profile) 393 + { 394 + int c; 395 + 396 + if (profile_unconfined(profile)) { 397 + int *pos; 398 + 399 + for (pos = unconfined_mediates; *pos; pos++) { 400 + if (ANY_RULE_MEDIATES(profile, *pos)) 401 + profile->label.mediates |= ((u64) 1) << AA_CLASS_NS; 402 + } 403 + return; 404 + } 405 + for (c = 0; c <= AA_CLASS_LAST; c++) { 406 + if (ANY_RULE_MEDIATES(profile, c)) 407 + profile->label.mediates |= ((u64) 1) << c; 408 + } 374 409 } 375 410 376 411 /* TODO: profile accounting - setup in remove */ ··· 498 463 } 499 464 500 465 /** 501 - * __create_missing_ancestors - create place holders for missing ancestores 466 + * __create_missing_ancestors - create place holders for missing ancestors 502 467 * @ns: namespace to lookup profile in (NOT NULL) 503 468 * @hname: hierarchical profile name to find parent of (NOT NULL) 504 469 * @gfp: type of allocation. ··· 656 621 /* TODO: ideally we should inherit abi from parent */ 657 622 profile->label.flags |= FLAG_NULL; 658 623 profile->attach.xmatch = aa_get_pdb(nullpdb); 659 - rules = list_first_entry(&profile->rules, typeof(*rules), list); 624 + rules = profile->label.rules[0]; 660 625 rules->file = aa_get_pdb(nullpdb); 661 626 rules->policy = aa_get_pdb(nullpdb); 627 + aa_compute_profile_mediates(profile); 662 628 663 629 if (parent) { 664 630 profile->path_flags = parent->path_flags; 665 - 631 + /* override/inherit what is mediated from parent */ 632 + profile->label.mediates = parent->label.mediates; 666 633 /* released on free_profile */ 667 634 rcu_assign_pointer(profile->parent, aa_get_profile(parent)); 668 635 profile->ns = aa_get_ns(parent->ns); ··· 870 833 bool capable = policy_ns_capable(subj_cred, label, user_ns, 871 834 CAP_MAC_ADMIN) == 0; 872 835 873 - AA_DEBUG("cap_mac_admin? %d\n", capable); 874 - AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); 836 + AA_DEBUG(DEBUG_POLICY, "cap_mac_admin? %d\n", capable); 837 + AA_DEBUG(DEBUG_POLICY, "policy locked? %d\n", aa_g_lock_policy); 875 838 876 839 return aa_policy_view_capable(subj_cred, label, ns) && capable && 877 840 !aa_g_lock_policy; ··· 880 843 bool aa_current_policy_view_capable(struct aa_ns *ns) 881 844 { 882 845 struct aa_label *label; 883 - bool res; 846 + bool needput, res; 884 847 885 - label = __begin_current_label_crit_section(); 848 + label = __begin_current_label_crit_section(&needput); 886 849 res = aa_policy_view_capable(current_cred(), label, ns); 887 - __end_current_label_crit_section(label); 850 + __end_current_label_crit_section(label, needput); 888 851 889 852 return res; 890 853 } ··· 892 855 bool aa_current_policy_admin_capable(struct aa_ns *ns) 893 856 { 894 857 struct aa_label *label; 895 - bool res; 858 + bool needput, res; 896 859 897 - label = __begin_current_label_crit_section(); 860 + label = __begin_current_label_crit_section(&needput); 898 861 res = aa_policy_admin_capable(current_cred(), label, ns); 899 - __end_current_label_crit_section(label); 862 + __end_current_label_crit_section(label, needput); 900 863 901 864 return res; 902 865 } ··· 1105 1068 goto out; 1106 1069 1107 1070 /* ensure that profiles are all for the same ns 1108 - * TODO: update locking to remove this constaint. All profiles in 1071 + * TODO: update locking to remove this constraint. All profiles in 1109 1072 * the load set must succeed as a set or the load will 1110 1073 * fail. Sort ent list and take ns locks in hierarchy order 1111 1074 */
+3 -3
security/apparmor/policy_compat.c
··· 286 286 287 287 AA_BUG(!dfa); 288 288 289 - for (state = 0; state < state_count; state++) 289 + for (state = 0; state < state_count; state++) { 290 290 ACCEPT_TABLE(dfa)[state] = state * factor; 291 - kvfree(dfa->tables[YYTD_ID_ACCEPT2]); 292 - dfa->tables[YYTD_ID_ACCEPT2] = NULL; 291 + ACCEPT_TABLE2(dfa)[state] = factor > 1 ? ACCEPT_FLAG_OWNER : 0; 292 + } 293 293 } 294 294 295 295 /* TODO: merge different dfa mappings into single map_policy fn */
+1 -1
security/apparmor/policy_ns.c
··· 107 107 struct aa_ns *ns; 108 108 109 109 ns = kzalloc(sizeof(*ns), GFP_KERNEL); 110 - AA_DEBUG("%s(%p)\n", __func__, ns); 110 + AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, ns); 111 111 if (!ns) 112 112 return NULL; 113 113 if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL))
+55 -12
security/apparmor/policy_unpack.c
··· 29 29 #include "include/policy.h" 30 30 #include "include/policy_unpack.h" 31 31 #include "include/policy_compat.h" 32 + #include "include/signal.h" 32 33 33 34 /* audit callback for unpack fields */ 34 35 static void audit_cb(struct audit_buffer *ab, void *va) ··· 599 598 fail: 600 599 if (rules->secmark) { 601 600 for (i = 0; i < size; i++) 602 - kfree(rules->secmark[i].label); 603 - kfree(rules->secmark); 601 + kfree_sensitive(rules->secmark[i].label); 602 + kfree_sensitive(rules->secmark); 604 603 rules->secmark_count = 0; 605 604 rules->secmark = NULL; 606 605 } ··· 717 716 void *pos = e->pos; 718 717 int i, flags, error = -EPROTO; 719 718 ssize_t size; 719 + u32 version = 0; 720 720 721 721 pdb = aa_alloc_pdb(GFP_KERNEL); 722 722 if (!pdb) ··· 735 733 if (pdb->perms) { 736 734 /* perms table present accept is index */ 737 735 flags = TO_ACCEPT1_FLAG(YYTD_DATA32); 736 + if (aa_unpack_u32(e, &version, "permsv") && version > 2) 737 + /* accept2 used for dfa flags */ 738 + flags |= TO_ACCEPT2_FLAG(YYTD_DATA32); 738 739 } else { 739 740 /* packed perms in accept1 and accept2 */ 740 741 flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | ··· 775 770 } 776 771 } 777 772 773 + /* accept2 is in some cases being allocated, even with perms */ 774 + if (pdb->perms && !pdb->dfa->tables[YYTD_ID_ACCEPT2]) { 775 + /* add dfa flags table missing in v2 */ 776 + u32 noents = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_lolen; 777 + u16 tdflags = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_flags; 778 + size_t tsize = table_size(noents, tdflags); 779 + 780 + pdb->dfa->tables[YYTD_ID_ACCEPT2] = kvzalloc(tsize, GFP_KERNEL); 781 + if (!pdb->dfa->tables[YYTD_ID_ACCEPT2]) { 782 + *info = "failed to alloc dfa flags table"; 783 + goto out; 784 + } 785 + pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_lolen = noents; 786 + pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_flags = tdflags; 787 + } 778 788 /* 779 789 * Unfortunately due to a bug in earlier userspaces, a 780 790 * transition table may be present even when the dfa is ··· 803 783 if (!pdb->dfa && pdb->trans.table) 804 784 aa_free_str_table(&pdb->trans); 805 785 806 - /* TODO: move compat mapping here, requires dfa merging first */ 807 - /* TODO: move verify here, it has to be done after compat mappings */ 808 - 786 + /* TODO: 787 + * - move compat mapping here, requires dfa merging first 788 + * - move verify here, it has to be done after compat mappings 789 + * - move free of unneeded trans table here, has to be done 790 + * after perm mapping. 791 + */ 792 + out: 809 793 *policy = pdb; 810 794 return 0; 811 795 ··· 886 862 error = -ENOMEM; 887 863 goto fail; 888 864 } 889 - rules = list_first_entry(&profile->rules, typeof(*rules), list); 865 + rules = profile->label.rules[0]; 890 866 891 867 /* profile renaming is optional */ 892 868 (void) aa_unpack_str(e, &profile->rename, "rename"); ··· 922 898 (void) aa_unpack_strdup(e, &disconnected, "disconnected"); 923 899 profile->disconnected = disconnected; 924 900 901 + /* optional */ 902 + (void) aa_unpack_u32(e, &profile->signal, "kill"); 903 + if (profile->signal < 1 || profile->signal > MAXMAPPED_SIG) { 904 + info = "profile kill.signal invalid value"; 905 + goto fail; 906 + } 925 907 /* per profile debug flags (complain, audit) */ 926 908 if (!aa_unpack_nameX(e, AA_STRUCT, "flags")) { 927 909 info = "profile missing flags"; ··· 1131 1101 goto fail; 1132 1102 } 1133 1103 1104 + aa_compute_profile_mediates(profile); 1105 + 1134 1106 return profile; 1135 1107 1136 1108 fail: ··· 1247 1215 static bool verify_perms(struct aa_policydb *pdb) 1248 1216 { 1249 1217 int i; 1218 + int xidx, xmax = -1; 1250 1219 1251 1220 for (i = 0; i < pdb->size; i++) { 1252 1221 if (!verify_perm(&pdb->perms[i])) 1253 1222 return false; 1254 1223 /* verify indexes into str table */ 1255 - if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE && 1256 - (pdb->perms[i].xindex & AA_X_INDEX_MASK) >= pdb->trans.size) 1257 - return false; 1224 + if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE) { 1225 + xidx = pdb->perms[i].xindex & AA_X_INDEX_MASK; 1226 + if (xidx >= pdb->trans.size) 1227 + return false; 1228 + if (xmax < xidx) 1229 + xmax = xidx; 1230 + } 1258 1231 if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->trans.size) 1259 1232 return false; 1260 1233 if (pdb->perms[i].label && 1261 1234 pdb->perms[i].label >= pdb->trans.size) 1262 1235 return false; 1263 1236 } 1264 - 1237 + /* deal with incorrectly constructed string tables */ 1238 + if (xmax == -1) { 1239 + aa_free_str_table(&pdb->trans); 1240 + } else if (pdb->trans.size > xmax + 1) { 1241 + if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL)) 1242 + return false; 1243 + } 1265 1244 return true; 1266 1245 } 1267 1246 ··· 1286 1243 */ 1287 1244 static int verify_profile(struct aa_profile *profile) 1288 1245 { 1289 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 1290 - typeof(*rules), list); 1246 + struct aa_ruleset *rules = profile->label.rules[0]; 1247 + 1291 1248 if (!rules) 1292 1249 return 0; 1293 1250
+4 -2
security/apparmor/policy_unpack_test.c
··· 9 9 #include "include/policy.h" 10 10 #include "include/policy_unpack.h" 11 11 12 + #include <linux/unaligned.h> 13 + 12 14 #define TEST_STRING_NAME "TEST_STRING" 13 15 #define TEST_STRING_DATA "testing" 14 16 #define TEST_STRING_BUF_OFFSET \ ··· 82 80 *(buf + 1) = strlen(TEST_U32_NAME) + 1; 83 81 strscpy(buf + 3, TEST_U32_NAME, e->end - (void *)(buf + 3)); 84 82 *(buf + 3 + strlen(TEST_U32_NAME) + 1) = AA_U32; 85 - *((__le32 *)(buf + 3 + strlen(TEST_U32_NAME) + 2)) = cpu_to_le32(TEST_U32_DATA); 83 + put_unaligned_le32(TEST_U32_DATA, buf + 3 + strlen(TEST_U32_NAME) + 2); 86 84 87 85 buf = e->start + TEST_NAMED_U64_BUF_OFFSET; 88 86 *buf = AA_NAME; ··· 105 103 *(buf + 1) = strlen(TEST_ARRAY_NAME) + 1; 106 104 strscpy(buf + 3, TEST_ARRAY_NAME, e->end - (void *)(buf + 3)); 107 105 *(buf + 3 + strlen(TEST_ARRAY_NAME) + 1) = AA_ARRAY; 108 - *((__le16 *)(buf + 3 + strlen(TEST_ARRAY_NAME) + 2)) = cpu_to_le16(TEST_ARRAY_SIZE); 106 + put_unaligned_le16(TEST_ARRAY_SIZE, buf + 3 + strlen(TEST_ARRAY_NAME) + 2); 109 107 110 108 return e; 111 109 }
+4 -2
security/apparmor/procattr.c
··· 125 125 for (count = 0; (hat < end) && count < 16; ++count) { 126 126 char *next = hat + strlen(hat) + 1; 127 127 hats[count] = hat; 128 - AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" 128 + AA_DEBUG(DEBUG_DOMAIN, 129 + "%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" 129 130 , __func__, current->pid, token, count, hat); 130 131 hat = next; 131 132 } 132 133 } else 133 - AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", 134 + AA_DEBUG(DEBUG_DOMAIN, 135 + "%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", 134 136 __func__, current->pid, token, count, "<NULL>"); 135 137 136 138 return aa_change_hat(hats, count, token, flags);
+3 -8
security/apparmor/resource.c
··· 89 89 struct aa_profile *profile, unsigned int resource, 90 90 struct rlimit *new_rlim) 91 91 { 92 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 93 - typeof(*rules), list); 92 + struct aa_ruleset *rules = profile->label.rules[0]; 94 93 int e = 0; 95 94 96 95 if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max > ··· 164 165 * to the lesser of the tasks hard limit and the init tasks soft limit 165 166 */ 166 167 label_for_each_confined(i, old_l, old) { 167 - struct aa_ruleset *rules = list_first_entry(&old->rules, 168 - typeof(*rules), 169 - list); 168 + struct aa_ruleset *rules = old->label.rules[0]; 170 169 if (rules->rlimits.mask) { 171 170 int j; 172 171 ··· 182 185 183 186 /* set any new hard limits as dictated by the new profile */ 184 187 label_for_each_confined(i, new_l, new) { 185 - struct aa_ruleset *rules = list_first_entry(&new->rules, 186 - typeof(*rules), 187 - list); 188 + struct aa_ruleset *rules = new->label.rules[0]; 188 189 int j; 189 190 190 191 if (!rules->rlimits.mask)
+4 -7
security/apparmor/task.c
··· 228 228 struct aa_label *peer, u32 request, 229 229 struct apparmor_audit_data *ad) 230 230 { 231 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 232 - typeof(*rules), list); 231 + struct aa_ruleset *rules = profile->label.rules[0]; 233 232 struct aa_perms perms = { }; 234 233 235 234 ad->subj_cred = cred; ··· 245 246 struct apparmor_audit_data *ad) 246 247 { 247 248 if (profile_unconfined(tracee) || unconfined(tracer) || 248 - !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE)) 249 + !label_mediates(&tracee->label, AA_CLASS_PTRACE)) 249 250 return 0; 250 251 251 252 return profile_ptrace_perm(cred, tracee, tracer, request, ad); ··· 259 260 if (profile_unconfined(tracer)) 260 261 return 0; 261 262 262 - if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE)) 263 + if (label_mediates(&tracer->label, AA_CLASS_PTRACE)) 263 264 return profile_ptrace_perm(cred, tracer, tracee, request, ad); 264 265 265 266 /* profile uses the old style capability check for ptrace */ ··· 323 324 ad->request = request; 324 325 325 326 if (!profile_unconfined(profile)) { 326 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 327 - typeof(*rules), 328 - list); 327 + struct aa_ruleset *rules = profile->label.rules[0]; 329 328 aa_state_t state; 330 329 331 330 state = RULE_MEDIATES(rules, ad->class);
+1 -1
tools/accounting/Makefile
··· 2 2 CC := $(CROSS_COMPILE)gcc 3 3 CFLAGS := -I../../usr/include 4 4 5 - PROGS := getdelays procacct 5 + PROGS := getdelays procacct delaytop 6 6 7 7 all: $(PROGS) 8 8
+862
tools/accounting/delaytop.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * delaytop.c - system-wide delay monitoring tool. 4 + * 5 + * This tool provides real-time monitoring and statistics of 6 + * system, container, and task-level delays, including CPU, 7 + * memory, IO, and IRQ. It supports both interactive (top-like), 8 + * and can output delay information for the whole system, specific 9 + * containers (cgroups), or individual tasks (PIDs). 10 + * 11 + * Key features: 12 + * - Collects per-task delay accounting statistics via taskstats. 13 + * - Collects system-wide PSI information. 14 + * - Supports sorting, filtering. 15 + * - Supports both interactive (screen refresh). 16 + * 17 + * Copyright (C) Fan Yu, ZTE Corp. 2025 18 + * Copyright (C) Wang Yaxin, ZTE Corp. 2025 19 + * 20 + * Compile with 21 + * gcc -I/usr/src/linux/include delaytop.c -o delaytop 22 + */ 23 + 24 + #include <stdio.h> 25 + #include <stdlib.h> 26 + #include <string.h> 27 + #include <errno.h> 28 + #include <unistd.h> 29 + #include <fcntl.h> 30 + #include <getopt.h> 31 + #include <signal.h> 32 + #include <time.h> 33 + #include <dirent.h> 34 + #include <ctype.h> 35 + #include <stdbool.h> 36 + #include <sys/types.h> 37 + #include <sys/stat.h> 38 + #include <sys/socket.h> 39 + #include <sys/select.h> 40 + #include <termios.h> 41 + #include <limits.h> 42 + #include <linux/genetlink.h> 43 + #include <linux/taskstats.h> 44 + #include <linux/cgroupstats.h> 45 + 46 + #define PSI_CPU_SOME "/proc/pressure/cpu" 47 + #define PSI_CPU_FULL "/proc/pressure/cpu" 48 + #define PSI_MEMORY_SOME "/proc/pressure/memory" 49 + #define PSI_MEMORY_FULL "/proc/pressure/memory" 50 + #define PSI_IO_SOME "/proc/pressure/io" 51 + #define PSI_IO_FULL "/proc/pressure/io" 52 + #define PSI_IRQ_FULL "/proc/pressure/irq" 53 + 54 + #define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len))) 55 + #define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN)) 56 + #define NLA_PAYLOAD(len) (len - NLA_HDRLEN) 57 + 58 + #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) 59 + #define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN) 60 + 61 + #define TASK_COMM_LEN 16 62 + #define MAX_MSG_SIZE 1024 63 + #define MAX_TASKS 1000 64 + #define SET_TASK_STAT(task_count, field) tasks[task_count].field = stats.field 65 + #define BOOL_FPRINT(stream, fmt, ...) \ 66 + ({ \ 67 + int ret = fprintf(stream, fmt, ##__VA_ARGS__); \ 68 + ret >= 0; \ 69 + }) 70 + #define PSI_LINE_FORMAT "%-12s %6.1f%%/%6.1f%%/%6.1f%%/%8llu(ms)\n" 71 + 72 + /* Program settings structure */ 73 + struct config { 74 + int delay; /* Update interval in seconds */ 75 + int iterations; /* Number of iterations, 0 == infinite */ 76 + int max_processes; /* Maximum number of processes to show */ 77 + char sort_field; /* Field to sort by */ 78 + int output_one_time; /* Output once and exit */ 79 + int monitor_pid; /* Monitor specific PID */ 80 + char *container_path; /* Path to container cgroup */ 81 + }; 82 + 83 + /* PSI statistics structure */ 84 + struct psi_stats { 85 + double cpu_some_avg10, cpu_some_avg60, cpu_some_avg300; 86 + unsigned long long cpu_some_total; 87 + double cpu_full_avg10, cpu_full_avg60, cpu_full_avg300; 88 + unsigned long long cpu_full_total; 89 + double memory_some_avg10, memory_some_avg60, memory_some_avg300; 90 + unsigned long long memory_some_total; 91 + double memory_full_avg10, memory_full_avg60, memory_full_avg300; 92 + unsigned long long memory_full_total; 93 + double io_some_avg10, io_some_avg60, io_some_avg300; 94 + unsigned long long io_some_total; 95 + double io_full_avg10, io_full_avg60, io_full_avg300; 96 + unsigned long long io_full_total; 97 + double irq_full_avg10, irq_full_avg60, irq_full_avg300; 98 + unsigned long long irq_full_total; 99 + }; 100 + 101 + /* Task delay information structure */ 102 + struct task_info { 103 + int pid; 104 + int tgid; 105 + char command[TASK_COMM_LEN]; 106 + unsigned long long cpu_count; 107 + unsigned long long cpu_delay_total; 108 + unsigned long long blkio_count; 109 + unsigned long long blkio_delay_total; 110 + unsigned long long swapin_count; 111 + unsigned long long swapin_delay_total; 112 + unsigned long long freepages_count; 113 + unsigned long long freepages_delay_total; 114 + unsigned long long thrashing_count; 115 + unsigned long long thrashing_delay_total; 116 + unsigned long long compact_count; 117 + unsigned long long compact_delay_total; 118 + unsigned long long wpcopy_count; 119 + unsigned long long wpcopy_delay_total; 120 + unsigned long long irq_count; 121 + unsigned long long irq_delay_total; 122 + }; 123 + 124 + /* Container statistics structure */ 125 + struct container_stats { 126 + int nr_sleeping; /* Number of sleeping processes */ 127 + int nr_running; /* Number of running processes */ 128 + int nr_stopped; /* Number of stopped processes */ 129 + int nr_uninterruptible; /* Number of uninterruptible processes */ 130 + int nr_io_wait; /* Number of processes in IO wait */ 131 + }; 132 + 133 + /* Global variables */ 134 + static struct config cfg; 135 + static struct psi_stats psi; 136 + static struct task_info tasks[MAX_TASKS]; 137 + static int task_count; 138 + static int running = 1; 139 + static struct container_stats container_stats; 140 + 141 + /* Netlink socket variables */ 142 + static int nl_sd = -1; 143 + static int family_id; 144 + 145 + /* Set terminal to non-canonical mode for q-to-quit */ 146 + static struct termios orig_termios; 147 + static void enable_raw_mode(void) 148 + { 149 + struct termios raw; 150 + 151 + tcgetattr(STDIN_FILENO, &orig_termios); 152 + raw = orig_termios; 153 + raw.c_lflag &= ~(ICANON | ECHO); 154 + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); 155 + } 156 + static void disable_raw_mode(void) 157 + { 158 + tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); 159 + } 160 + 161 + /* Display usage information and command line options */ 162 + static void usage(void) 163 + { 164 + printf("Usage: delaytop [Options]\n" 165 + "Options:\n" 166 + " -h, --help Show this help message and exit\n" 167 + " -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n" 168 + " -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n" 169 + " -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n" 170 + " -o, --once Display once and exit\n" 171 + " -p, --pid=PID Monitor only the specified PID\n" 172 + " -C, --container=PATH Monitor the container at specified cgroup path\n"); 173 + exit(0); 174 + } 175 + 176 + /* Parse command line arguments and set configuration */ 177 + static void parse_args(int argc, char **argv) 178 + { 179 + int c; 180 + struct option long_options[] = { 181 + {"help", no_argument, 0, 'h'}, 182 + {"delay", required_argument, 0, 'd'}, 183 + {"iterations", required_argument, 0, 'n'}, 184 + {"pid", required_argument, 0, 'p'}, 185 + {"once", no_argument, 0, 'o'}, 186 + {"processes", required_argument, 0, 'P'}, 187 + {"container", required_argument, 0, 'C'}, 188 + {0, 0, 0, 0} 189 + }; 190 + 191 + /* Set defaults */ 192 + cfg.delay = 2; 193 + cfg.iterations = 0; 194 + cfg.max_processes = 20; 195 + cfg.sort_field = 'c'; /* Default sort by CPU delay */ 196 + cfg.output_one_time = 0; 197 + cfg.monitor_pid = 0; /* 0 means monitor all PIDs */ 198 + cfg.container_path = NULL; 199 + 200 + while (1) { 201 + int option_index = 0; 202 + 203 + c = getopt_long(argc, argv, "hd:n:p:oP:C:", long_options, &option_index); 204 + if (c == -1) 205 + break; 206 + 207 + switch (c) { 208 + case 'h': 209 + usage(); 210 + break; 211 + case 'd': 212 + cfg.delay = atoi(optarg); 213 + if (cfg.delay < 1) { 214 + fprintf(stderr, "Error: delay must be >= 1.\n"); 215 + exit(1); 216 + } 217 + break; 218 + case 'n': 219 + cfg.iterations = atoi(optarg); 220 + if (cfg.iterations < 0) { 221 + fprintf(stderr, "Error: iterations must be >= 0.\n"); 222 + exit(1); 223 + } 224 + break; 225 + case 'p': 226 + cfg.monitor_pid = atoi(optarg); 227 + if (cfg.monitor_pid < 1) { 228 + fprintf(stderr, "Error: pid must be >= 1.\n"); 229 + exit(1); 230 + } 231 + break; 232 + case 'o': 233 + cfg.output_one_time = 1; 234 + break; 235 + case 'P': 236 + cfg.max_processes = atoi(optarg); 237 + if (cfg.max_processes < 1) { 238 + fprintf(stderr, "Error: processes must be >= 1.\n"); 239 + exit(1); 240 + } 241 + if (cfg.max_processes > MAX_TASKS) { 242 + fprintf(stderr, "Warning: processes capped to %d.\n", 243 + MAX_TASKS); 244 + cfg.max_processes = MAX_TASKS; 245 + } 246 + break; 247 + case 'C': 248 + cfg.container_path = strdup(optarg); 249 + break; 250 + default: 251 + fprintf(stderr, "Try 'delaytop --help' for more information.\n"); 252 + exit(1); 253 + } 254 + } 255 + } 256 + 257 + /* Create a raw netlink socket and bind */ 258 + static int create_nl_socket(void) 259 + { 260 + int fd; 261 + struct sockaddr_nl local; 262 + 263 + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); 264 + if (fd < 0) 265 + return -1; 266 + 267 + memset(&local, 0, sizeof(local)); 268 + local.nl_family = AF_NETLINK; 269 + 270 + if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0) { 271 + fprintf(stderr, "Failed to bind socket when create nl_socket\n"); 272 + close(fd); 273 + return -1; 274 + } 275 + 276 + return fd; 277 + } 278 + 279 + /* Send a command via netlink */ 280 + static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid, 281 + __u8 genl_cmd, __u16 nla_type, 282 + void *nla_data, int nla_len) 283 + { 284 + struct sockaddr_nl nladdr; 285 + struct nlattr *na; 286 + int r, buflen; 287 + char *buf; 288 + 289 + struct { 290 + struct nlmsghdr n; 291 + struct genlmsghdr g; 292 + char buf[MAX_MSG_SIZE]; 293 + } msg; 294 + 295 + msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); 296 + msg.n.nlmsg_type = nlmsg_type; 297 + msg.n.nlmsg_flags = NLM_F_REQUEST; 298 + msg.n.nlmsg_seq = 0; 299 + msg.n.nlmsg_pid = nlmsg_pid; 300 + msg.g.cmd = genl_cmd; 301 + msg.g.version = 0x1; 302 + na = (struct nlattr *) GENLMSG_DATA(&msg); 303 + na->nla_type = nla_type; 304 + na->nla_len = nla_len + NLA_HDRLEN; 305 + memcpy(NLA_DATA(na), nla_data, nla_len); 306 + msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len); 307 + 308 + buf = (char *) &msg; 309 + buflen = msg.n.nlmsg_len; 310 + memset(&nladdr, 0, sizeof(nladdr)); 311 + nladdr.nl_family = AF_NETLINK; 312 + while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr, 313 + sizeof(nladdr))) < buflen) { 314 + if (r > 0) { 315 + buf += r; 316 + buflen -= r; 317 + } else if (errno != EAGAIN) 318 + return -1; 319 + } 320 + return 0; 321 + } 322 + 323 + /* Get family ID for taskstats via netlink */ 324 + static int get_family_id(int sd) 325 + { 326 + struct { 327 + struct nlmsghdr n; 328 + struct genlmsghdr g; 329 + char buf[256]; 330 + } ans; 331 + 332 + int id = 0, rc; 333 + struct nlattr *na; 334 + int rep_len; 335 + char name[100]; 336 + 337 + strncpy(name, TASKSTATS_GENL_NAME, sizeof(name) - 1); 338 + name[sizeof(name) - 1] = '\0'; 339 + rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY, 340 + CTRL_ATTR_FAMILY_NAME, (void *)name, 341 + strlen(TASKSTATS_GENL_NAME)+1); 342 + if (rc < 0) { 343 + fprintf(stderr, "Failed to send cmd for family id\n"); 344 + return 0; 345 + } 346 + 347 + rep_len = recv(sd, &ans, sizeof(ans), 0); 348 + if (ans.n.nlmsg_type == NLMSG_ERROR || 349 + (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len)) { 350 + fprintf(stderr, "Failed to receive response for family id\n"); 351 + return 0; 352 + } 353 + 354 + na = (struct nlattr *) GENLMSG_DATA(&ans); 355 + na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len)); 356 + if (na->nla_type == CTRL_ATTR_FAMILY_ID) 357 + id = *(__u16 *) NLA_DATA(na); 358 + return id; 359 + } 360 + 361 + static void read_psi_stats(void) 362 + { 363 + FILE *fp; 364 + char line[256]; 365 + int ret = 0; 366 + /* Zero all fields */ 367 + memset(&psi, 0, sizeof(psi)); 368 + /* CPU pressure */ 369 + fp = fopen(PSI_CPU_SOME, "r"); 370 + if (fp) { 371 + while (fgets(line, sizeof(line), fp)) { 372 + if (strncmp(line, "some", 4) == 0) { 373 + ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu", 374 + &psi.cpu_some_avg10, &psi.cpu_some_avg60, 375 + &psi.cpu_some_avg300, &psi.cpu_some_total); 376 + if (ret != 4) 377 + fprintf(stderr, "Failed to parse CPU some PSI data\n"); 378 + } else if (strncmp(line, "full", 4) == 0) { 379 + ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu", 380 + &psi.cpu_full_avg10, &psi.cpu_full_avg60, 381 + &psi.cpu_full_avg300, &psi.cpu_full_total); 382 + if (ret != 4) 383 + fprintf(stderr, "Failed to parse CPU full PSI data\n"); 384 + } 385 + } 386 + fclose(fp); 387 + } 388 + /* Memory pressure */ 389 + fp = fopen(PSI_MEMORY_SOME, "r"); 390 + if (fp) { 391 + while (fgets(line, sizeof(line), fp)) { 392 + if (strncmp(line, "some", 4) == 0) { 393 + ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu", 394 + &psi.memory_some_avg10, &psi.memory_some_avg60, 395 + &psi.memory_some_avg300, &psi.memory_some_total); 396 + if (ret != 4) 397 + fprintf(stderr, "Failed to parse Memory some PSI data\n"); 398 + } else if (strncmp(line, "full", 4) == 0) { 399 + ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu", 400 + &psi.memory_full_avg10, &psi.memory_full_avg60, 401 + &psi.memory_full_avg300, &psi.memory_full_total); 402 + } 403 + if (ret != 4) 404 + fprintf(stderr, "Failed to parse Memory full PSI data\n"); 405 + } 406 + fclose(fp); 407 + } 408 + /* IO pressure */ 409 + fp = fopen(PSI_IO_SOME, "r"); 410 + if (fp) { 411 + while (fgets(line, sizeof(line), fp)) { 412 + if (strncmp(line, "some", 4) == 0) { 413 + ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu", 414 + &psi.io_some_avg10, &psi.io_some_avg60, 415 + &psi.io_some_avg300, &psi.io_some_total); 416 + if (ret != 4) 417 + fprintf(stderr, "Failed to parse IO some PSI data\n"); 418 + } else if (strncmp(line, "full", 4) == 0) { 419 + ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu", 420 + &psi.io_full_avg10, &psi.io_full_avg60, 421 + &psi.io_full_avg300, &psi.io_full_total); 422 + if (ret != 4) 423 + fprintf(stderr, "Failed to parse IO full PSI data\n"); 424 + } 425 + } 426 + fclose(fp); 427 + } 428 + /* IRQ pressure (only full) */ 429 + fp = fopen(PSI_IRQ_FULL, "r"); 430 + if (fp) { 431 + while (fgets(line, sizeof(line), fp)) { 432 + if (strncmp(line, "full", 4) == 0) { 433 + ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu", 434 + &psi.irq_full_avg10, &psi.irq_full_avg60, 435 + &psi.irq_full_avg300, &psi.irq_full_total); 436 + if (ret != 4) 437 + fprintf(stderr, "Failed to parse IRQ full PSI data\n"); 438 + } 439 + } 440 + fclose(fp); 441 + } 442 + } 443 + 444 + static int read_comm(int pid, char *comm_buf, size_t buf_size) 445 + { 446 + char path[64]; 447 + int ret = -1; 448 + size_t len; 449 + FILE *fp; 450 + 451 + snprintf(path, sizeof(path), "/proc/%d/comm", pid); 452 + fp = fopen(path, "r"); 453 + if (!fp) { 454 + fprintf(stderr, "Failed to open comm file /proc/%d/comm\n", pid); 455 + return ret; 456 + } 457 + 458 + if (fgets(comm_buf, buf_size, fp)) { 459 + len = strlen(comm_buf); 460 + if (len > 0 && comm_buf[len - 1] == '\n') 461 + comm_buf[len - 1] = '\0'; 462 + ret = 0; 463 + } 464 + 465 + fclose(fp); 466 + 467 + return ret; 468 + } 469 + 470 + static void fetch_and_fill_task_info(int pid, const char *comm) 471 + { 472 + struct { 473 + struct nlmsghdr n; 474 + struct genlmsghdr g; 475 + char buf[MAX_MSG_SIZE]; 476 + } resp; 477 + struct taskstats stats; 478 + struct nlattr *nested; 479 + struct nlattr *na; 480 + int nested_len; 481 + int nl_len; 482 + int rc; 483 + 484 + /* Send request for task stats */ 485 + if (send_cmd(nl_sd, family_id, getpid(), TASKSTATS_CMD_GET, 486 + TASKSTATS_CMD_ATTR_PID, &pid, sizeof(pid)) < 0) { 487 + fprintf(stderr, "Failed to send request for task stats\n"); 488 + return; 489 + } 490 + 491 + /* Receive response */ 492 + rc = recv(nl_sd, &resp, sizeof(resp), 0); 493 + if (rc < 0 || resp.n.nlmsg_type == NLMSG_ERROR) { 494 + fprintf(stderr, "Failed to receive response for task stats\n"); 495 + return; 496 + } 497 + 498 + /* Parse response */ 499 + nl_len = GENLMSG_PAYLOAD(&resp.n); 500 + na = (struct nlattr *) GENLMSG_DATA(&resp); 501 + while (nl_len > 0) { 502 + if (na->nla_type == TASKSTATS_TYPE_AGGR_PID) { 503 + nested = (struct nlattr *) NLA_DATA(na); 504 + nested_len = NLA_PAYLOAD(na->nla_len); 505 + while (nested_len > 0) { 506 + if (nested->nla_type == TASKSTATS_TYPE_STATS) { 507 + memcpy(&stats, NLA_DATA(nested), sizeof(stats)); 508 + if (task_count < MAX_TASKS) { 509 + tasks[task_count].pid = pid; 510 + tasks[task_count].tgid = pid; 511 + strncpy(tasks[task_count].command, comm, 512 + TASK_COMM_LEN - 1); 513 + tasks[task_count].command[TASK_COMM_LEN - 1] = '\0'; 514 + SET_TASK_STAT(task_count, cpu_count); 515 + SET_TASK_STAT(task_count, cpu_delay_total); 516 + SET_TASK_STAT(task_count, blkio_count); 517 + SET_TASK_STAT(task_count, blkio_delay_total); 518 + SET_TASK_STAT(task_count, swapin_count); 519 + SET_TASK_STAT(task_count, swapin_delay_total); 520 + SET_TASK_STAT(task_count, freepages_count); 521 + SET_TASK_STAT(task_count, freepages_delay_total); 522 + SET_TASK_STAT(task_count, thrashing_count); 523 + SET_TASK_STAT(task_count, thrashing_delay_total); 524 + SET_TASK_STAT(task_count, compact_count); 525 + SET_TASK_STAT(task_count, compact_delay_total); 526 + SET_TASK_STAT(task_count, wpcopy_count); 527 + SET_TASK_STAT(task_count, wpcopy_delay_total); 528 + SET_TASK_STAT(task_count, irq_count); 529 + SET_TASK_STAT(task_count, irq_delay_total); 530 + task_count++; 531 + } 532 + break; 533 + } 534 + nested_len -= NLA_ALIGN(nested->nla_len); 535 + nested = NLA_NEXT(nested); 536 + } 537 + } 538 + nl_len -= NLA_ALIGN(na->nla_len); 539 + na = NLA_NEXT(na); 540 + } 541 + return; 542 + } 543 + 544 + static void get_task_delays(void) 545 + { 546 + char comm[TASK_COMM_LEN]; 547 + struct dirent *entry; 548 + DIR *dir; 549 + int pid; 550 + 551 + task_count = 0; 552 + if (cfg.monitor_pid > 0) { 553 + if (read_comm(cfg.monitor_pid, comm, sizeof(comm)) == 0) 554 + fetch_and_fill_task_info(cfg.monitor_pid, comm); 555 + return; 556 + } 557 + 558 + dir = opendir("/proc"); 559 + if (!dir) { 560 + fprintf(stderr, "Error opening /proc directory\n"); 561 + return; 562 + } 563 + 564 + while ((entry = readdir(dir)) != NULL && task_count < MAX_TASKS) { 565 + if (!isdigit(entry->d_name[0])) 566 + continue; 567 + pid = atoi(entry->d_name); 568 + if (pid == 0) 569 + continue; 570 + if (read_comm(pid, comm, sizeof(comm)) != 0) 571 + continue; 572 + fetch_and_fill_task_info(pid, comm); 573 + } 574 + closedir(dir); 575 + } 576 + 577 + /* Calculate average delay in milliseconds */ 578 + static double average_ms(unsigned long long total, unsigned long long count) 579 + { 580 + if (count == 0) 581 + return 0; 582 + return (double)total / 1000000.0 / count; 583 + } 584 + 585 + /* Comparison function for sorting tasks */ 586 + static int compare_tasks(const void *a, const void *b) 587 + { 588 + const struct task_info *t1 = (const struct task_info *)a; 589 + const struct task_info *t2 = (const struct task_info *)b; 590 + double avg1, avg2; 591 + 592 + switch (cfg.sort_field) { 593 + case 'c': /* CPU */ 594 + avg1 = average_ms(t1->cpu_delay_total, t1->cpu_count); 595 + avg2 = average_ms(t2->cpu_delay_total, t2->cpu_count); 596 + if (avg1 != avg2) 597 + return avg2 > avg1 ? 1 : -1; 598 + return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1; 599 + 600 + default: 601 + return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1; 602 + } 603 + } 604 + 605 + /* Sort tasks by selected field */ 606 + static void sort_tasks(void) 607 + { 608 + if (task_count > 0) 609 + qsort(tasks, task_count, sizeof(struct task_info), compare_tasks); 610 + } 611 + 612 + /* Get container statistics via cgroupstats */ 613 + static void get_container_stats(void) 614 + { 615 + int rc, cfd; 616 + struct { 617 + struct nlmsghdr n; 618 + struct genlmsghdr g; 619 + char buf[MAX_MSG_SIZE]; 620 + } req, resp; 621 + struct nlattr *na; 622 + int nl_len; 623 + struct cgroupstats stats; 624 + 625 + /* Check if container path is set */ 626 + if (!cfg.container_path) 627 + return; 628 + 629 + /* Open container cgroup */ 630 + cfd = open(cfg.container_path, O_RDONLY); 631 + if (cfd < 0) { 632 + fprintf(stderr, "Error opening container path: %s\n", cfg.container_path); 633 + return; 634 + } 635 + 636 + /* Send request for container stats */ 637 + if (send_cmd(nl_sd, family_id, getpid(), CGROUPSTATS_CMD_GET, 638 + CGROUPSTATS_CMD_ATTR_FD, &cfd, sizeof(__u32)) < 0) { 639 + fprintf(stderr, "Failed to send request for container stats\n"); 640 + close(cfd); 641 + return; 642 + } 643 + 644 + /* Receive response */ 645 + rc = recv(nl_sd, &resp, sizeof(resp), 0); 646 + if (rc < 0 || resp.n.nlmsg_type == NLMSG_ERROR) { 647 + fprintf(stderr, "Failed to receive response for container stats\n"); 648 + close(cfd); 649 + return; 650 + } 651 + 652 + /* Parse response */ 653 + nl_len = GENLMSG_PAYLOAD(&resp.n); 654 + na = (struct nlattr *) GENLMSG_DATA(&resp); 655 + while (nl_len > 0) { 656 + if (na->nla_type == CGROUPSTATS_TYPE_CGROUP_STATS) { 657 + /* Get the cgroupstats structure */ 658 + memcpy(&stats, NLA_DATA(na), sizeof(stats)); 659 + 660 + /* Fill container stats */ 661 + container_stats.nr_sleeping = stats.nr_sleeping; 662 + container_stats.nr_running = stats.nr_running; 663 + container_stats.nr_stopped = stats.nr_stopped; 664 + container_stats.nr_uninterruptible = stats.nr_uninterruptible; 665 + container_stats.nr_io_wait = stats.nr_io_wait; 666 + break; 667 + } 668 + nl_len -= NLA_ALIGN(na->nla_len); 669 + na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len)); 670 + } 671 + 672 + close(cfd); 673 + } 674 + 675 + /* Display results to stdout or log file */ 676 + static void display_results(void) 677 + { 678 + time_t now = time(NULL); 679 + struct tm *tm_now = localtime(&now); 680 + FILE *out = stdout; 681 + char timestamp[32]; 682 + bool suc = true; 683 + int i, count; 684 + 685 + /* Clear terminal screen */ 686 + suc &= BOOL_FPRINT(out, "\033[H\033[J"); 687 + 688 + /* PSI output (one-line, no cat style) */ 689 + suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60/avg300/total)\n"); 690 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 691 + "CPU some:", 692 + psi.cpu_some_avg10, 693 + psi.cpu_some_avg60, 694 + psi.cpu_some_avg300, 695 + psi.cpu_some_total / 1000); 696 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 697 + "CPU full:", 698 + psi.cpu_full_avg10, 699 + psi.cpu_full_avg60, 700 + psi.cpu_full_avg300, 701 + psi.cpu_full_total / 1000); 702 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 703 + "Memory full:", 704 + psi.memory_full_avg10, 705 + psi.memory_full_avg60, 706 + psi.memory_full_avg300, 707 + psi.memory_full_total / 1000); 708 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 709 + "Memory some:", 710 + psi.memory_some_avg10, 711 + psi.memory_some_avg60, 712 + psi.memory_some_avg300, 713 + psi.memory_some_total / 1000); 714 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 715 + "IO full:", 716 + psi.io_full_avg10, 717 + psi.io_full_avg60, 718 + psi.io_full_avg300, 719 + psi.io_full_total / 1000); 720 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 721 + "IO some:", 722 + psi.io_some_avg10, 723 + psi.io_some_avg60, 724 + psi.io_some_avg300, 725 + psi.io_some_total / 1000); 726 + suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT, 727 + "IRQ full:", 728 + psi.irq_full_avg10, 729 + psi.irq_full_avg60, 730 + psi.irq_full_avg300, 731 + psi.irq_full_total / 1000); 732 + 733 + if (cfg.container_path) { 734 + suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path); 735 + suc &= BOOL_FPRINT(out, "Processes: running=%d, sleeping=%d, ", 736 + container_stats.nr_running, container_stats.nr_sleeping); 737 + suc &= BOOL_FPRINT(out, "stopped=%d, uninterruptible=%d, io_wait=%d\n\n", 738 + container_stats.nr_stopped, container_stats.nr_uninterruptible, 739 + container_stats.nr_io_wait); 740 + } 741 + suc &= BOOL_FPRINT(out, "Top %d processes (sorted by CPU delay):\n", 742 + cfg.max_processes); 743 + suc &= BOOL_FPRINT(out, "%5s %5s %-17s", "PID", "TGID", "COMMAND"); 744 + suc &= BOOL_FPRINT(out, "%7s %7s %7s %7s %7s %7s %7s %7s\n", 745 + "CPU(ms)", "IO(ms)", "SWAP(ms)", "RCL(ms)", 746 + "THR(ms)", "CMP(ms)", "WP(ms)", "IRQ(ms)"); 747 + 748 + suc &= BOOL_FPRINT(out, "-----------------------------------------------"); 749 + suc &= BOOL_FPRINT(out, "----------------------------------------------\n"); 750 + count = task_count < cfg.max_processes ? task_count : cfg.max_processes; 751 + 752 + for (i = 0; i < count; i++) { 753 + suc &= BOOL_FPRINT(out, "%5d %5d %-15s", 754 + tasks[i].pid, tasks[i].tgid, tasks[i].command); 755 + suc &= BOOL_FPRINT(out, "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", 756 + average_ms(tasks[i].cpu_delay_total, tasks[i].cpu_count), 757 + average_ms(tasks[i].blkio_delay_total, tasks[i].blkio_count), 758 + average_ms(tasks[i].swapin_delay_total, tasks[i].swapin_count), 759 + average_ms(tasks[i].freepages_delay_total, tasks[i].freepages_count), 760 + average_ms(tasks[i].thrashing_delay_total, tasks[i].thrashing_count), 761 + average_ms(tasks[i].compact_delay_total, tasks[i].compact_count), 762 + average_ms(tasks[i].wpcopy_delay_total, tasks[i].wpcopy_count), 763 + average_ms(tasks[i].irq_delay_total, tasks[i].irq_count)); 764 + } 765 + 766 + suc &= BOOL_FPRINT(out, "\n"); 767 + 768 + if (!suc) 769 + perror("Error writing to output"); 770 + } 771 + 772 + /* Main function */ 773 + int main(int argc, char **argv) 774 + { 775 + int iterations = 0; 776 + int use_q_quit = 0; 777 + 778 + /* Parse command line arguments */ 779 + parse_args(argc, argv); 780 + 781 + /* Setup netlink socket */ 782 + nl_sd = create_nl_socket(); 783 + if (nl_sd < 0) { 784 + fprintf(stderr, "Error creating netlink socket\n"); 785 + exit(1); 786 + } 787 + 788 + /* Get family ID for taskstats via netlink */ 789 + family_id = get_family_id(nl_sd); 790 + if (!family_id) { 791 + fprintf(stderr, "Error getting taskstats family ID\n"); 792 + close(nl_sd); 793 + exit(1); 794 + } 795 + 796 + if (!cfg.output_one_time) { 797 + use_q_quit = 1; 798 + enable_raw_mode(); 799 + printf("Press 'q' to quit.\n"); 800 + fflush(stdout); 801 + } 802 + 803 + /* Main loop */ 804 + while (running) { 805 + /* Read PSI statistics */ 806 + read_psi_stats(); 807 + 808 + /* Get container stats if container path provided */ 809 + if (cfg.container_path) 810 + get_container_stats(); 811 + 812 + /* Get task delays */ 813 + get_task_delays(); 814 + 815 + /* Sort tasks */ 816 + sort_tasks(); 817 + 818 + /* Display results to stdout or log file */ 819 + display_results(); 820 + 821 + /* Check for iterations */ 822 + if (cfg.iterations > 0 && ++iterations >= cfg.iterations) 823 + break; 824 + 825 + /* Exit if output_one_time is set */ 826 + if (cfg.output_one_time) 827 + break; 828 + 829 + /* Check for 'q' key to quit */ 830 + if (use_q_quit) { 831 + struct timeval tv = {cfg.delay, 0}; 832 + fd_set readfds; 833 + 834 + FD_ZERO(&readfds); 835 + FD_SET(STDIN_FILENO, &readfds); 836 + int r = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv); 837 + 838 + if (r > 0 && FD_ISSET(STDIN_FILENO, &readfds)) { 839 + char ch = 0; 840 + 841 + read(STDIN_FILENO, &ch, 1); 842 + if (ch == 'q' || ch == 'Q') { 843 + running = 0; 844 + break; 845 + } 846 + } 847 + } else { 848 + sleep(cfg.delay); 849 + } 850 + } 851 + 852 + /* Restore terminal mode */ 853 + if (use_q_quit) 854 + disable_raw_mode(); 855 + 856 + /* Cleanup */ 857 + close(nl_sd); 858 + if (cfg.container_path) 859 + free(cfg.container_path); 860 + 861 + return 0; 862 + }
+100 -67
tools/accounting/getdelays.c
··· 194 194 #define average_ms(t, c) (t / 1000000ULL / (c ? c : 1)) 195 195 #define delay_ms(t) (t / 1000000ULL) 196 196 197 + /* 198 + * Version compatibility note: 199 + * Field availability depends on taskstats version (t->version), 200 + * corresponding to TASKSTATS_VERSION in kernel headers 201 + * see include/uapi/linux/taskstats.h 202 + * 203 + * Version feature mapping: 204 + * version >= 11 - supports COMPACT statistics 205 + * version >= 13 - supports WPCOPY statistics 206 + * version >= 14 - supports IRQ statistics 207 + * version >= 16 - supports *_max and *_min delay statistics 208 + * 209 + * Always verify version before accessing version-dependent fields 210 + * to maintain backward compatibility. 211 + */ 212 + #define PRINT_CPU_DELAY(version, t) \ 213 + do { \ 214 + if (version >= 16) { \ 215 + printf("%-10s%15s%15s%15s%15s%15s%15s%15s\n", \ 216 + "CPU", "count", "real total", "virtual total", \ 217 + "delay total", "delay average", "delay max", "delay min"); \ 218 + printf(" %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n", \ 219 + (unsigned long long)(t)->cpu_count, \ 220 + (unsigned long long)(t)->cpu_run_real_total, \ 221 + (unsigned long long)(t)->cpu_run_virtual_total, \ 222 + (unsigned long long)(t)->cpu_delay_total, \ 223 + average_ms((double)(t)->cpu_delay_total, (t)->cpu_count), \ 224 + delay_ms((double)(t)->cpu_delay_max), \ 225 + delay_ms((double)(t)->cpu_delay_min)); \ 226 + } else { \ 227 + printf("%-10s%15s%15s%15s%15s%15s\n", \ 228 + "CPU", "count", "real total", "virtual total", \ 229 + "delay total", "delay average"); \ 230 + printf(" %15llu%15llu%15llu%15llu%15.3fms\n", \ 231 + (unsigned long long)(t)->cpu_count, \ 232 + (unsigned long long)(t)->cpu_run_real_total, \ 233 + (unsigned long long)(t)->cpu_run_virtual_total, \ 234 + (unsigned long long)(t)->cpu_delay_total, \ 235 + average_ms((double)(t)->cpu_delay_total, (t)->cpu_count)); \ 236 + } \ 237 + } while (0) 238 + #define PRINT_FILED_DELAY(name, version, t, count, total, max, min) \ 239 + do { \ 240 + if (version >= 16) { \ 241 + printf("%-10s%15s%15s%15s%15s%15s\n", \ 242 + name, "count", "delay total", "delay average", \ 243 + "delay max", "delay min"); \ 244 + printf(" %15llu%15llu%15.3fms%13.6fms%13.6fms\n", \ 245 + (unsigned long long)(t)->count, \ 246 + (unsigned long long)(t)->total, \ 247 + average_ms((double)(t)->total, (t)->count), \ 248 + delay_ms((double)(t)->max), \ 249 + delay_ms((double)(t)->min)); \ 250 + } else { \ 251 + printf("%-10s%15s%15s%15s\n", \ 252 + name, "count", "delay total", "delay average"); \ 253 + printf(" %15llu%15llu%15.3fms\n", \ 254 + (unsigned long long)(t)->count, \ 255 + (unsigned long long)(t)->total, \ 256 + average_ms((double)(t)->total, (t)->count)); \ 257 + } \ 258 + } while (0) 259 + 197 260 static void print_delayacct(struct taskstats *t) 198 261 { 199 - printf("\n\nCPU %15s%15s%15s%15s%15s%15s%15s\n" 200 - " %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n" 201 - "IO %15s%15s%15s%15s%15s\n" 202 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 203 - "SWAP %15s%15s%15s%15s%15s\n" 204 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 205 - "RECLAIM %12s%15s%15s%15s%15s\n" 206 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 207 - "THRASHING%12s%15s%15s%15s%15s\n" 208 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 209 - "COMPACT %12s%15s%15s%15s%15s\n" 210 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 211 - "WPCOPY %12s%15s%15s%15s%15s\n" 212 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 213 - "IRQ %15s%15s%15s%15s%15s\n" 214 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n", 215 - "count", "real total", "virtual total", 216 - "delay total", "delay average", "delay max", "delay min", 217 - (unsigned long long)t->cpu_count, 218 - (unsigned long long)t->cpu_run_real_total, 219 - (unsigned long long)t->cpu_run_virtual_total, 220 - (unsigned long long)t->cpu_delay_total, 221 - average_ms((double)t->cpu_delay_total, t->cpu_count), 222 - delay_ms((double)t->cpu_delay_max), 223 - delay_ms((double)t->cpu_delay_min), 224 - "count", "delay total", "delay average", "delay max", "delay min", 225 - (unsigned long long)t->blkio_count, 226 - (unsigned long long)t->blkio_delay_total, 227 - average_ms((double)t->blkio_delay_total, t->blkio_count), 228 - delay_ms((double)t->blkio_delay_max), 229 - delay_ms((double)t->blkio_delay_min), 230 - "count", "delay total", "delay average", "delay max", "delay min", 231 - (unsigned long long)t->swapin_count, 232 - (unsigned long long)t->swapin_delay_total, 233 - average_ms((double)t->swapin_delay_total, t->swapin_count), 234 - delay_ms((double)t->swapin_delay_max), 235 - delay_ms((double)t->swapin_delay_min), 236 - "count", "delay total", "delay average", "delay max", "delay min", 237 - (unsigned long long)t->freepages_count, 238 - (unsigned long long)t->freepages_delay_total, 239 - average_ms((double)t->freepages_delay_total, t->freepages_count), 240 - delay_ms((double)t->freepages_delay_max), 241 - delay_ms((double)t->freepages_delay_min), 242 - "count", "delay total", "delay average", "delay max", "delay min", 243 - (unsigned long long)t->thrashing_count, 244 - (unsigned long long)t->thrashing_delay_total, 245 - average_ms((double)t->thrashing_delay_total, t->thrashing_count), 246 - delay_ms((double)t->thrashing_delay_max), 247 - delay_ms((double)t->thrashing_delay_min), 248 - "count", "delay total", "delay average", "delay max", "delay min", 249 - (unsigned long long)t->compact_count, 250 - (unsigned long long)t->compact_delay_total, 251 - average_ms((double)t->compact_delay_total, t->compact_count), 252 - delay_ms((double)t->compact_delay_max), 253 - delay_ms((double)t->compact_delay_min), 254 - "count", "delay total", "delay average", "delay max", "delay min", 255 - (unsigned long long)t->wpcopy_count, 256 - (unsigned long long)t->wpcopy_delay_total, 257 - average_ms((double)t->wpcopy_delay_total, t->wpcopy_count), 258 - delay_ms((double)t->wpcopy_delay_max), 259 - delay_ms((double)t->wpcopy_delay_min), 260 - "count", "delay total", "delay average", "delay max", "delay min", 261 - (unsigned long long)t->irq_count, 262 - (unsigned long long)t->irq_delay_total, 263 - average_ms((double)t->irq_delay_total, t->irq_count), 264 - delay_ms((double)t->irq_delay_max), 265 - delay_ms((double)t->irq_delay_min)); 262 + printf("\n\n"); 263 + 264 + PRINT_CPU_DELAY(t->version, t); 265 + 266 + PRINT_FILED_DELAY("IO", t->version, t, 267 + blkio_count, blkio_delay_total, 268 + blkio_delay_max, blkio_delay_min); 269 + 270 + PRINT_FILED_DELAY("SWAP", t->version, t, 271 + swapin_count, swapin_delay_total, 272 + swapin_delay_max, swapin_delay_min); 273 + 274 + PRINT_FILED_DELAY("RECLAIM", t->version, t, 275 + freepages_count, freepages_delay_total, 276 + freepages_delay_max, freepages_delay_min); 277 + 278 + PRINT_FILED_DELAY("THRASHING", t->version, t, 279 + thrashing_count, thrashing_delay_total, 280 + thrashing_delay_max, thrashing_delay_min); 281 + 282 + if (t->version >= 11) { 283 + PRINT_FILED_DELAY("COMPACT", t->version, t, 284 + compact_count, compact_delay_total, 285 + compact_delay_max, compact_delay_min); 286 + } 287 + 288 + if (t->version >= 13) { 289 + PRINT_FILED_DELAY("WPCOPY", t->version, t, 290 + wpcopy_count, wpcopy_delay_total, 291 + wpcopy_delay_max, wpcopy_delay_min); 292 + } 293 + 294 + if (t->version >= 14) { 295 + PRINT_FILED_DELAY("IRQ", t->version, t, 296 + irq_count, irq_delay_total, 297 + irq_delay_max, irq_delay_min); 298 + } 266 299 } 267 300 268 301 static void task_context_switch_counts(struct taskstats *t)
+2 -1
tools/testing/selftests/bpf/progs/bpf_misc.h
··· 229 229 230 230 #if __clang_major__ >= 18 && defined(ENABLE_ATOMICS_TESTS) && \ 231 231 (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \ 232 - (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) 232 + (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) || \ 233 + (defined(__TARGET_ARCH_powerpc)) 233 234 #define CAN_USE_LOAD_ACQ_STORE_REL 234 235 #endif 235 236
+54 -8
tools/testing/selftests/cachestat/test_cachestat.c
··· 33 33 cs->nr_evicted, cs->nr_recently_evicted); 34 34 } 35 35 36 + enum file_type { 37 + FILE_MMAP, 38 + FILE_SHMEM 39 + }; 40 + 36 41 bool write_exactly(int fd, size_t filesize) 37 42 { 38 43 int random_fd = open("/dev/urandom", O_RDONLY); ··· 206 201 out: 207 202 return ret; 208 203 } 204 + const char *file_type_str(enum file_type type) 205 + { 206 + switch (type) { 207 + case FILE_SHMEM: 208 + return "shmem"; 209 + case FILE_MMAP: 210 + return "mmap"; 211 + default: 212 + return "unknown"; 213 + } 214 + } 209 215 210 - bool test_cachestat_shmem(void) 216 + 217 + bool run_cachestat_test(enum file_type type) 211 218 { 212 219 size_t PS = sysconf(_SC_PAGESIZE); 213 220 size_t filesize = PS * 512 * 2; /* 2 2MB huge pages */ ··· 229 212 char *filename = "tmpshmcstat"; 230 213 struct cachestat cs; 231 214 bool ret = true; 215 + int fd; 232 216 unsigned long num_pages = compute_len / PS; 233 - int fd = shm_open(filename, O_CREAT | O_RDWR, 0600); 217 + if (type == FILE_SHMEM) 218 + fd = shm_open(filename, O_CREAT | O_RDWR, 0600); 219 + else 220 + fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666); 234 221 235 222 if (fd < 0) { 236 - ksft_print_msg("Unable to create shmem file.\n"); 223 + ksft_print_msg("Unable to create %s file.\n", 224 + file_type_str(type)); 237 225 ret = false; 238 226 goto out; 239 227 } 240 228 241 229 if (ftruncate(fd, filesize)) { 242 - ksft_print_msg("Unable to truncate shmem file.\n"); 230 + ksft_print_msg("Unable to truncate %s file.\n",file_type_str(type)); 243 231 ret = false; 244 232 goto close_fd; 245 233 } 234 + switch (type) { 235 + case FILE_SHMEM: 236 + if (!write_exactly(fd, filesize)) { 237 + ksft_print_msg("Unable to write to file.\n"); 238 + ret = false; 239 + goto close_fd; 240 + } 241 + break; 242 + case FILE_MMAP: 243 + char *map = mmap(NULL, filesize, PROT_READ | PROT_WRITE, 244 + MAP_SHARED, fd, 0); 246 245 247 - if (!write_exactly(fd, filesize)) { 248 - ksft_print_msg("Unable to write to shmem file.\n"); 246 + if (map == MAP_FAILED) { 247 + ksft_print_msg("mmap failed.\n"); 248 + ret = false; 249 + goto close_fd; 250 + } 251 + for (int i = 0; i < filesize; i++) 252 + map[i] = 'A'; 253 + break; 254 + default: 255 + ksft_print_msg("Unsupported file type.\n"); 249 256 ret = false; 250 257 goto close_fd; 251 258 } 252 - 253 259 syscall_ret = syscall(__NR_cachestat, fd, &cs_range, &cs, 0); 254 260 255 261 if (syscall_ret) { ··· 348 308 break; 349 309 } 350 310 351 - if (test_cachestat_shmem()) 311 + if (run_cachestat_test(FILE_SHMEM)) 352 312 ksft_test_result_pass("cachestat works with a shmem file\n"); 353 313 else { 354 314 ksft_test_result_fail("cachestat fails with a shmem file\n"); 355 315 ret = 1; 356 316 } 357 317 318 + if (run_cachestat_test(FILE_MMAP)) 319 + ksft_test_result_pass("cachestat works with a mmap file\n"); 320 + else { 321 + ksft_test_result_fail("cachestat fails with a mmap file\n"); 322 + ret = 1; 323 + } 358 324 return ret; 359 325 }
+9
tools/testing/selftests/kho/arm64.conf
··· 1 + QEMU_CMD="qemu-system-aarch64 -M virt -cpu max" 2 + QEMU_KCONFIG=" 3 + CONFIG_SERIAL_AMBA_PL010=y 4 + CONFIG_SERIAL_AMBA_PL010_CONSOLE=y 5 + CONFIG_SERIAL_AMBA_PL011=y 6 + CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 7 + " 8 + KERNEL_IMAGE="Image" 9 + KERNEL_CMDLINE="console=ttyAMA0"
+100
tools/testing/selftests/kho/init.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #ifndef NOLIBC 4 + #include <errno.h> 5 + #include <stdio.h> 6 + #include <unistd.h> 7 + #include <fcntl.h> 8 + #include <syscall.h> 9 + #include <sys/mount.h> 10 + #include <sys/reboot.h> 11 + #endif 12 + 13 + /* from arch/x86/include/asm/setup.h */ 14 + #define COMMAND_LINE_SIZE 2048 15 + 16 + /* from include/linux/kexex.h */ 17 + #define KEXEC_FILE_NO_INITRAMFS 0x00000004 18 + 19 + #define KHO_FINILIZE "/debugfs/kho/out/finalize" 20 + #define KERNEL_IMAGE "/kernel" 21 + 22 + static int mount_filesystems(void) 23 + { 24 + if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0) 25 + return -1; 26 + 27 + return mount("proc", "/proc", "proc", 0, NULL); 28 + } 29 + 30 + static int kho_enable(void) 31 + { 32 + const char enable[] = "1"; 33 + int fd; 34 + 35 + fd = open(KHO_FINILIZE, O_RDWR); 36 + if (fd < 0) 37 + return -1; 38 + 39 + if (write(fd, enable, sizeof(enable)) != sizeof(enable)) 40 + return 1; 41 + 42 + close(fd); 43 + return 0; 44 + } 45 + 46 + static long kexec_file_load(int kernel_fd, int initrd_fd, 47 + unsigned long cmdline_len, const char *cmdline, 48 + unsigned long flags) 49 + { 50 + return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len, 51 + cmdline, flags); 52 + } 53 + 54 + static int kexec_load(void) 55 + { 56 + char cmdline[COMMAND_LINE_SIZE]; 57 + ssize_t len; 58 + int fd, err; 59 + 60 + fd = open("/proc/cmdline", O_RDONLY); 61 + if (fd < 0) 62 + return -1; 63 + 64 + len = read(fd, cmdline, sizeof(cmdline)); 65 + close(fd); 66 + if (len < 0) 67 + return -1; 68 + 69 + /* replace \n with \0 */ 70 + cmdline[len - 1] = 0; 71 + fd = open(KERNEL_IMAGE, O_RDONLY); 72 + if (fd < 0) 73 + return -1; 74 + 75 + err = kexec_file_load(fd, -1, len, cmdline, KEXEC_FILE_NO_INITRAMFS); 76 + close(fd); 77 + 78 + return err ? : 0; 79 + } 80 + 81 + int main(int argc, char *argv[]) 82 + { 83 + if (mount_filesystems()) 84 + goto err_reboot; 85 + 86 + if (kho_enable()) 87 + goto err_reboot; 88 + 89 + if (kexec_load()) 90 + goto err_reboot; 91 + 92 + if (reboot(RB_KEXEC)) 93 + goto err_reboot; 94 + 95 + return 0; 96 + 97 + err_reboot: 98 + reboot(RB_AUTOBOOT); 99 + return -1; 100 + }
+183
tools/testing/selftests/kho/vmtest.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + set -ue 5 + 6 + CROSS_COMPILE="${CROSS_COMPILE:-""}" 7 + 8 + test_dir=$(realpath "$(dirname "$0")") 9 + kernel_dir=$(realpath "$test_dir/../../../..") 10 + 11 + tmp_dir=$(mktemp -d /tmp/kho-test.XXXXXXXX) 12 + headers_dir="$tmp_dir/usr" 13 + initrd_dir="$tmp_dir/initrd" 14 + initrd="$tmp_dir/initrd.cpio" 15 + 16 + source "$test_dir/../kselftest/ktap_helpers.sh" 17 + 18 + function usage() { 19 + cat <<EOF 20 + $0 [-d build_dir] [-j jobs] [-t target_arch] [-h] 21 + Options: 22 + -d) path to the kernel build directory 23 + -j) number of jobs for compilation, similar to -j in make 24 + -t) run test for target_arch, requires CROSS_COMPILE set 25 + supported targets: aarch64, x86_64 26 + -h) display this help 27 + EOF 28 + } 29 + 30 + function cleanup() { 31 + rm -fr "$tmp_dir" 32 + ktap_finished 33 + } 34 + trap cleanup EXIT 35 + 36 + function skip() { 37 + local msg=${1:-""} 38 + 39 + ktap_test_skip "$msg" 40 + exit "$KSFT_SKIP" 41 + } 42 + 43 + function fail() { 44 + local msg=${1:-""} 45 + 46 + ktap_test_fail "$msg" 47 + exit "$KSFT_FAIL" 48 + } 49 + 50 + function build_kernel() { 51 + local build_dir=$1 52 + local make_cmd=$2 53 + local arch_kconfig=$3 54 + local kimage=$4 55 + 56 + local kho_config="$tmp_dir/kho.config" 57 + local kconfig="$build_dir/.config" 58 + 59 + # enable initrd, KHO and KHO test in kernel configuration 60 + tee "$kconfig" > "$kho_config" <<EOF 61 + CONFIG_BLK_DEV_INITRD=y 62 + CONFIG_KEXEC_HANDOVER=y 63 + CONFIG_TEST_KEXEC_HANDOVER=y 64 + CONFIG_DEBUG_KERNEL=y 65 + CONFIG_DEBUG_VM=y 66 + $arch_kconfig 67 + EOF 68 + 69 + make_cmd="$make_cmd -C $kernel_dir O=$build_dir" 70 + $make_cmd olddefconfig 71 + 72 + # verify that kernel confiration has all necessary options 73 + while read -r opt ; do 74 + grep "$opt" "$kconfig" &>/dev/null || skip "$opt is missing" 75 + done < "$kho_config" 76 + 77 + $make_cmd "$kimage" 78 + $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir" 79 + } 80 + 81 + function mkinitrd() { 82 + local kernel=$1 83 + 84 + mkdir -p "$initrd_dir"/{dev,debugfs,proc} 85 + sudo mknod "$initrd_dir/dev/console" c 5 1 86 + 87 + "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -I"$headers_dir/include" \ 88 + -fno-asynchronous-unwind-tables -fno-ident -nostdlib \ 89 + -include "$test_dir/../../../include/nolibc/nolibc.h" \ 90 + -o "$initrd_dir/init" "$test_dir/init.c" \ 91 + 92 + cp "$kernel" "$initrd_dir/kernel" 93 + 94 + pushd "$initrd_dir" &>/dev/null 95 + find . | cpio -H newc --create > "$initrd" 2>/dev/null 96 + popd &>/dev/null 97 + } 98 + 99 + function run_qemu() { 100 + local qemu_cmd=$1 101 + local cmdline=$2 102 + local kernel=$3 103 + local serial="$tmp_dir/qemu.serial" 104 + 105 + cmdline="$cmdline kho=on panic=-1" 106 + 107 + $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \ 108 + -accel kvm -accel hvf -accel tcg \ 109 + -serial file:"$serial" \ 110 + -append "$cmdline" \ 111 + -kernel "$kernel" \ 112 + -initrd "$initrd" 113 + 114 + grep "KHO restore succeeded" "$serial" &> /dev/null || fail "KHO failed" 115 + } 116 + 117 + function target_to_arch() { 118 + local target=$1 119 + 120 + case $target in 121 + aarch64) echo "arm64" ;; 122 + x86_64) echo "x86" ;; 123 + *) skip "architecture $target is not supported" 124 + esac 125 + } 126 + 127 + function main() { 128 + local build_dir="$kernel_dir/.kho" 129 + local jobs=$(($(nproc) * 2)) 130 + local target="$(uname -m)" 131 + 132 + # skip the test if any of the preparation steps fails 133 + set -o errtrace 134 + trap skip ERR 135 + 136 + while getopts 'hd:j:t:' opt; do 137 + case $opt in 138 + d) 139 + build_dir="$OPTARG" 140 + ;; 141 + j) 142 + jobs="$OPTARG" 143 + ;; 144 + t) 145 + target="$OPTARG" 146 + ;; 147 + h) 148 + usage 149 + exit 0 150 + ;; 151 + *) 152 + echo Unknown argument "$opt" 153 + usage 154 + exit 1 155 + ;; 156 + esac 157 + done 158 + 159 + ktap_print_header 160 + ktap_set_plan 1 161 + 162 + if [[ "$target" != "$(uname -m)" ]] && [[ -z "$CROSS_COMPILE" ]]; then 163 + skip "Cross-platform testing needs to specify CROSS_COMPILE" 164 + fi 165 + 166 + mkdir -p "$build_dir" 167 + local arch=$(target_to_arch "$target") 168 + source "$test_dir/$arch.conf" 169 + 170 + # build the kernel and create initrd 171 + # initrd includes the kernel image that will be kexec'ed 172 + local make_cmd="make ARCH=$arch CROSS_COMPILE=$CROSS_COMPILE -j$jobs" 173 + build_kernel "$build_dir" "$make_cmd" "$QEMU_KCONFIG" "$KERNEL_IMAGE" 174 + 175 + local kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE" 176 + mkinitrd "$kernel" 177 + 178 + run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$kernel" 179 + 180 + ktap_test_pass "KHO succeeded" 181 + } 182 + 183 + main "$@"
+7
tools/testing/selftests/kho/x86.conf
··· 1 + QEMU_CMD=qemu-system-x86_64 2 + QEMU_KCONFIG=" 3 + CONFIG_SERIAL_8250=y 4 + CONFIG_SERIAL_8250_CONSOLE=y 5 + " 6 + KERNEL_IMAGE="bzImage" 7 + KERNEL_CMDLINE="console=ttyS0"
+1
tools/testing/selftests/mm/.gitignore
··· 21 21 transhuge-stress 22 22 pagemap_ioctl 23 23 pfnmap 24 + process_madv 24 25 *.tmp* 25 26 protection_keys 26 27 protection_keys_32
+1
tools/testing/selftests/mm/Makefile
··· 85 85 TEST_GEN_FILES += on-fault-limit 86 86 TEST_GEN_FILES += pagemap_ioctl 87 87 TEST_GEN_FILES += pfnmap 88 + TEST_GEN_FILES += process_madv 88 89 TEST_GEN_FILES += thuge-gen 89 90 TEST_GEN_FILES += transhuge-stress 90 91 TEST_GEN_FILES += uffd-stress
+344
tools/testing/selftests/mm/process_madv.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #define _GNU_SOURCE 4 + #include "../kselftest_harness.h" 5 + #include <errno.h> 6 + #include <setjmp.h> 7 + #include <signal.h> 8 + #include <stdbool.h> 9 + #include <stdio.h> 10 + #include <stdlib.h> 11 + #include <string.h> 12 + #include <linux/mman.h> 13 + #include <sys/syscall.h> 14 + #include <unistd.h> 15 + #include <sched.h> 16 + #include "vm_util.h" 17 + 18 + #include "../pidfd/pidfd.h" 19 + 20 + FIXTURE(process_madvise) 21 + { 22 + unsigned long page_size; 23 + pid_t child_pid; 24 + int remote_pidfd; 25 + int pidfd; 26 + }; 27 + 28 + FIXTURE_SETUP(process_madvise) 29 + { 30 + self->page_size = (unsigned long)sysconf(_SC_PAGESIZE); 31 + self->pidfd = PIDFD_SELF; 32 + self->remote_pidfd = -1; 33 + self->child_pid = -1; 34 + }; 35 + 36 + FIXTURE_TEARDOWN_PARENT(process_madvise) 37 + { 38 + /* This teardown is guaranteed to run, even if tests SKIP or ASSERT */ 39 + if (self->child_pid > 0) { 40 + kill(self->child_pid, SIGKILL); 41 + waitpid(self->child_pid, NULL, 0); 42 + } 43 + 44 + if (self->remote_pidfd >= 0) 45 + close(self->remote_pidfd); 46 + } 47 + 48 + static ssize_t sys_process_madvise(int pidfd, const struct iovec *iovec, 49 + size_t vlen, int advice, unsigned int flags) 50 + { 51 + return syscall(__NR_process_madvise, pidfd, iovec, vlen, advice, flags); 52 + } 53 + 54 + /* 55 + * This test uses PIDFD_SELF to target the current process. The main 56 + * goal is to verify the basic behavior of process_madvise() with 57 + * a vector of non-contiguous memory ranges, not its cross-process 58 + * capabilities. 59 + */ 60 + TEST_F(process_madvise, basic) 61 + { 62 + const unsigned long pagesize = self->page_size; 63 + const int madvise_pages = 4; 64 + struct iovec vec[madvise_pages]; 65 + int pidfd = self->pidfd; 66 + ssize_t ret; 67 + char *map; 68 + 69 + /* 70 + * Create a single large mapping. We will pick pages from this 71 + * mapping to advise on. This ensures we test non-contiguous iovecs. 72 + */ 73 + map = mmap(NULL, pagesize * 10, PROT_READ | PROT_WRITE, 74 + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 75 + if (map == MAP_FAILED) 76 + SKIP(return, "mmap failed, not enough memory.\n"); 77 + 78 + /* Fill the entire region with a known pattern. */ 79 + memset(map, 'A', pagesize * 10); 80 + 81 + /* 82 + * Setup the iovec to point to 4 non-contiguous pages 83 + * within the mapping. 84 + */ 85 + vec[0].iov_base = &map[0 * pagesize]; 86 + vec[0].iov_len = pagesize; 87 + vec[1].iov_base = &map[3 * pagesize]; 88 + vec[1].iov_len = pagesize; 89 + vec[2].iov_base = &map[5 * pagesize]; 90 + vec[2].iov_len = pagesize; 91 + vec[3].iov_base = &map[8 * pagesize]; 92 + vec[3].iov_len = pagesize; 93 + 94 + ret = sys_process_madvise(pidfd, vec, madvise_pages, MADV_DONTNEED, 0); 95 + if (ret == -1 && errno == EPERM) 96 + SKIP(return, 97 + "process_madvise() unsupported or permission denied, try running as root.\n"); 98 + else if (errno == EINVAL) 99 + SKIP(return, 100 + "process_madvise() unsupported or parameter invalid, please check arguments.\n"); 101 + 102 + /* The call should succeed and report the total bytes processed. */ 103 + ASSERT_EQ(ret, madvise_pages * pagesize); 104 + 105 + /* Check that advised pages are now zero. */ 106 + for (int i = 0; i < madvise_pages; i++) { 107 + char *advised_page = (char *)vec[i].iov_base; 108 + 109 + /* Content must be 0, not 'A'. */ 110 + ASSERT_EQ(*advised_page, '\0'); 111 + } 112 + 113 + /* Check that an un-advised page in between is still 'A'. */ 114 + char *unadvised_page = &map[1 * pagesize]; 115 + 116 + for (int i = 0; i < pagesize; i++) 117 + ASSERT_EQ(unadvised_page[i], 'A'); 118 + 119 + /* Cleanup. */ 120 + ASSERT_EQ(munmap(map, pagesize * 10), 0); 121 + } 122 + 123 + /* 124 + * This test deterministically validates process_madvise() with MADV_COLLAPSE 125 + * on a remote process, other advices are difficult to verify reliably. 126 + * 127 + * The test verifies that a memory region in a child process, 128 + * focus on process_madv remote result, only check addresses and lengths. 129 + * The correctness of the MADV_COLLAPSE can be found in the relevant test examples in khugepaged. 130 + */ 131 + TEST_F(process_madvise, remote_collapse) 132 + { 133 + const unsigned long pagesize = self->page_size; 134 + long huge_page_size; 135 + int pipe_info[2]; 136 + ssize_t ret; 137 + struct iovec vec; 138 + 139 + struct child_info { 140 + pid_t pid; 141 + void *map_addr; 142 + } info; 143 + 144 + huge_page_size = read_pmd_pagesize(); 145 + if (huge_page_size <= 0) 146 + SKIP(return, "Could not determine a valid huge page size.\n"); 147 + 148 + ASSERT_EQ(pipe(pipe_info), 0); 149 + 150 + self->child_pid = fork(); 151 + ASSERT_NE(self->child_pid, -1); 152 + 153 + if (self->child_pid == 0) { 154 + char *map; 155 + size_t map_size = 2 * huge_page_size; 156 + 157 + close(pipe_info[0]); 158 + 159 + map = mmap(NULL, map_size, PROT_READ | PROT_WRITE, 160 + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 161 + ASSERT_NE(map, MAP_FAILED); 162 + 163 + /* Fault in as small pages */ 164 + for (size_t i = 0; i < map_size; i += pagesize) 165 + map[i] = 'A'; 166 + 167 + /* Send info and pause */ 168 + info.pid = getpid(); 169 + info.map_addr = map; 170 + ret = write(pipe_info[1], &info, sizeof(info)); 171 + ASSERT_EQ(ret, sizeof(info)); 172 + close(pipe_info[1]); 173 + 174 + pause(); 175 + exit(0); 176 + } 177 + 178 + close(pipe_info[1]); 179 + 180 + /* Receive child info */ 181 + ret = read(pipe_info[0], &info, sizeof(info)); 182 + if (ret <= 0) { 183 + waitpid(self->child_pid, NULL, 0); 184 + SKIP(return, "Failed to read child info from pipe.\n"); 185 + } 186 + ASSERT_EQ(ret, sizeof(info)); 187 + close(pipe_info[0]); 188 + self->child_pid = info.pid; 189 + 190 + self->remote_pidfd = syscall(__NR_pidfd_open, self->child_pid, 0); 191 + ASSERT_GE(self->remote_pidfd, 0); 192 + 193 + vec.iov_base = info.map_addr; 194 + vec.iov_len = huge_page_size; 195 + 196 + ret = sys_process_madvise(self->remote_pidfd, &vec, 1, MADV_COLLAPSE, 197 + 0); 198 + if (ret == -1) { 199 + if (errno == EINVAL) 200 + SKIP(return, "PROCESS_MADV_ADVISE is not supported.\n"); 201 + else if (errno == EPERM) 202 + SKIP(return, 203 + "No process_madvise() permissions, try running as root.\n"); 204 + return; 205 + } 206 + 207 + ASSERT_EQ(ret, huge_page_size); 208 + } 209 + 210 + /* 211 + * Test process_madvise() with a pidfd for a process that has already 212 + * exited to ensure correct error handling. 213 + */ 214 + TEST_F(process_madvise, exited_process_pidfd) 215 + { 216 + const unsigned long pagesize = self->page_size; 217 + struct iovec vec; 218 + char *map; 219 + ssize_t ret; 220 + 221 + map = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 222 + 0); 223 + if (map == MAP_FAILED) 224 + SKIP(return, "mmap failed, not enough memory.\n"); 225 + 226 + vec.iov_base = map; 227 + vec.iov_len = pagesize; 228 + 229 + /* 230 + * Using a pidfd for a process that has already exited should fail 231 + * with ESRCH. 232 + */ 233 + self->child_pid = fork(); 234 + ASSERT_NE(self->child_pid, -1); 235 + 236 + if (self->child_pid == 0) 237 + exit(0); 238 + 239 + self->remote_pidfd = syscall(__NR_pidfd_open, self->child_pid, 0); 240 + ASSERT_GE(self->remote_pidfd, 0); 241 + 242 + /* Wait for the child to ensure it has terminated. */ 243 + waitpid(self->child_pid, NULL, 0); 244 + 245 + ret = sys_process_madvise(self->remote_pidfd, &vec, 1, MADV_DONTNEED, 246 + 0); 247 + ASSERT_EQ(ret, -1); 248 + ASSERT_EQ(errno, ESRCH); 249 + } 250 + 251 + /* 252 + * Test process_madvise() with bad pidfds to ensure correct error 253 + * handling. 254 + */ 255 + TEST_F(process_madvise, bad_pidfd) 256 + { 257 + const unsigned long pagesize = self->page_size; 258 + struct iovec vec; 259 + char *map; 260 + ssize_t ret; 261 + 262 + map = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 263 + 0); 264 + if (map == MAP_FAILED) 265 + SKIP(return, "mmap failed, not enough memory.\n"); 266 + 267 + vec.iov_base = map; 268 + vec.iov_len = pagesize; 269 + 270 + /* Using an invalid fd number (-1) should fail with EBADF. */ 271 + ret = sys_process_madvise(-1, &vec, 1, MADV_DONTNEED, 0); 272 + ASSERT_EQ(ret, -1); 273 + ASSERT_EQ(errno, EBADF); 274 + 275 + /* 276 + * Using a valid fd that is not a pidfd (e.g. stdin) should fail 277 + * with EBADF. 278 + */ 279 + ret = sys_process_madvise(STDIN_FILENO, &vec, 1, MADV_DONTNEED, 0); 280 + ASSERT_EQ(ret, -1); 281 + ASSERT_EQ(errno, EBADF); 282 + } 283 + 284 + /* 285 + * Test that process_madvise() rejects vlen > UIO_MAXIOV. 286 + * The kernel should return -EINVAL when the number of iovecs exceeds 1024. 287 + */ 288 + TEST_F(process_madvise, invalid_vlen) 289 + { 290 + const unsigned long pagesize = self->page_size; 291 + int pidfd = self->pidfd; 292 + struct iovec vec; 293 + char *map; 294 + ssize_t ret; 295 + 296 + map = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 297 + 0); 298 + if (map == MAP_FAILED) 299 + SKIP(return, "mmap failed, not enough memory.\n"); 300 + 301 + vec.iov_base = map; 302 + vec.iov_len = pagesize; 303 + 304 + ret = sys_process_madvise(pidfd, &vec, 1025, MADV_DONTNEED, 0); 305 + ASSERT_EQ(ret, -1); 306 + ASSERT_EQ(errno, EINVAL); 307 + 308 + /* Cleanup. */ 309 + ASSERT_EQ(munmap(map, pagesize), 0); 310 + } 311 + 312 + /* 313 + * Test process_madvise() with an invalid flag value. Currently, only a flag 314 + * value of 0 is supported. This test is reserved for the future, e.g., if 315 + * synchronous flags are added. 316 + */ 317 + TEST_F(process_madvise, flag) 318 + { 319 + const unsigned long pagesize = self->page_size; 320 + unsigned int invalid_flag; 321 + int pidfd = self->pidfd; 322 + struct iovec vec; 323 + char *map; 324 + ssize_t ret; 325 + 326 + map = mmap(NULL, pagesize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 327 + 0); 328 + if (map == MAP_FAILED) 329 + SKIP(return, "mmap failed, not enough memory.\n"); 330 + 331 + vec.iov_base = map; 332 + vec.iov_len = pagesize; 333 + 334 + invalid_flag = 0x80000000; 335 + 336 + ret = sys_process_madvise(pidfd, &vec, 1, MADV_DONTNEED, invalid_flag); 337 + ASSERT_EQ(ret, -1); 338 + ASSERT_EQ(errno, EINVAL); 339 + 340 + /* Cleanup. */ 341 + ASSERT_EQ(munmap(map, pagesize), 0); 342 + } 343 + 344 + TEST_HARNESS_MAIN
+5
tools/testing/selftests/mm/run_vmtests.sh
··· 65 65 test pagemap_scan IOCTL 66 66 - pfnmap 67 67 tests for VM_PFNMAP handling 68 + - process_madv 69 + test for process_madv 68 70 - cow 69 71 test copy-on-write semantics 70 72 - thp ··· 426 424 427 425 # MADV_POPULATE_READ and MADV_POPULATE_WRITE tests 428 426 CATEGORY="madv_populate" run_test ./madv_populate 427 + 428 + # PROCESS_MADV test 429 + CATEGORY="process_madv" run_test ./process_madv 429 430 430 431 CATEGORY="vma_merge" run_test ./merge 431 432
+1
tools/testing/selftests/perf_events/.gitignore
··· 2 2 sigtrap_threads 3 3 remove_on_exec 4 4 watermark_signal 5 + mmap
+1 -1
tools/testing/selftests/perf_events/Makefile
··· 2 2 CFLAGS += -Wl,-no-as-needed -Wall $(KHDR_INCLUDES) 3 3 LDFLAGS += -lpthread 4 4 5 - TEST_GEN_PROGS := sigtrap_threads remove_on_exec watermark_signal 5 + TEST_GEN_PROGS := sigtrap_threads remove_on_exec watermark_signal mmap 6 6 include ../lib.mk
+236
tools/testing/selftests/perf_events/mmap.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #define _GNU_SOURCE 3 + 4 + #include <dirent.h> 5 + #include <sched.h> 6 + #include <stdbool.h> 7 + #include <stdio.h> 8 + #include <unistd.h> 9 + 10 + #include <sys/ioctl.h> 11 + #include <sys/mman.h> 12 + #include <sys/syscall.h> 13 + #include <sys/types.h> 14 + 15 + #include <linux/perf_event.h> 16 + 17 + #include "../kselftest_harness.h" 18 + 19 + #define RB_SIZE 0x3000 20 + #define AUX_SIZE 0x10000 21 + #define AUX_OFFS 0x4000 22 + 23 + #define HOLE_SIZE 0x1000 24 + 25 + /* Reserve space for rb, aux with space for shrink-beyond-vma testing. */ 26 + #define REGION_SIZE (2 * RB_SIZE + 2 * AUX_SIZE) 27 + #define REGION_AUX_OFFS (2 * RB_SIZE) 28 + 29 + #define MAP_BASE 1 30 + #define MAP_AUX 2 31 + 32 + #define EVENT_SRC_DIR "/sys/bus/event_source/devices" 33 + 34 + FIXTURE(perf_mmap) 35 + { 36 + int fd; 37 + void *ptr; 38 + void *region; 39 + }; 40 + 41 + FIXTURE_VARIANT(perf_mmap) 42 + { 43 + bool aux; 44 + unsigned long ptr_size; 45 + }; 46 + 47 + FIXTURE_VARIANT_ADD(perf_mmap, rb) 48 + { 49 + .aux = false, 50 + .ptr_size = RB_SIZE, 51 + }; 52 + 53 + FIXTURE_VARIANT_ADD(perf_mmap, aux) 54 + { 55 + .aux = true, 56 + .ptr_size = AUX_SIZE, 57 + }; 58 + 59 + static bool read_event_type(struct dirent *dent, __u32 *type) 60 + { 61 + char typefn[512]; 62 + FILE *fp; 63 + int res; 64 + 65 + snprintf(typefn, sizeof(typefn), "%s/%s/type", EVENT_SRC_DIR, dent->d_name); 66 + fp = fopen(typefn, "r"); 67 + if (!fp) 68 + return false; 69 + 70 + res = fscanf(fp, "%u", type); 71 + fclose(fp); 72 + return res > 0; 73 + } 74 + 75 + FIXTURE_SETUP(perf_mmap) 76 + { 77 + struct perf_event_attr attr = { 78 + .size = sizeof(attr), 79 + .disabled = 1, 80 + .exclude_kernel = 1, 81 + .exclude_hv = 1, 82 + }; 83 + struct perf_event_attr attr_ok = {}; 84 + unsigned int eacces = 0, map = 0; 85 + struct perf_event_mmap_page *rb; 86 + struct dirent *dent; 87 + void *aux, *region; 88 + DIR *dir; 89 + 90 + self->ptr = NULL; 91 + 92 + dir = opendir(EVENT_SRC_DIR); 93 + if (!dir) 94 + SKIP(return, "perf not available."); 95 + 96 + region = mmap(NULL, REGION_SIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); 97 + ASSERT_NE(region, MAP_FAILED); 98 + self->region = region; 99 + 100 + // Try to find a suitable event on this system 101 + while ((dent = readdir(dir))) { 102 + int fd; 103 + 104 + if (!read_event_type(dent, &attr.type)) 105 + continue; 106 + 107 + fd = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0); 108 + if (fd < 0) { 109 + if (errno == EACCES) 110 + eacces++; 111 + continue; 112 + } 113 + 114 + // Check whether the event supports mmap() 115 + rb = mmap(region, RB_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0); 116 + if (rb == MAP_FAILED) { 117 + close(fd); 118 + continue; 119 + } 120 + 121 + if (!map) { 122 + // Save the event in case that no AUX capable event is found 123 + attr_ok = attr; 124 + map = MAP_BASE; 125 + } 126 + 127 + if (!variant->aux) 128 + continue; 129 + 130 + rb->aux_offset = AUX_OFFS; 131 + rb->aux_size = AUX_SIZE; 132 + 133 + // Check whether it supports a AUX buffer 134 + aux = mmap(region + REGION_AUX_OFFS, AUX_SIZE, PROT_READ | PROT_WRITE, 135 + MAP_SHARED | MAP_FIXED, fd, AUX_OFFS); 136 + if (aux == MAP_FAILED) { 137 + munmap(rb, RB_SIZE); 138 + close(fd); 139 + continue; 140 + } 141 + 142 + attr_ok = attr; 143 + map = MAP_AUX; 144 + munmap(aux, AUX_SIZE); 145 + munmap(rb, RB_SIZE); 146 + close(fd); 147 + break; 148 + } 149 + closedir(dir); 150 + 151 + if (!map) { 152 + if (!eacces) 153 + SKIP(return, "No mappable perf event found."); 154 + else 155 + SKIP(return, "No permissions for perf_event_open()"); 156 + } 157 + 158 + self->fd = syscall(SYS_perf_event_open, &attr_ok, 0, -1, -1, 0); 159 + ASSERT_NE(self->fd, -1); 160 + 161 + rb = mmap(region, RB_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, self->fd, 0); 162 + ASSERT_NE(rb, MAP_FAILED); 163 + 164 + if (!variant->aux) { 165 + self->ptr = rb; 166 + return; 167 + } 168 + 169 + if (map != MAP_AUX) 170 + SKIP(return, "No AUX event found."); 171 + 172 + rb->aux_offset = AUX_OFFS; 173 + rb->aux_size = AUX_SIZE; 174 + aux = mmap(region + REGION_AUX_OFFS, AUX_SIZE, PROT_READ | PROT_WRITE, 175 + MAP_SHARED | MAP_FIXED, self->fd, AUX_OFFS); 176 + ASSERT_NE(aux, MAP_FAILED); 177 + self->ptr = aux; 178 + } 179 + 180 + FIXTURE_TEARDOWN(perf_mmap) 181 + { 182 + ASSERT_EQ(munmap(self->region, REGION_SIZE), 0); 183 + if (self->fd != -1) 184 + ASSERT_EQ(close(self->fd), 0); 185 + } 186 + 187 + TEST_F(perf_mmap, remap) 188 + { 189 + void *tmp, *ptr = self->ptr; 190 + unsigned long size = variant->ptr_size; 191 + 192 + // Test the invalid remaps 193 + ASSERT_EQ(mremap(ptr, size, HOLE_SIZE, MREMAP_MAYMOVE), MAP_FAILED); 194 + ASSERT_EQ(mremap(ptr + HOLE_SIZE, size, HOLE_SIZE, MREMAP_MAYMOVE), MAP_FAILED); 195 + ASSERT_EQ(mremap(ptr + size - HOLE_SIZE, HOLE_SIZE, size, MREMAP_MAYMOVE), MAP_FAILED); 196 + // Shrink the end of the mapping such that we only unmap past end of the VMA, 197 + // which should succeed and poke a hole into the PROT_NONE region 198 + ASSERT_NE(mremap(ptr + size - HOLE_SIZE, size, HOLE_SIZE, MREMAP_MAYMOVE), MAP_FAILED); 199 + 200 + // Remap the whole buffer to a new address 201 + tmp = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 202 + ASSERT_NE(tmp, MAP_FAILED); 203 + 204 + // Try splitting offset 1 hole size into VMA, this should fail 205 + ASSERT_EQ(mremap(ptr + HOLE_SIZE, size - HOLE_SIZE, size - HOLE_SIZE, 206 + MREMAP_MAYMOVE | MREMAP_FIXED, tmp), MAP_FAILED); 207 + // Remapping the whole thing should succeed fine 208 + ptr = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tmp); 209 + ASSERT_EQ(ptr, tmp); 210 + ASSERT_EQ(munmap(tmp, size), 0); 211 + } 212 + 213 + TEST_F(perf_mmap, unmap) 214 + { 215 + unsigned long size = variant->ptr_size; 216 + 217 + // Try to poke holes into the mappings 218 + ASSERT_NE(munmap(self->ptr, HOLE_SIZE), 0); 219 + ASSERT_NE(munmap(self->ptr + HOLE_SIZE, HOLE_SIZE), 0); 220 + ASSERT_NE(munmap(self->ptr + size - HOLE_SIZE, HOLE_SIZE), 0); 221 + } 222 + 223 + TEST_F(perf_mmap, map) 224 + { 225 + unsigned long size = variant->ptr_size; 226 + 227 + // Try to poke holes into the mappings by mapping anonymous memory over it 228 + ASSERT_EQ(mmap(self->ptr, HOLE_SIZE, PROT_READ | PROT_WRITE, 229 + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0), MAP_FAILED); 230 + ASSERT_EQ(mmap(self->ptr + HOLE_SIZE, HOLE_SIZE, PROT_READ | PROT_WRITE, 231 + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0), MAP_FAILED); 232 + ASSERT_EQ(mmap(self->ptr + size - HOLE_SIZE, HOLE_SIZE, PROT_READ | PROT_WRITE, 233 + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0), MAP_FAILED); 234 + } 235 + 236 + TEST_HARNESS_MAIN
+1
tools/testing/selftests/ptrace/.gitignore
··· 3 3 get_set_sud 4 4 peeksiginfo 5 5 vmaccess 6 + set_syscall_info
+7 -9
tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
··· 32 32 33 33 fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR); 34 34 if (fd < 0) { 35 - perror("Unable to open workload type feature enable file\n"); 35 + perror("Unable to open workload type feature enable file"); 36 36 exit(1); 37 37 } 38 38 39 39 if (write(fd, "0\n", 2) < 0) { 40 - perror("Can't disable workload hints\n"); 40 + perror("Can't disable workload hints"); 41 41 exit(1); 42 42 } 43 43 ··· 68 68 exit(1); 69 69 70 70 sprintf(delay_str, "%s\n", argv[1]); 71 - 72 - sprintf(delay_str, "%s\n", argv[1]); 73 71 fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR); 74 72 if (fd < 0) { 75 - perror("Unable to open workload notification delay\n"); 73 + perror("Unable to open workload notification delay"); 76 74 exit(1); 77 75 } 78 76 79 77 if (write(fd, delay_str, strlen(delay_str)) < 0) { 80 - perror("Can't set delay\n"); 78 + perror("Can't set delay"); 81 79 exit(1); 82 80 } 83 81 ··· 92 94 /* Enable feature via sysfs knob */ 93 95 fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR); 94 96 if (fd < 0) { 95 - perror("Unable to open workload type feature enable file\n"); 97 + perror("Unable to open workload type feature enable file"); 96 98 exit(1); 97 99 } 98 100 99 101 if (write(fd, "1\n", 2) < 0) { 100 - perror("Can't enable workload hints\n"); 102 + perror("Can't enable workload hints"); 101 103 exit(1); 102 104 } 103 105 ··· 108 110 while (1) { 109 111 fd = open(WORKLOAD_TYPE_INDEX_ATTRIBUTE, O_RDONLY); 110 112 if (fd < 0) { 111 - perror("Unable to open workload type file\n"); 113 + perror("Unable to open workload type file"); 112 114 exit(1); 113 115 } 114 116
+4 -2
tools/testing/vma/vma_internal.h
··· 108 108 #define CAP_IPC_LOCK 14 109 109 110 110 #ifdef CONFIG_64BIT 111 - /* VM is sealed, in vm_flags */ 112 - #define VM_SEALED _BITUL(63) 111 + #define VM_SEALED_BIT 42 112 + #define VM_SEALED BIT(VM_SEALED_BIT) 113 + #else 114 + #define VM_SEALED VM_NONE 113 115 #endif 114 116 115 117 #define FIRST_USER_ADDRESS 0UL