diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs new file mode 100644 index 0000000000000000000000000000000000000000..a9512594dc4ca0d41e670fad6b61bea726a95ee2 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-fs-erofs @@ -0,0 +1,7 @@ +What: /sys/fs/erofs/features/ +Date: November 2021 +Contact: "Huang Jianan" +Description: Shows all enabled kernel features. + Supported features: + zero_padding, compr_cfgs, big_pcluster, chunked_file, + device_table, compr_head2, sb_chksum. diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 9beb2b650f1678840d0c8a8f4c2fa8a317d76b60..9b583dd0298b7926d7b2ab9bd33a846711d109e3 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -55,8 +55,9 @@ Description: Controls the in-place-update policy. 0x04 F2FS_IPU_UTIL 0x08 F2FS_IPU_SSR_UTIL 0x10 F2FS_IPU_FSYNC - 0x20 F2FS_IPU_ASYNC, + 0x20 F2FS_IPU_ASYNC 0x40 F2FS_IPU_NOCACHE + 0x80 F2FS_IPU_HONOR_OPU_WRITE ==== ================= Refer segment.h for details. @@ -98,6 +99,33 @@ Description: Controls the issue rate of discard commands that consist of small checkpoint is triggered, and issued during the checkpoint. By default, it is disabled with 0. +What: /sys/fs/f2fs//max_discard_request +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the number of discards a thread will issue at a time. + Higher number will allow the discard thread to finish its work + faster, at the cost of higher latency for incomming I/O. + +What: /sys/fs/f2fs//min_discard_issue_time +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the interval the discard thread will wait between + issuing discard requests when there are discards to be issued and + no I/O aware interruptions occur. + +What: /sys/fs/f2fs//mid_discard_issue_time +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the interval the discard thread will wait between + issuing discard requests when there are discards to be issued and + an I/O aware interruption occurs. + +What: /sys/fs/f2fs//max_discard_issue_time +Date: December 2021 +Contact: "Konstantin Vyshetsky" +Description: Controls the interval the discard thread will wait when there are + no discard operations to be issued. + What: /sys/fs/f2fs//discard_granularity Date: July 2017 Contact: "Chao Yu" @@ -269,11 +297,16 @@ Description: Shows current reserved blocks in system, it may be temporarily What: /sys/fs/f2fs//gc_urgent Date: August 2017 Contact: "Jaegeuk Kim" -Description: Do background GC agressively when set. When gc_urgent = 1, - background thread starts to do GC by given gc_urgent_sleep_time - interval. When gc_urgent = 2, F2FS will lower the bar of - checking idle in order to process outstanding discard commands - and GC a little bit aggressively. It is set to 0 by default. +Description: Do background GC aggressively when set. Set to 0 by default. + gc urgent high(1): does GC forcibly in a period of given + gc_urgent_sleep_time and ignores I/O idling check. uses greedy + GC approach and turns SSR mode on. + gc urgent low(2): lowers the bar of checking I/O idling in + order to process outstanding discard commands and GC a + little bit aggressively. uses cost benefit GC approach. + gc urgent mid(3): does GC forcibly in a period of given + gc_urgent_sleep_time and executes a mid level of I/O idling check. + uses cost benefit GC approach. What: /sys/fs/f2fs//gc_urgent_sleep_time Date: August 2017 @@ -430,6 +463,7 @@ Description: Show status of f2fs superblock in real time. 0x800 SBI_QUOTA_SKIP_FLUSH skip flushing quota in current CP 0x1000 SBI_QUOTA_NEED_REPAIR quota file may be corrupted 0x2000 SBI_IS_RESIZEFS resizefs is in process + 0x4000 SBI_IS_FREEZING freefs is in process ====== ===================== ================================= What: /sys/fs/f2fs//ckpt_thread_ioprio @@ -503,7 +537,7 @@ Date: July 2021 Contact: "Daeho Jeong" Description: Show how many segments have been reclaimed by GC during a specific GC mode (0: GC normal, 1: GC idle CB, 2: GC idle greedy, - 3: GC idle AT, 4: GC urgent high, 5: GC urgent low) + 3: GC idle AT, 4: GC urgent high, 5: GC urgent low 6: GC urgent mid) You can re-initialize this value to "0". What: /sys/fs/f2fs//gc_segment_mode @@ -540,3 +574,9 @@ Contact: "Daeho Jeong" Description: You can set the trial count limit for GC urgent high mode with this value. If GC thread gets to the limit, the mode will turn back to GC normal mode. By default, the value is zero, which means there is no limit like before. + +What: /sys/fs/f2fs//max_roll_forward_node_blocks +Date: January 2022 +Contact: "Jaegeuk Kim" +Description: Controls max # of node block writes to be used for roll forward + recovery. This can limit the roll forward recovery time. diff --git a/Documentation/admin-guide/mm/index.rst b/Documentation/admin-guide/mm/index.rst index cd727cfc1b0404db5e422a41a7dd2b3193d122a9..2a2b5bd8299a8b6b751289732e733116bcb3ff04 100644 --- a/Documentation/admin-guide/mm/index.rst +++ b/Documentation/admin-guide/mm/index.rst @@ -31,6 +31,7 @@ the Linux memory management. idle_page_tracking ksm memory-hotplug + multigen_lru nommu-mmap numa_memory_policy numaperf diff --git a/Documentation/admin-guide/mm/multigen_lru.rst b/Documentation/admin-guide/mm/multigen_lru.rst new file mode 100644 index 0000000000000000000000000000000000000000..3d9a6ef842298f99e09393bafa9b23a22bc2ac56 --- /dev/null +++ b/Documentation/admin-guide/mm/multigen_lru.rst @@ -0,0 +1,152 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +Multi-Gen LRU +============= +The multi-gen LRU is an alternative LRU implementation that optimizes +page reclaim and improves performance under memory pressure. Page +reclaim decides the kernel's caching policy and ability to overcommit +memory. It directly impacts the kswapd CPU usage and RAM efficiency. + +Quick start +=========== +Build the kernel with the following configurations. + +* ``CONFIG_LRU_GEN=y`` +* ``CONFIG_LRU_GEN_ENABLED=y`` + +All set! + +Runtime options +=============== +``/sys/kernel/mm/lru_gen/`` contains stable ABIs described in the +following subsections. + +Kill switch +----------- +``enable`` accepts different values to enable or disable the following +components. Its default value depends on ``CONFIG_LRU_GEN_ENABLED``. +All the components should be enabled unless some of them have +unforeseen side effects. Writing to ``enable`` has no effect when a +component is not supported by the hardware, and valid values will be +accepted even when the main switch is off. + +====== =============================================================== +Values Components +====== =============================================================== +0x0001 The main switch for the multi-gen LRU. +0x0002 Clearing the accessed bit in leaf page table entries in large + batches, when MMU sets it (e.g., on x86). This behavior can + theoretically worsen lock contention (mmap_lock). If it is + disabled, the multi-gen LRU will suffer a minor performance + degradation. +0x0004 Clearing the accessed bit in non-leaf page table entries as + well, when MMU sets it (e.g., on x86). This behavior was not + verified on x86 varieties other than Intel and AMD. If it is + disabled, the multi-gen LRU will suffer a negligible + performance degradation. +[yYnN] Apply to all the components above. +====== =============================================================== + +E.g., +:: + + echo y >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0007 + echo 5 >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0005 + +Thrashing prevention +-------------------- +Personal computers are more sensitive to thrashing because it can +cause janks (lags when rendering UI) and negatively impact user +experience. The multi-gen LRU offers thrashing prevention to the +majority of laptop and desktop users who do not have ``oomd``. + +Users can write ``N`` to ``min_ttl_ms`` to prevent the working set of +``N`` milliseconds from getting evicted. The OOM killer is triggered +if this working set cannot be kept in memory. In other words, this +option works as an adjustable pressure relief valve, and when open, it +terminates applications that are hopefully not being used. + +Based on the average human detectable lag (~100ms), ``N=1000`` usually +eliminates intolerable janks due to thrashing. Larger values like +``N=3000`` make janks less noticeable at the risk of premature OOM +kills. + +The default value ``0`` means disabled. + +Experimental features +===================== +``/sys/kernel/debug/lru_gen`` accepts commands described in the +following subsections. Multiple command lines are supported, so does +concatenation with delimiters ``,`` and ``;``. + +``/sys/kernel/debug/lru_gen_full`` provides additional stats for +debugging. ``CONFIG_LRU_GEN_STATS=y`` keeps historical stats from +evicted generations in this file. + +Working set estimation +---------------------- +Working set estimation measures how much memory an application +requires in a given time interval, and it is usually done with little +impact on the performance of the application. E.g., data centers want +to optimize job scheduling (bin packing) to improve memory +utilizations. When a new job comes in, the job scheduler needs to find +out whether each server it manages can allocate a certain amount of +memory for this new job before it can pick a candidate. To do so, this +job scheduler needs to estimate the working sets of the existing jobs. + +When it is read, ``lru_gen`` returns a histogram of numbers of pages +accessed over different time intervals for each memcg and node. +``MAX_NR_GENS`` decides the number of bins for each histogram. +:: + + memcg memcg_id memcg_path + node node_id + min_gen_nr age_in_ms nr_anon_pages nr_file_pages + ... + max_gen_nr age_in_ms nr_anon_pages nr_file_pages + +Each generation contains an estimated number of pages that have been +accessed within ``age_in_ms`` non-cumulatively. E.g., ``min_gen_nr`` +contains the coldest pages and ``max_gen_nr`` contains the hottest +pages, since ``age_in_ms`` of the former is the largest and that of +the latter is the smallest. + +Users can write ``+ memcg_id node_id max_gen_nr +[can_swap[full_scan]]`` to ``lru_gen`` to create a new generation +``max_gen_nr+1``. ``can_swap`` defaults to the swap setting and, if it +is set to ``1``, it forces the scan of anon pages when swap is off. +``full_scan`` defaults to ``1`` and, if it is set to ``0``, it reduces +the overhead as well as the coverage when scanning page tables. + +A typical use case is that a job scheduler writes to ``lru_gen`` at a +certain time interval to create new generations, and it ranks the +servers it manages based on the sizes of their cold memory defined by +this time interval. + +Proactive reclaim +----------------- +Proactive reclaim induces memory reclaim when there is no memory +pressure and usually targets cold memory only. E.g., when a new job +comes in, the job scheduler wants to proactively reclaim memory on the +server it has selected to improve the chance of successfully landing +this new job. + +Users can write ``- memcg_id node_id min_gen_nr [swappiness +[nr_to_reclaim]]`` to ``lru_gen`` to evict generations less than or +equal to ``min_gen_nr``. Note that ``min_gen_nr`` should be less than +``max_gen_nr-1`` as ``max_gen_nr`` and ``max_gen_nr-1`` are not fully +aged and therefore cannot be evicted. ``swappiness`` overrides the +default value in ``/proc/sys/vm/swappiness``. ``nr_to_reclaim`` limits +the number of pages to evict. + +A typical use case is that a job scheduler writes to ``lru_gen`` +before it tries to land a new job on a server, and if it fails to +materialize the cold memory without impacting the existing jobs on +this server, it retries on the next server according to the ranking +result obtained from the working set estimation step described +earlier. diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index e338306f4587341ef4b5f5377ebd44f321e4b01e..7d5e8a67c775f16dcc63bacdd50dbad80248d111 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -787,7 +787,6 @@ bit 1 print system memory info bit 2 print timer info bit 3 print locks info if ``CONFIG_LOCKDEP`` is on bit 4 print ftrace buffer -bit 5 print all printk messages in buffer ===== ============================================ So for example to print tasks and memory info on panic, user can:: diff --git a/Documentation/core-api/dma-attributes.rst b/Documentation/core-api/dma-attributes.rst index 17706dc91ec9fcf51178017b41f50862072c2c40..1887d92e8e926909b3641ffed82b5129dfde0c4d 100644 --- a/Documentation/core-api/dma-attributes.rst +++ b/Documentation/core-api/dma-attributes.rst @@ -130,11 +130,3 @@ accesses to DMA buffers in both privileged "supervisor" and unprivileged subsystem that the buffer is fully accessible at the elevated privilege level (and ideally inaccessible or at least read-only at the lesser-privileged levels). - -DMA_ATTR_OVERWRITE ------------------- - -This is a hint to the DMA-mapping subsystem that the device is expected to -overwrite the entire mapped size, thus the caller does not require any of the -previous buffer contents to be preserved. This allows bounce-buffering -implementations to optimise DMA_FROM_DEVICE transfers. diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index 6fe2a3d8ee6b86dd3d83b63512834c70fee18fce..b29050fd7470a3811530572ef5d4d25922ffee56 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -44,7 +44,7 @@ patternProperties: properties: reg: description: - Contains the chip-select IDs. + Contains the native Ready/Busy IDs. nand-ecc-mode: description: @@ -174,6 +174,6 @@ examples: nand-ecc-mode = "soft"; nand-ecc-algo = "bch"; - /* NAND chip specific properties */ + /* controller specific properties */ }; }; diff --git a/Documentation/devicetree/bindings/spi/spi-mxic.txt b/Documentation/devicetree/bindings/spi/spi-mxic.txt index 7bcbb229b78bb3c6d03652d63ad5da6ace0304f9..529f2dab2648a78b5a82d7b7ffd95bb07e8c51e1 100644 --- a/Documentation/devicetree/bindings/spi/spi-mxic.txt +++ b/Documentation/devicetree/bindings/spi/spi-mxic.txt @@ -8,13 +8,11 @@ Required properties: - reg: should contain 2 entries, one for the registers and one for the direct mapping area - reg-names: should contain "regs" and "dirmap" +- interrupts: interrupt line connected to the SPI controller - clock-names: should contain "ps_clk", "send_clk" and "send_dly_clk" - clocks: should contain 3 entries for the "ps_clk", "send_clk" and "send_dly_clk" clocks -Optional properties: -- interrupts: interrupt line connected to the SPI controller - Example: spi@43c30000 { diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst index 01df283c7d04f7fb8c9ba94d36a61d05056e9f7f..7119aa213be71c396c599c215e17688688db4d33 100644 --- a/Documentation/filesystems/erofs.rst +++ b/Documentation/filesystems/erofs.rst @@ -93,6 +93,14 @@ dax A legacy option which is an alias for ``dax=always``. device=%s Specify a path to an extra device to be used together. =================== ========================================================= +Sysfs Entries +============= + +Information about mounted erofs file systems can be found in /sys/fs/erofs. +Each mounted filesystem will have a directory in /sys/fs/erofs based on its +device name (i.e., /sys/fs/erofs/sda). +(see also Documentation/ABI/testing/sysfs-fs-erofs) + On-disk details =============== diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 4d5d50dca65c6725e164ab08806824fa5a083404..6ccd5efb25b779d13157d0279a9e16328a0f1476 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -1047,8 +1047,8 @@ astute users may notice some differences in behavior: may be used to overwrite the source files but isn't guaranteed to be effective on all filesystems and storage devices. -- Direct I/O is not supported on encrypted files. Attempts to use - direct I/O on such files will fall back to buffered I/O. +- Direct I/O is supported on encrypted files only under some + circumstances. For details, see `Direct I/O support`_. - The fallocate operations FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE are not supported on encrypted files and will @@ -1179,6 +1179,27 @@ Inline encryption doesn't affect the ciphertext or other aspects of the on-disk format, so users may freely switch back and forth between using "inlinecrypt" and not using "inlinecrypt". +Direct I/O support +================== + +For direct I/O on an encrypted file to work, the following conditions +must be met (in addition to the conditions for direct I/O on an +unencrypted file): + +* The file must be using inline encryption. Usually this means that + the filesystem must be mounted with ``-o inlinecrypt`` and inline + encryption hardware must be present. However, a software fallback + is also available. For details, see `Inline encryption support`_. + +* The I/O request must be fully aligned to the filesystem block size. + This means that the file position the I/O is targeting, the lengths + of all I/O segments, and the memory addresses of all I/O buffers + must be multiples of this value. Note that the filesystem block + size may be greater than the logical block size of the block device. + +If either of the above conditions is not met, then direct I/O on the +encrypted file will fall back to buffered I/O. + Implementation details ====================== diff --git a/Documentation/process/stable-kernel-rules.rst b/Documentation/process/stable-kernel-rules.rst index fbcb48bc2a9030caa28ebc04d8c24f305bb505bd..003c865e9c212342ecac53c42eddd6848077de4f 100644 --- a/Documentation/process/stable-kernel-rules.rst +++ b/Documentation/process/stable-kernel-rules.rst @@ -168,16 +168,7 @@ Trees - The finalized and tagged releases of all stable kernels can be found in separate branches per version at: - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git - - - The release candidate of all stable kernel versions can be found at: - - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git/ - - .. warning:: - The -stable-rc tree is a snapshot in time of the stable-queue tree and - will change frequently, hence will be rebased often. It should only be - used for testing purposes (e.g. to be consumed by CI systems). + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git Review committee diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 9b52f50a68542b932879f054bdd6b436ee7658a1..d25335993e55309d8c7799178231a251ec890e42 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -261,10 +261,6 @@ alc-sense-combo huawei-mbx-stereo Enable initialization verbs for Huawei MBX stereo speakers; might be risky, try this at your own risk -alc298-samsung-headphone - Samsung laptops with ALC298 -alc256-samsung-headphone - Samsung laptops with ALC256 ALC66x/67x/892 ============== diff --git a/Documentation/vm/index.rst b/Documentation/vm/index.rst index eff5fbd492d08fa68208771dcf8bf4751bec32af..9f80cc8a1cd9eb81efda1cb5246d324a4eb24917 100644 --- a/Documentation/vm/index.rst +++ b/Documentation/vm/index.rst @@ -41,6 +41,7 @@ descriptions of data structures and algorithms. ksm memory-model mmu_notifier + multigen_lru numa overcommit-accounting page_migration diff --git a/Documentation/vm/multigen_lru.rst b/Documentation/vm/multigen_lru.rst new file mode 100644 index 0000000000000000000000000000000000000000..8f6498002576c9f235ad9fd2a75863a0895d8f73 --- /dev/null +++ b/Documentation/vm/multigen_lru.rst @@ -0,0 +1,160 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +Multi-Gen LRU +============= +The multi-gen LRU is an alternative LRU implementation that optimizes +page reclaim and improves performance under memory pressure. Page +reclaim decides the kernel's caching policy and ability to overcommit +memory. It directly impacts the kswapd CPU usage and RAM efficiency. + +Design overview +=============== +Objectives +---------- +The design objectives are: + +* Good representation of access recency +* Try to profit from spatial locality +* Fast paths to make obvious choices +* Simple self-correcting heuristics + +The representation of access recency is at the core of all LRU +implementations. In the multi-gen LRU, each generation represents a +group of pages with similar access recency. Generations establish a +common frame of reference and therefore help make better choices, +e.g., between different memcgs on a computer or different computers in +a data center (for job scheduling). + +Exploiting spatial locality improves efficiency when gathering the +accessed bit. A rmap walk targets a single page and does not try to +profit from discovering a young PTE. A page table walk can sweep all +the young PTEs in an address space, but the address space can be too +large to make a profit. The key is to optimize both methods and use +them in combination. + +Fast paths reduce code complexity and runtime overhead. Unmapped pages +do not require TLB flushes; clean pages do not require writeback. +These facts are only helpful when other conditions, e.g., access +recency, are similar. With generations as a common frame of reference, +additional factors stand out. But obvious choices might not be good +choices; thus self-correction is required. + +The benefits of simple self-correcting heuristics are self-evident. +Again, with generations as a common frame of reference, this becomes +attainable. Specifically, pages in the same generation can be +categorized based on additional factors, and a feedback loop can +statistically compare the refault percentages across those categories +and infer which of them are better choices. + +Assumptions +----------- +The protection of hot pages and the selection of cold pages are based +on page access channels and patterns. There are two access channels: + +* Accesses through page tables +* Accesses through file descriptors + +The protection of the former channel is by design stronger because: + +1. The uncertainty in determining the access patterns of the former + channel is higher due to the approximation of the accessed bit. +2. The cost of evicting the former channel is higher due to the TLB + flushes required and the likelihood of encountering the dirty bit. +3. The penalty of underprotecting the former channel is higher because + applications usually do not prepare themselves for major page + faults like they do for blocked I/O. E.g., GUI applications + commonly use dedicated I/O threads to avoid blocking the rendering + threads. + +There are also two access patterns: + +* Accesses exhibiting temporal locality +* Accesses not exhibiting temporal locality + +For the reasons listed above, the former channel is assumed to follow +the former pattern unless ``VM_SEQ_READ`` or ``VM_RAND_READ`` is +present, and the latter channel is assumed to follow the latter +pattern unless outlying refaults have been observed. + +Workflow overview +================= +Evictable pages are divided into multiple generations for each +``lruvec``. The youngest generation number is stored in +``lrugen->max_seq`` for both anon and file types as they are aged on +an equal footing. The oldest generation numbers are stored in +``lrugen->min_seq[]`` separately for anon and file types as clean file +pages can be evicted regardless of swap constraints. These three +variables are monotonically increasing. + +Generation numbers are truncated into ``order_base_2(MAX_NR_GENS+1)`` +bits in order to fit into the gen counter in ``page->flags``. Each +truncated generation number is an index to ``lrugen->lists[]``. The +sliding window technique is used to track at least ``MIN_NR_GENS`` and +at most ``MAX_NR_GENS`` generations. The gen counter stores a value +within ``[1, MAX_NR_GENS]`` while a page is on one of +``lrugen->lists[]``; otherwise it stores zero. + +Each generation is divided into multiple tiers. Tiers represent +different ranges of numbers of accesses through file descriptors. A +page accessed ``N`` times through file descriptors is in tier +``order_base_2(N)``. In contrast to moving across generations, which +requires the LRU lock, moving across tiers only requires operations on +``page->flags`` and therefore has a negligible cost. A feedback loop +modeled after the PID controller monitors refaults over all the tiers +from anon and file types and decides which tiers from which types to +evict or protect. + +There are two conceptually independent procedures: the aging and the +eviction. They form a closed-loop system, i.e., the page reclaim. + +Aging +----- +The aging produces young generations. Given an ``lruvec``, it +increments ``max_seq`` when ``max_seq-min_seq+1`` approaches +``MIN_NR_GENS``. The aging promotes hot pages to the youngest +generation when it finds them accessed through page tables; the +demotion of cold pages happens consequently when it increments +``max_seq``. The aging uses page table walks and rmap walks to find +young PTEs. For the former, it iterates ``lruvec_memcg()->mm_list`` +and calls ``walk_page_range()`` with each ``mm_struct`` on this list +to scan PTEs. On finding a young PTE, it clears the accessed bit and +updates the gen counter of the page mapped by this PTE to +``(max_seq%MAX_NR_GENS)+1``. After each iteration of this list, it +increments ``max_seq``. For the latter, when the eviction walks the +rmap and finds a young PTE, the aging scans the adjacent PTEs and +follows the same steps just described. + +Eviction +-------- +The eviction consumes old generations. Given an ``lruvec``, it +increments ``min_seq`` when ``lrugen->lists[]`` indexed by +``min_seq%MAX_NR_GENS`` becomes empty. To select a type and a tier to +evict from, it first compares ``min_seq[]`` to select the older type. +If both types are equally old, it selects the one whose first tier has +a lower refault percentage. The first tier contains single-use +unmapped clean pages, which are the best bet. The eviction sorts a +page according to the gen counter if the aging has found this page +accessed through page tables and updated the gen counter. It also +moves a page to the next generation, i.e., ``min_seq+1``, if this page +was accessed multiple times through file descriptors and the feedback +loop has detected outlying refaults from the tier this page is in. To +do this, the feedback loop uses the first tier as the baseline, for +the reason stated earlier. + +Summary +------- +The multi-gen LRU can be disassembled into the following parts: + +* Generations +* Page table walks +* Rmap walks +* Bloom filters +* The PID controller + +The aging and the eviction is a producer-consumer model; specifically, +the latter drives the former by the sliding window over generations. +Within the aging, rmap walks drive page table walks by inserting hot +densely populated page tables to the Bloom filters. Within the +eviction, the PID controller uses refaults as the feedback to select +types to evict and tiers to protect. diff --git a/Makefile b/Makefile index 394463064862611baa147a738a837f712b3b0b02..e4517d58b89f0bd5bc7d852d30ac8db2c3945f20 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 PATCHLEVEL = 10 -SUBLEVEL = 110 +SUBLEVEL = 107 EXTRAVERSION = NAME = Dare mighty things diff --git a/android/abi_gki_aarch64.xml b/android/abi_gki_aarch64.xml index 9f3e735ec93d167b8590097cc086d0f07cc0cbf3..61944e90b46a5593f61796644929f7878330dfca 100644 --- a/android/abi_gki_aarch64.xml +++ b/android/abi_gki_aarch64.xml @@ -1,15 +1,17 @@ - - - + + + - - + + + + - + @@ -21,78 +23,79 @@ - - - - - + + + + + - - - - + + + + - - + + - - + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + - + - + - + - - - - - - - - - + + + + + + + + + @@ -101,7 +104,7 @@ - + @@ -113,83 +116,83 @@ - + - + - - - - + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + + @@ -197,67 +200,82 @@ - + + + - - - + + + - - + + + - - - + + + + - - - - + + + + + + - + - + + + + + - + - + + + - + - - - - + + + + + + - + + @@ -271,56 +289,56 @@ - - + + - - + + - - - - - + + + + + - + - - - + + + - - + + - + - - + + - + - - - - - - - - - - + + + + + + + + + + @@ -346,43 +364,42 @@ - + - + - - + + - + - - - - - + + + + + - - - + + + - + - - - - + + + + - - + @@ -393,28 +410,28 @@ - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - + + + + + + + + + @@ -422,184 +439,184 @@ - - + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -608,72 +625,71 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - + + - + - + - - - - - - + + + + + + - - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + @@ -681,34 +697,36 @@ - - - - - - - + + + + + + + - - - + + + - + - - + + - - + + - - - + + + + + @@ -716,373 +734,372 @@ - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1095,53 +1112,53 @@ - - - - - - - - + + + + + + + + - + - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - + + + + + + @@ -1152,132 +1169,132 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - + + + @@ -1286,261 +1303,262 @@ - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + - + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - + - - + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + + - - + + - + - + - + - + - - + + - - - - - - - + + + + + + + @@ -1553,101 +1571,112 @@ - - - + + + - - - - - - - + + + + + + + - - - + + + - + + - - - + + + - - - + + + + + + + + + + + + + + + + + + - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - + + + + + - + - - - - - - - + + + + + + + @@ -1656,71 +1685,71 @@ - - - - - + + + + + - - + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1733,12 +1762,11 @@ - - - + + - - + + @@ -1749,185 +1777,190 @@ - - - + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - + + + + + + - - + + - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + - + - - + + - + @@ -1935,49 +1968,49 @@ - - - - - + + + + + - + - - + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + - + @@ -1994,23 +2027,23 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - + + + @@ -2026,28 +2059,25 @@ - - - - - - + + - + - - - - - - - + + + + + + + + @@ -2068,89 +2098,89 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -2159,50 +2189,50 @@ - - - - - - + + + + + + - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + - + @@ -2211,310 +2241,315 @@ - - - - + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - + + - + @@ -2524,42 +2559,42 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + @@ -2582,112 +2617,112 @@ - - + + - - - - - + + + + + - + - + - + - - + + - - + + - + - - + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - - - - + + + + - - + + @@ -2698,404 +2733,394 @@ - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - - - - - - - - + + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - - - + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -3115,7 +3140,7 @@ - + @@ -3136,45 +3161,46 @@ - - - - + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - + - - - + + + - + @@ -3185,160 +3211,161 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - + + + + + - + - + - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - + + - - + + - - + + - - - - - - + + + + + + - - - - + + + + + - + - - - + + + - - - + + + - + @@ -3348,238 +3375,243 @@ - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + + - - - - - + + + + + - - + + - + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - + - + - - - + + + - - + + - - + + - - - + + + @@ -3592,30 +3624,30 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - + + @@ -3625,32 +3657,32 @@ - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -3661,6 +3693,7 @@ + @@ -3668,6 +3701,7 @@ + @@ -3678,60 +3712,72 @@ + + + + + + - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -3756,101 +3802,102 @@ - + - + - - + + + - + - + - - - + + + - + - - + - - + - - - - - - - + + + + + + + - + - + - - + + - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + - - + + - - + + @@ -3861,14 +3908,14 @@ - - + + - - - + + + @@ -4122,7 +4169,7 @@ - + @@ -4314,12 +4361,12 @@ - + - + - + @@ -4731,7 +4778,7 @@ - + @@ -5019,6 +5066,7 @@ + @@ -5600,41 +5648,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6308,12 +6321,12 @@ - + - + - + @@ -7021,24 +7034,24 @@ - + - + - + - + - + - + - + @@ -7379,7 +7392,6 @@ - @@ -7497,7 +7509,7 @@ - + @@ -8014,7 +8026,7 @@ - + @@ -8025,15 +8037,15 @@ - + - + - + - + @@ -8606,7 +8618,7 @@ - + @@ -9347,10 +9359,13 @@ - + - - + + + + + @@ -9409,12 +9424,12 @@ - + - + - + @@ -9579,6 +9594,7 @@ + @@ -10646,66 +10662,66 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -11394,7 +11410,7 @@ - + @@ -11414,6 +11430,7 @@ + @@ -11971,18 +11988,18 @@ - + - + - + - + - + @@ -12632,33 +12649,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -13246,7 +13263,6 @@ - @@ -13462,7 +13478,6 @@ - @@ -13550,6 +13565,7 @@ + @@ -14272,7 +14288,7 @@ - + @@ -14613,12 +14629,12 @@ - + - + - + @@ -14692,42 +14708,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -15343,12 +15359,12 @@ - + - + - + @@ -15988,21 +16004,15 @@ - - - - - - - + - + - + - + @@ -16989,21 +16999,21 @@ - + - + - + - + - + - + @@ -17704,6 +17714,7 @@ + @@ -17992,222 +18003,222 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -18859,21 +18870,21 @@ - + - + - + - + - + - + @@ -18894,7 +18905,7 @@ - + @@ -19854,7 +19865,6 @@ - @@ -20121,38 +20131,38 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -20475,7 +20485,6 @@ - @@ -20586,7 +20595,6 @@ - @@ -20736,12 +20744,12 @@ - + - + - - + + @@ -20760,57 +20768,57 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -20869,7 +20877,6 @@ - @@ -21207,6 +21214,10 @@ + + + + @@ -21433,7 +21444,7 @@ - + @@ -21448,7 +21459,7 @@ - + @@ -21470,15 +21481,6 @@ - - - - - - - - - @@ -21515,8 +21517,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -21735,12 +21766,12 @@ - + - + - + @@ -22165,10 +22196,6 @@ - - - - @@ -22196,18 +22223,18 @@ - + - + - + - + - + @@ -22235,15 +22262,15 @@ - + - + - + - + @@ -22282,87 +22309,87 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -22468,33 +22495,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -22754,6 +22781,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -23034,7 +23108,7 @@ - + @@ -24191,7 +24265,7 @@ - + @@ -24475,14 +24549,6 @@ - - - - - - - - @@ -24996,7 +25062,7 @@ - + @@ -25065,12 +25131,12 @@ - + - + - + @@ -25142,21 +25208,21 @@ - + - + - + - + - + - + @@ -27361,15 +27427,15 @@ - + - + - + - + @@ -27466,7 +27532,7 @@ - + @@ -27761,9 +27827,9 @@ - + - + @@ -27776,7 +27842,6 @@ - @@ -27842,7 +27907,7 @@ - + @@ -27852,30 +27917,30 @@ - + - + - + - + - + - + - + - + - + @@ -28431,24 +28496,24 @@ - + - + - + - + - + - + - + @@ -29199,12 +29264,6 @@ - - - - - - @@ -29842,7 +29901,7 @@ - + @@ -29988,12 +30047,6 @@ - - - - - - @@ -32449,7 +32502,7 @@ - + @@ -32696,96 +32749,99 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + - - + + - - + + - - + + - - + + @@ -33556,12 +33612,12 @@ - + - + - + @@ -33720,6 +33776,10 @@ + + + + @@ -33843,7 +33903,7 @@ - + @@ -33858,30 +33918,30 @@ - + - + - + - + - + - + - + - + - + @@ -34014,7 +34074,6 @@ - @@ -35175,7 +35234,7 @@ - + @@ -35532,36 +35591,39 @@ - + - + + + + - + - + - + - + - + - + - + - + @@ -35678,6 +35740,11 @@ + + + + + @@ -35828,7 +35895,6 @@ - @@ -36491,30 +36557,30 @@ - + - + - + - + - + - + - + - + - + @@ -36905,18 +36971,18 @@ - + - + - + - + - + @@ -37499,7 +37565,7 @@ - + @@ -38405,6 +38471,12 @@ + + + + + + @@ -38733,78 +38805,78 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -39228,9 +39300,9 @@ - + - + @@ -39365,24 +39437,24 @@ - + - + - + - + - + - + - + @@ -39392,21 +39464,21 @@ - + - + - + - + - + - + @@ -39610,15 +39682,15 @@ - + - + - + - + @@ -39629,6 +39701,14 @@ + + + + + + + + @@ -39707,7 +39787,6 @@ - @@ -39782,7 +39861,6 @@ - @@ -40695,7 +40773,7 @@ - + @@ -41024,7 +41102,7 @@ - + @@ -41501,24 +41579,24 @@ - + - + - + - + - + - + - + @@ -41952,18 +42030,18 @@ - + - + - + - + - + @@ -42187,6 +42265,11 @@ + + + + + @@ -42812,20 +42895,6 @@ - - - - - - - - - - - - - - @@ -42893,12 +42962,12 @@ - + - + - + @@ -43947,27 +44016,27 @@ - + - + - + - + - + - + - + - + @@ -44163,6 +44232,7 @@ + @@ -44803,54 +44873,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -45402,18 +45472,18 @@ - + - + - + - + - + @@ -45733,7 +45803,7 @@ - + @@ -45967,16 +46037,12 @@ - - - - - + @@ -46020,42 +46086,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -46078,13 +46144,13 @@ - + - + - + @@ -46093,7 +46159,7 @@ - + @@ -46218,54 +46284,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -46418,6 +46484,11 @@ + + + + + @@ -46667,12 +46738,12 @@ - + - + - + @@ -47450,11 +47521,21 @@ + + + + + + + + + + + + + + - - - - @@ -47616,12 +47697,6 @@ - - - - - - @@ -47934,7 +48009,7 @@ - + @@ -48089,15 +48164,18 @@ - + - + - + + + + @@ -48827,6 +48905,11 @@ + + + + + @@ -48984,20 +49067,17 @@ - - - - + - + - + - + @@ -49118,21 +49198,21 @@ - + - + - + - + - + - + @@ -49636,7 +49716,6 @@ - @@ -50025,15 +50104,15 @@ - + - + - + - + @@ -50974,36 +51053,36 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -51998,26 +52077,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -53473,24 +53532,24 @@ - + - + - + - + - + - + - + @@ -53675,12 +53734,6 @@ - - - - - - @@ -55382,11 +55435,6 @@ - - - - - @@ -55636,12 +55684,12 @@ - + - + - + @@ -55832,61 +55880,61 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -57454,9 +57502,6 @@ - - - @@ -57610,7 +57655,7 @@ - + @@ -58133,6 +58178,7 @@ + @@ -58198,7 +58244,6 @@ - @@ -58274,63 +58319,63 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -58775,6 +58820,7 @@ + @@ -58896,6 +58942,10 @@ + + + + @@ -58938,7 +58988,6 @@ - @@ -59284,7 +59333,7 @@ - + @@ -59355,7 +59404,6 @@ - @@ -59367,7 +59415,7 @@ - + @@ -59726,17 +59774,6 @@ - - - - - - - - - - - @@ -60607,15 +60644,15 @@ - + - + - + - + @@ -60886,7 +60923,7 @@ - + @@ -61115,6 +61152,7 @@ + @@ -61853,37 +61891,47 @@ - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + @@ -62504,7 +62552,6 @@ - @@ -62675,6 +62722,7 @@ + @@ -62689,6 +62737,11 @@ + + + + + @@ -62848,7 +62901,7 @@ - + @@ -62981,39 +63034,39 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -63100,7 +63153,7 @@ - + @@ -63381,21 +63434,21 @@ - + - + - + - + - + - + @@ -63426,50 +63479,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -63840,7 +63849,7 @@ - + @@ -64526,6 +64535,7 @@ + @@ -64691,25 +64701,25 @@ - + - + - + - + - + - + - + @@ -67163,7 +67173,7 @@ - + @@ -67171,7 +67181,7 @@ - + @@ -67203,7 +67213,7 @@ - + @@ -67230,7 +67240,7 @@ - + @@ -67241,7 +67251,7 @@ - + @@ -67270,7 +67280,7 @@ - + @@ -67278,7 +67288,7 @@ - + @@ -67286,10 +67296,10 @@ - + - + @@ -67316,10 +67326,10 @@ - + - + @@ -67360,7 +67370,7 @@ - + @@ -67368,7 +67378,7 @@ - + @@ -67384,10 +67394,10 @@ - + - + @@ -67499,16 +67509,16 @@ - + - + - + - + @@ -67578,7 +67588,7 @@ - + @@ -67589,10 +67599,10 @@ - + - + @@ -67717,18 +67727,18 @@ - + - + - + - + @@ -67805,7 +67815,7 @@ - + @@ -67854,7 +67864,7 @@ - + @@ -67870,7 +67880,7 @@ - + @@ -67987,15 +67997,15 @@ - + - + - + - + @@ -68037,15 +68047,15 @@ - + - + - + - + @@ -68245,87 +68255,87 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -68368,7 +68378,7 @@ - + @@ -68393,15 +68403,15 @@ - + - + - + @@ -68409,7 +68419,7 @@ - + @@ -68468,7 +68478,7 @@ - + @@ -68487,7 +68497,7 @@ - + @@ -68495,21 +68505,21 @@ - + - + - + - + - + @@ -68520,12 +68530,12 @@ - + - + - + @@ -68546,10 +68556,10 @@ - + - + @@ -68565,7 +68575,7 @@ - + @@ -68601,7 +68611,7 @@ - + @@ -68614,7 +68624,7 @@ - + @@ -68660,7 +68670,7 @@ - + @@ -68693,13 +68703,13 @@ - + - + - + @@ -68730,7 +68740,7 @@ - + @@ -68741,13 +68751,13 @@ - + - + @@ -68788,7 +68798,7 @@ - + @@ -68921,10 +68931,10 @@ - + - + @@ -68932,27 +68942,27 @@ - + - + - + - + - + - + - + @@ -68960,22 +68970,22 @@ - + - + - + - + - + - + @@ -69034,36 +69044,36 @@ - + - + - + - + - + - + - + - + - + - + @@ -69074,7 +69084,7 @@ - + @@ -69090,96 +69100,96 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -69192,13 +69202,13 @@ - + - + - + @@ -69332,7 +69342,7 @@ - + @@ -69373,11 +69383,6 @@ - - - - - @@ -69665,6 +69670,7 @@ + @@ -70504,14 +70510,8 @@ - - - - - - @@ -71089,6 +71089,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -72360,7 +72395,6 @@ - @@ -73069,7 +73103,7 @@ - + @@ -73092,6 +73126,7 @@ + @@ -73728,7 +73763,7 @@ - + @@ -74140,228 +74175,228 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -74375,15 +74410,15 @@ - + - + - + - + @@ -74396,7 +74431,6 @@ - @@ -74590,10 +74624,13 @@ - + + + + @@ -74653,10 +74690,6 @@ - - - - @@ -74968,12 +75001,12 @@ - + - + - + @@ -75749,409 +75782,412 @@ - + - + - + - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -76504,7 +76540,7 @@ - + @@ -76638,52 +76674,46 @@ - - - - + - - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -77276,12 +77306,12 @@ - + - + - + @@ -77487,117 +77517,117 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -77672,12 +77702,12 @@ - + - + - + @@ -77974,15 +78004,15 @@ - + - + - + - + @@ -78129,6 +78159,7 @@ + @@ -78927,21 +78958,21 @@ - + - + - + - + - + - + @@ -79379,6 +79410,7 @@ + @@ -79425,15 +79457,19 @@ - + + + + + - + - + - + @@ -80991,9 +81027,9 @@ - + - + @@ -81187,6 +81223,7 @@ + @@ -81267,21 +81304,21 @@ - + - + - + - + - + - + @@ -81617,18 +81654,18 @@ - + - + - + - + - + @@ -82146,12 +82183,12 @@ - + - + - + @@ -82257,7 +82294,7 @@ - + @@ -83034,7 +83071,7 @@ - + @@ -83447,15 +83484,15 @@ - + - + - + - + @@ -83658,7 +83695,7 @@ - + @@ -83738,22 +83775,22 @@ - + - + - + - + - + - + @@ -84597,7 +84634,12 @@ - + + + + + + @@ -84705,24 +84747,24 @@ - + - + - + - + - + - + - + @@ -85344,7 +85386,6 @@ - @@ -86124,15 +86165,15 @@ - + - + - + - + @@ -86445,27 +86486,27 @@ - + - + - + - + - + - + - + - + @@ -86892,12 +86933,12 @@ - + - + - + @@ -87211,21 +87252,21 @@ - + - + - + - + - + - + @@ -87278,36 +87319,36 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -87547,7 +87588,7 @@ - + @@ -88648,7 +88689,7 @@ - + @@ -89003,14 +89044,6 @@ - - - - - - - - @@ -89047,6 +89080,9 @@ + + + @@ -89330,7 +89366,7 @@ - + @@ -89949,63 +89985,63 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -90019,21 +90055,21 @@ - + - + - + - + - + - + @@ -90251,18 +90287,18 @@ - + - + - + - + - + @@ -90310,7 +90346,7 @@ - + @@ -90776,85 +90812,88 @@ - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -91417,12 +91456,12 @@ - + - + - + @@ -91436,7 +91475,7 @@ - + @@ -91792,51 +91831,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -92046,6 +92085,9 @@ + + + @@ -92466,21 +92508,21 @@ - + - + - + - + - + - + @@ -92909,15 +92951,15 @@ - + - + - + - + @@ -93085,7 +93127,6 @@ - @@ -93121,7 +93162,7 @@ - + @@ -93613,7 +93654,18 @@ - + + + + + + + + + + + + @@ -93621,7 +93673,7 @@ - + @@ -93629,7 +93681,7 @@ - + @@ -93637,7 +93689,7 @@ - + @@ -93645,7 +93697,7 @@ - + @@ -93653,7 +93705,7 @@ - + @@ -93661,7 +93713,7 @@ - + @@ -93708,7 +93760,7 @@ - + @@ -93719,7 +93771,7 @@ - + @@ -93739,7 +93791,7 @@ - + @@ -93762,7 +93814,7 @@ - + @@ -93782,26 +93834,26 @@ - + - + - + - + - + @@ -93815,7 +93867,7 @@ - + @@ -93823,7 +93875,7 @@ - + @@ -93843,7 +93895,7 @@ - + @@ -93866,7 +93918,7 @@ - + @@ -93874,7 +93926,7 @@ - + @@ -93882,7 +93934,7 @@ - + @@ -93890,7 +93942,7 @@ - + @@ -93898,7 +93950,7 @@ - + @@ -93924,17 +93976,17 @@ - + - + - + @@ -93942,17 +93994,17 @@ - + - + - + @@ -93972,7 +94024,7 @@ - + @@ -93980,7 +94032,7 @@ - + @@ -93988,7 +94040,7 @@ - + @@ -93996,12 +94048,12 @@ - + - + @@ -94009,7 +94061,7 @@ - + @@ -94017,7 +94069,7 @@ - + @@ -94031,7 +94083,7 @@ - + @@ -94072,7 +94124,7 @@ - + @@ -94089,17 +94141,6 @@ - - - - - - - - - - - @@ -94244,9 +94285,9 @@ - + - + @@ -94353,302 +94394,316 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + - + + + + + + + + + + + + @@ -94659,7 +94714,7 @@ - + @@ -94667,7 +94722,7 @@ - + @@ -94675,7 +94730,7 @@ - + @@ -94689,7 +94744,7 @@ - + @@ -94697,7 +94752,7 @@ - + @@ -94705,7 +94760,7 @@ - + @@ -94713,7 +94768,7 @@ - + @@ -94721,7 +94776,7 @@ - + @@ -94732,7 +94787,7 @@ - + @@ -94740,7 +94795,7 @@ - + @@ -94751,7 +94806,7 @@ - + @@ -94759,7 +94814,7 @@ - + @@ -94767,7 +94822,7 @@ - + @@ -94775,7 +94830,7 @@ - + @@ -94795,7 +94850,7 @@ - + @@ -94809,7 +94864,7 @@ - + @@ -94826,7 +94881,7 @@ - + @@ -94840,7 +94895,7 @@ - + @@ -94854,7 +94909,7 @@ - + @@ -94862,7 +94917,7 @@ - + @@ -94876,7 +94931,7 @@ - + @@ -94887,7 +94942,7 @@ - + @@ -94904,7 +94959,7 @@ - + @@ -94912,7 +94967,7 @@ - + @@ -94920,7 +94975,7 @@ - + @@ -94931,7 +94986,7 @@ - + @@ -94942,7 +94997,7 @@ - + @@ -94950,7 +95005,7 @@ - + @@ -94967,7 +95022,7 @@ - + @@ -94990,7 +95045,7 @@ - + @@ -94998,7 +95053,7 @@ - + @@ -95009,7 +95064,7 @@ - + @@ -95023,18 +95078,18 @@ - + - + - + @@ -95060,7 +95115,7 @@ - + @@ -95068,7 +95123,7 @@ - + @@ -95076,7 +95131,7 @@ - + @@ -95087,7 +95142,7 @@ - + @@ -95095,7 +95150,7 @@ - + @@ -95106,7 +95161,7 @@ - + @@ -95117,12 +95172,12 @@ - + - + @@ -95130,7 +95185,7 @@ - + @@ -95138,7 +95193,7 @@ - + @@ -95146,7 +95201,7 @@ - + @@ -95154,7 +95209,7 @@ - + @@ -95162,7 +95217,7 @@ - + @@ -95203,7 +95258,7 @@ - + @@ -95217,7 +95272,7 @@ - + @@ -95243,7 +95298,7 @@ - + @@ -95308,7 +95363,7 @@ - + @@ -95319,7 +95374,7 @@ - + @@ -95336,7 +95391,7 @@ - + @@ -95380,7 +95435,7 @@ - + @@ -95391,7 +95446,7 @@ - + @@ -95402,7 +95457,7 @@ - + @@ -95422,7 +95477,7 @@ - + @@ -95430,7 +95485,7 @@ - + @@ -95447,7 +95502,7 @@ - + @@ -95476,7 +95531,7 @@ - + @@ -95493,7 +95548,7 @@ - + @@ -95507,17 +95562,17 @@ - + - + - + @@ -95525,7 +95580,7 @@ - + @@ -95536,7 +95591,7 @@ - + @@ -95544,7 +95599,7 @@ - + @@ -95558,7 +95613,7 @@ - + @@ -95578,7 +95633,7 @@ - + @@ -95586,7 +95641,7 @@ - + @@ -95594,7 +95649,7 @@ - + @@ -95602,12 +95657,12 @@ - + - + @@ -95615,7 +95670,7 @@ - + @@ -95626,7 +95681,7 @@ - + @@ -95634,18 +95689,18 @@ - + - + - - + + @@ -95659,12 +95714,12 @@ - + - + @@ -95672,12 +95727,12 @@ - + - + @@ -95685,12 +95740,12 @@ - + - + @@ -95698,7 +95753,7 @@ - + @@ -95715,7 +95770,7 @@ - + @@ -95723,7 +95778,7 @@ - + @@ -95731,12 +95786,12 @@ - + - + @@ -95744,7 +95799,7 @@ - + @@ -95752,7 +95807,7 @@ - + @@ -95769,12 +95824,12 @@ - + - + @@ -95800,7 +95855,7 @@ - + @@ -95811,7 +95866,7 @@ - + @@ -95831,7 +95886,7 @@ - + @@ -95854,7 +95909,7 @@ - + @@ -95889,7 +95944,7 @@ - + @@ -95900,7 +95955,7 @@ - + @@ -95914,12 +95969,12 @@ - + - + @@ -95930,7 +95985,7 @@ - + @@ -95944,7 +95999,7 @@ - + @@ -95955,7 +96010,7 @@ - + @@ -95969,7 +96024,7 @@ - + @@ -95983,12 +96038,12 @@ - + - + @@ -95996,7 +96051,7 @@ - + @@ -96010,7 +96065,7 @@ - + @@ -96018,7 +96073,7 @@ - + @@ -96029,7 +96084,7 @@ - + @@ -96046,7 +96101,7 @@ - + @@ -96066,7 +96121,7 @@ - + @@ -96083,7 +96138,7 @@ - + @@ -96094,7 +96149,7 @@ - + @@ -96102,7 +96157,7 @@ - + @@ -96110,7 +96165,7 @@ - + @@ -96118,7 +96173,7 @@ - + @@ -96132,7 +96187,7 @@ - + @@ -96140,7 +96195,7 @@ - + @@ -96151,7 +96206,7 @@ - + @@ -96168,7 +96223,7 @@ - + @@ -96194,7 +96249,7 @@ - + @@ -96205,7 +96260,7 @@ - + @@ -96216,7 +96271,7 @@ - + @@ -96477,27 +96532,27 @@ - + - + - + - + - + - + - + - + @@ -96604,7 +96659,7 @@ - + @@ -96772,7 +96827,7 @@ - + @@ -96943,7 +96998,7 @@ - + @@ -98025,6 +98080,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -98684,12 +98774,12 @@ - + - + - + @@ -98825,7 +98915,6 @@ - @@ -99046,11 +99135,6 @@ - - - - - @@ -99696,6 +99780,29 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -100406,7 +100513,6 @@ - @@ -100687,12 +100793,12 @@ - + - + - + @@ -100842,7 +100948,7 @@ - + @@ -101126,27 +101232,27 @@ - + - + - + - + - + - + - + - + @@ -102486,10 +102592,6 @@ - - - - @@ -103443,6 +103545,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -103499,7 +103663,7 @@ - + @@ -103591,24 +103755,24 @@ - + - + - + - + - + - + - + @@ -104076,6 +104240,15 @@ + + + + + + + + + @@ -104104,9 +104277,9 @@ - + - + @@ -104386,7 +104559,6 @@ - @@ -104789,7 +104961,7 @@ - + @@ -105199,16 +105371,29 @@ + + + + + + + + + + + + + - - - - - + + + + + @@ -105271,34 +105456,34 @@ - - - - - + + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - + + + @@ -105606,6 +105791,11 @@ + + + + + @@ -105644,24 +105834,24 @@ - - + + - - - + + + - - - + + + - - - - + + + + @@ -105969,11 +106159,11 @@ - - - - - + + + + + @@ -105986,13 +106176,13 @@ - - - - - - - + + + + + + + @@ -106005,13 +106195,13 @@ - - - + + + - - + + @@ -106070,8 +106260,8 @@ - - + + @@ -106083,8 +106273,8 @@ - - + + @@ -106225,8 +106415,8 @@ - - + + @@ -106323,502 +106513,595 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - - - - + + + + + - - - - - - - - - - - + + + + + - - - + + + + - - - - + + + + + + - - - - - + + + + + + - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + - - - - - - + + + + + - - - - - - + + + + + - - - - + + + + + + - - - - - + + + + - - - - - + + + + - - - - - - + + + + - - - - + + + - - - - + + + + - - - + + + + - - - - + + + + - - - - + + + - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + - - - + + + - - - - + + + + - - - - - - + + + - - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + - - - - - - - - + + + + + + - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + + + - - - - - + + + - - - - + + + + - - - + + + + - - - + + + + - - - + + + + + - - - - - + + + + - - - - + + + + - - - - - - - + + + + - - - - - - - - + + + - - - - - + + + - - - - - - + + + - - - - + + + + + - - - - - + + + + - - - + + + + + + + - - - - + + + + - - - - + + + + + + + + - - - - - + + + - - - - - + + + + + - - - - - + + + + + + - - - - + + + + - - - - - + + + + + - - - - + + + - - - - + + + + - - - - - - + + + + - - - - - - + + + + + + - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - + + + + - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -106974,78 +107257,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -107094,9 +107391,9 @@ - - - + + + @@ -107142,12 +107439,12 @@ - - - - - - + + + + + + @@ -107318,7 +107615,7 @@ - + @@ -107352,9 +107649,9 @@ - - - + + + @@ -107450,17 +107747,17 @@ - - - + + + - - - - - - + + + + + + @@ -107505,13 +107802,6 @@ - - - - - - - @@ -108521,9 +108811,9 @@ - - - + + + @@ -108538,11 +108828,11 @@ - - - - - + + + + + @@ -108554,10 +108844,10 @@ - - - - + + + + @@ -108586,11 +108876,11 @@ - - - - - + + + + + @@ -108621,13 +108911,13 @@ - - - - - - - + + + + + + + @@ -108639,19 +108929,19 @@ - - - - - + + + + + - - - - - - + + + + + + @@ -108665,19 +108955,19 @@ - - - - - - + + + + + + - - - - - + + + + + @@ -108695,10 +108985,10 @@ - - - - + + + + @@ -108727,12 +109017,12 @@ - - - - - - + + + + + + @@ -108744,14 +109034,14 @@ - - - - + + + + - - + + @@ -108846,9 +109136,9 @@ - - - + + + @@ -108871,8 +109161,8 @@ - - + + @@ -108887,14 +109177,14 @@ - - - + + + - - - + + + @@ -108905,9 +109195,9 @@ - - - + + + @@ -108967,8 +109257,8 @@ - - + + @@ -109020,13 +109310,6 @@ - - - - - - - @@ -109041,9 +109324,9 @@ - - - + + + @@ -109123,11 +109406,12 @@ - - + + + - + @@ -109301,6 +109585,15 @@ + + + + + + + + + @@ -110485,11 +110778,6 @@ - - - - - @@ -110625,9 +110913,9 @@ - - - + + + @@ -110642,9 +110930,9 @@ - - - + + + @@ -110898,10 +111186,10 @@ - - - - + + + + @@ -111666,8 +111954,8 @@ - - + + @@ -111741,15 +112029,15 @@ - - - + + + - - - - + + + + @@ -112739,10 +113027,10 @@ - - - - + + + + @@ -113189,10 +113477,10 @@ - - - - + + + + @@ -113346,7 +113634,6 @@ - @@ -113483,7 +113770,7 @@ - + @@ -113491,13 +113778,13 @@ - - - + + + - - + + @@ -113543,6 +113830,11 @@ + + + + + @@ -113614,14 +113906,14 @@ - - - + + + - - - + + + @@ -113876,6 +114168,12 @@ + + + + + + @@ -113914,33 +114212,33 @@ - - + + - - - - - - + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -113950,38 +114248,89 @@ - - + + - - - - - + + + - - - + + + - - + + - - - - + + + + - - + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -114209,7 +114558,6 @@ - @@ -114692,12 +115040,6 @@ - - - - - - @@ -114765,8 +115107,8 @@ - - + + @@ -115214,12 +115556,12 @@ - - + + - - + + @@ -115242,16 +115584,16 @@ - - + + - - + + - - + + @@ -115263,6 +115605,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -115602,6 +115966,11 @@ + + + + + @@ -116229,24 +116598,6 @@ - - - - - - - - - - - - - - - - - - @@ -116547,14 +116898,14 @@ - - - - + + + + - - + + @@ -116649,8 +117000,8 @@ - - + + @@ -116731,8 +117082,8 @@ - - + + @@ -117038,36 +117389,36 @@ - - - - - - + + + + + + - - - + + + - - + + - - + + - - - - - + + + + + - - + + @@ -117174,11 +117525,22 @@ - - - + + + + + + + + + + + + + + @@ -117222,45 +117584,45 @@ - - - - + + + + - - - - + + + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -117268,14 +117630,14 @@ - - - + + + - - - + + + @@ -117799,14 +118161,14 @@ - - - - + + + + - - + + @@ -117884,8 +118246,8 @@ - - + + @@ -117896,12 +118258,12 @@ - - + + - - + + @@ -117916,12 +118278,12 @@ - - + + - - + + @@ -117937,10 +118299,10 @@ - - - - + + + + @@ -117948,20 +118310,20 @@ - - - + + + - - - + + + - - - - + + + + @@ -117985,9 +118347,9 @@ - - - + + + @@ -118003,9 +118365,9 @@ - - - + + + @@ -118018,14 +118380,14 @@ - - - + + + - - - + + + @@ -118033,36 +118395,44 @@ - - - - + + + + + + + + + + + + - - - - + + + + - - - - + + + + - - - + + + - - + + - - - + + + @@ -118075,21 +118445,21 @@ - - - - + + + + - - - + + + - - - - + + + + @@ -118100,26 +118470,26 @@ - - + + - - + + - - - + + + - - + + - - - + + + @@ -118127,8 +118497,8 @@ - - + + @@ -118139,27 +118509,27 @@ - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + @@ -118172,18 +118542,19 @@ - - - - + + + + - - - - + + + + + @@ -118203,12 +118574,12 @@ - - - - - - + + + + + + @@ -118249,20 +118620,20 @@ - - - - + + + + - - - - + + + + - - + + @@ -118282,8 +118653,8 @@ - - + + @@ -118327,29 +118698,29 @@ - - - - - - + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -118441,8 +118812,11 @@ - - + + + + + @@ -118450,8 +118824,14 @@ - - + + + + + + + + @@ -118723,13 +119103,13 @@ - - + + - - + + @@ -118884,8 +119264,8 @@ - - + + @@ -119055,6 +119435,7 @@ + @@ -119112,8 +119493,8 @@ - - + + @@ -119176,8 +119557,8 @@ - - + + @@ -119482,12 +119863,12 @@ - - - - - - + + + + + + @@ -119800,7 +120181,7 @@ - + @@ -119849,41 +120230,41 @@ - - + + - - + + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + @@ -120164,23 +120545,6 @@ - - - - - - - - - - - - - - - - - @@ -120254,40 +120618,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -120334,9 +120664,9 @@ - - - + + + @@ -120656,10 +120986,10 @@ - - - - + + + + @@ -120715,11 +121045,11 @@ - - - - - + + + + + @@ -120727,9 +121057,9 @@ - - - + + + @@ -120963,13 +121293,13 @@ - - - - - - - + + + + + + + @@ -121021,13 +121351,13 @@ - - - + + + - - + + @@ -121036,17 +121366,17 @@ - - - + + + - - - - - - + + + + + + @@ -121062,12 +121392,12 @@ - - - - - - + + + + + + @@ -121080,7 +121410,7 @@ - + @@ -121717,9 +122047,9 @@ - - - + + + @@ -121974,6 +122304,10 @@ + + + + @@ -122006,7 +122340,7 @@ - + @@ -122129,9 +122463,9 @@ - - - + + + @@ -122489,21 +122823,21 @@ - - - + + + - - - + + + - - - - - + + + + + @@ -122514,49 +122848,49 @@ - - - - - - + + + + + + - - + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - + + + - - + + @@ -122569,52 +122903,52 @@ - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - + + + + + - - + + @@ -122623,9 +122957,9 @@ - - - + + + @@ -122641,74 +122975,74 @@ - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -122719,15 +123053,15 @@ - - - - - + + + + + - - + + @@ -122805,8 +123139,8 @@ - - + + @@ -122845,8 +123179,8 @@ - - + + @@ -122892,6 +123226,14 @@ + + + + + + + + @@ -123018,6 +123360,10 @@ + + + + @@ -123037,8 +123383,16 @@ - - + + + + + + + + + + @@ -123046,8 +123400,8 @@ - - + + @@ -123066,6 +123420,12 @@ + + + + + + @@ -123148,6 +123508,14 @@ + + + + + + + + @@ -123367,9 +123735,9 @@ - - - + + + @@ -124065,16 +124433,16 @@ - - - - + + + + - - - - + + + + @@ -124121,28 +124489,28 @@ - - - - + + + + - - - - + + + + - - - - - + + + + + - - - + + + @@ -124198,18 +124566,17 @@ - - - + + + - - + + - - + @@ -124269,8 +124636,8 @@ - - + + @@ -124380,57 +124747,57 @@ - - - - + + + + - - + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - + + + - - - - + + + + - - - - - + + + + + @@ -124494,22 +124861,22 @@ - - - + + + - - + + - - + + - - - + + + @@ -124527,14 +124894,14 @@ - - - + + + - - - + + + @@ -124551,13 +124918,13 @@ - - + + - - - + + + @@ -124565,8 +124932,8 @@ - - + + diff --git a/android/abi_gki_aarch64_generic b/android/abi_gki_aarch64_generic index 14968c013c61a6aea8a5400632a09edc1e8411f9..d8bc7290f9bda70addc977ed3df4edc4c8307603 100644 --- a/android/abi_gki_aarch64_generic +++ b/android/abi_gki_aarch64_generic @@ -240,6 +240,7 @@ config_group_init_type_name config_item_init_type_name config_item_put + console_set_on_cmdline console_suspend_enabled console_trylock console_unlock @@ -285,6 +286,8 @@ cpuhp_tasks_frozen cpu_hwcap_keys cpu_hwcaps + cpuidle_driver_state_disabled + cpuidle_get_driver cpuidle_governor_latency_req cpuidle_pause_and_lock cpuidle_resume_and_unlock @@ -388,6 +391,7 @@ devfreq_update_interval dev_fwnode dev_get_by_name + dev_get_stats device_add device_add_disk device_add_groups @@ -567,6 +571,7 @@ dma_fence_remove_callback dma_fence_signal dma_fence_signal_locked + dma_fence_wait_timeout dma_free_attrs dma_free_noncoherent dma_get_sgtable_attrs @@ -769,6 +774,7 @@ drm_poll drm_prime_gem_destroy drm_printf + __drm_printfn_debug __drm_printfn_info __drm_printfn_seq_file drm_property_blob_get @@ -840,6 +846,7 @@ find_last_bit find_next_bit find_next_zero_bit + find_pid_ns find_task_by_vpid find_vma finish_wait @@ -896,6 +903,22 @@ get_device __get_free_pages get_governor_parent_kobj + gether_cleanup + gether_connect + gether_disconnect + gether_get_dev_addr + gether_get_host_addr + gether_get_host_addr_u8 + gether_get_ifname + gether_get_qmult + gether_register_netdev + gether_set_dev_addr + gether_set_gadget + gether_set_host_addr + gether_set_ifname + gether_set_qmult + gether_setup_name_default + get_pfnblock_flags_mask get_pid_task get_random_bytes get_random_bytes_arch @@ -990,6 +1013,7 @@ i2c_unregister_device i2c_verify_client ida_alloc_range + ida_destroy ida_free idr_alloc idr_alloc_cyclic @@ -1028,6 +1052,7 @@ input_mt_destroy_slots input_mt_init_slots input_mt_report_slot_state + input_mt_sync_frame input_open_device input_register_device input_register_handle @@ -1038,6 +1063,10 @@ input_unregister_device input_unregister_handle input_unregister_handler + interval_tree_insert + interval_tree_iter_first + interval_tree_iter_next + interval_tree_remove int_sqrt int_to_scsilun iomem_resource @@ -1088,7 +1117,9 @@ irq_create_mapping_affinity irq_create_of_mapping __irq_domain_add + irq_domain_get_irq_data irq_domain_remove + irq_domain_set_info irq_domain_xlate_twocell irq_find_mapping irq_get_irq_data @@ -1229,6 +1260,7 @@ mbox_free_channel mbox_request_channel mbox_send_message + memchr memcmp memcpy __memcpy_fromio @@ -1328,6 +1360,7 @@ nsec_to_clock_t ns_to_timespec64 __num_online_cpus + nvhe_hyp_panic_handler nvmem_device_put nvmem_device_read nvmem_device_write @@ -1422,7 +1455,7 @@ __page_frag_cache_drain page_frag_free page_mapping - __page_pinner_migration_failed + __page_pinner_put_page panic panic_notifier_list param_array_ops @@ -1456,6 +1489,8 @@ pci_irq_vector pci_load_and_free_saved_state pci_load_saved_state + pci_msi_mask_irq + pci_msi_unmask_irq pci_read_config_dword pci_read_config_word __pci_register_driver @@ -1474,6 +1509,7 @@ pci_write_config_dword pci_write_config_word PDE_DATA + pelt_load_avg_max __per_cpu_offset perf_aux_output_begin perf_aux_output_end @@ -1512,9 +1548,11 @@ pin_user_pages_fast pin_user_pages_remote pktgen_xfrm_outer_mode_output + pkvm_iommu_finalize pkvm_iommu_resume pkvm_iommu_s2mpu_register pkvm_iommu_suspend + pkvm_iommu_sysmmu_sync_register platform_bus_type platform_device_add platform_device_add_data @@ -1532,6 +1570,7 @@ platform_find_device_by_driver platform_get_irq platform_get_irq_byname + platform_get_irq_optional platform_get_resource platform_get_resource_byname platform_irq_count @@ -1653,6 +1692,7 @@ __rcu_read_unlock rdev_get_drvdata rdev_get_id + reboot_mode refcount_dec_not_one refcount_warn_saturate __refrigerator @@ -2044,6 +2084,7 @@ submit_bio submit_bio_wait subsys_system_register + suspend_set_ops __sw_hweight32 __sw_hweight64 sync_file_create @@ -2121,6 +2162,7 @@ _totalram_pages touch_softlockup_watchdog __trace_bprintk + __trace_bputs trace_event_buffer_commit trace_event_buffer_reserve trace_event_ignore_this_pid @@ -2128,6 +2170,7 @@ trace_event_reg trace_handle_return __traceiter_android_rvh_arm64_serror_panic + __traceiter_android_rvh_attach_entity_load_avg __traceiter_android_rvh_bad_mode __traceiter_android_rvh_cgroup_force_kthread_migration __traceiter_android_rvh_check_preempt_wakeup @@ -2135,6 +2178,7 @@ __traceiter_android_rvh_cpu_overutilized __traceiter_android_rvh_dequeue_task __traceiter_android_rvh_dequeue_task_fair + __traceiter_android_rvh_detach_entity_load_avg __traceiter_android_rvh_die_kernel_fault __traceiter_android_rvh_do_mem_abort __traceiter_android_rvh_do_sea @@ -2145,19 +2189,25 @@ __traceiter_android_rvh_find_energy_efficient_cpu __traceiter_android_rvh_irqs_disable __traceiter_android_rvh_irqs_enable + __traceiter_android_rvh_pci_d3_sleep __traceiter_android_rvh_post_init_entity_util_avg __traceiter_android_rvh_preempt_disable __traceiter_android_rvh_preempt_enable + __traceiter_android_rvh_remove_entity_load_avg __traceiter_android_rvh_sched_fork __traceiter_android_rvh_select_task_rq_fair __traceiter_android_rvh_select_task_rq_rt __traceiter_android_rvh_set_iowait + __traceiter_android_rvh_set_task_cpu __traceiter_android_rvh_typec_tcpci_chk_contaminant __traceiter_android_rvh_typec_tcpci_get_vbus __traceiter_android_rvh_uclamp_eff_get __traceiter_android_rvh_uclamp_rq_util_with __traceiter_android_rvh_ufs_complete_init __traceiter_android_rvh_ufs_reprogram_all_keys + __traceiter_android_rvh_update_blocked_fair + __traceiter_android_rvh_update_load_avg + __traceiter_android_rvh_update_rt_rq_load_avg __traceiter_android_rvh_util_est_update __traceiter_android_vh_arch_set_freq_scale __traceiter_android_vh_cma_alloc_finish @@ -2167,17 +2217,23 @@ __traceiter_android_vh_dup_task_struct __traceiter_android_vh_enable_thermal_genl_check __traceiter_android_vh_ep_create_wakeup_source + __traceiter_android_vh_get_user_pages + __traceiter_android_vh___get_user_pages_remote + __traceiter_android_vh_internal_get_user_pages_fast __traceiter_android_vh_ipi_stop __traceiter_android_vh_meminfo_proc_show __traceiter_android_vh_of_i2c_get_board_info __traceiter_android_vh_pagecache_get_page + __traceiter_android_vh_pin_user_pages __traceiter_android_vh_rmqueue + __traceiter_android_vh_scheduler_tick __traceiter_android_vh_setscheduler_uclamp __traceiter_android_vh_snd_compr_use_pause_in_drain __traceiter_android_vh_sound_usb_support_cpu_suspend __traceiter_android_vh_sysrq_crash __traceiter_android_vh_thermal_pm_notify_suspend __traceiter_android_vh_timerfd_create + __traceiter_android_vh_try_grab_compound_head __traceiter_android_vh_typec_store_partner_src_caps __traceiter_android_vh_typec_tcpci_override_toggling __traceiter_android_vh_typec_tcpm_get_timer @@ -2218,6 +2274,7 @@ __traceiter_suspend_resume trace_output_call __tracepoint_android_rvh_arm64_serror_panic + __tracepoint_android_rvh_attach_entity_load_avg __tracepoint_android_rvh_bad_mode __tracepoint_android_rvh_cgroup_force_kthread_migration __tracepoint_android_rvh_check_preempt_wakeup @@ -2225,6 +2282,7 @@ __tracepoint_android_rvh_cpu_overutilized __tracepoint_android_rvh_dequeue_task __tracepoint_android_rvh_dequeue_task_fair + __tracepoint_android_rvh_detach_entity_load_avg __tracepoint_android_rvh_die_kernel_fault __tracepoint_android_rvh_do_mem_abort __tracepoint_android_rvh_do_sea @@ -2235,19 +2293,25 @@ __tracepoint_android_rvh_find_energy_efficient_cpu __tracepoint_android_rvh_irqs_disable __tracepoint_android_rvh_irqs_enable + __tracepoint_android_rvh_pci_d3_sleep __tracepoint_android_rvh_post_init_entity_util_avg __tracepoint_android_rvh_preempt_disable __tracepoint_android_rvh_preempt_enable + __tracepoint_android_rvh_remove_entity_load_avg __tracepoint_android_rvh_sched_fork __tracepoint_android_rvh_select_task_rq_fair __tracepoint_android_rvh_select_task_rq_rt __tracepoint_android_rvh_set_iowait + __tracepoint_android_rvh_set_task_cpu __tracepoint_android_rvh_typec_tcpci_chk_contaminant __tracepoint_android_rvh_typec_tcpci_get_vbus __tracepoint_android_rvh_uclamp_eff_get __tracepoint_android_rvh_uclamp_rq_util_with __tracepoint_android_rvh_ufs_complete_init __tracepoint_android_rvh_ufs_reprogram_all_keys + __tracepoint_android_rvh_update_blocked_fair + __tracepoint_android_rvh_update_load_avg + __tracepoint_android_rvh_update_rt_rq_load_avg __tracepoint_android_rvh_util_est_update __tracepoint_android_vh_arch_set_freq_scale __tracepoint_android_vh_cma_alloc_finish @@ -2257,17 +2321,23 @@ __tracepoint_android_vh_dup_task_struct __tracepoint_android_vh_enable_thermal_genl_check __tracepoint_android_vh_ep_create_wakeup_source + __tracepoint_android_vh_get_user_pages + __tracepoint_android_vh___get_user_pages_remote + __tracepoint_android_vh_internal_get_user_pages_fast __tracepoint_android_vh_ipi_stop __tracepoint_android_vh_meminfo_proc_show __tracepoint_android_vh_of_i2c_get_board_info __tracepoint_android_vh_pagecache_get_page + __tracepoint_android_vh_pin_user_pages __tracepoint_android_vh_rmqueue + __tracepoint_android_vh_scheduler_tick __tracepoint_android_vh_setscheduler_uclamp __tracepoint_android_vh_snd_compr_use_pause_in_drain __tracepoint_android_vh_sound_usb_support_cpu_suspend __tracepoint_android_vh_sysrq_crash __tracepoint_android_vh_thermal_pm_notify_suspend __tracepoint_android_vh_timerfd_create + __tracepoint_android_vh_try_grab_compound_head __tracepoint_android_vh_typec_store_partner_src_caps __tracepoint_android_vh_typec_tcpci_override_toggling __tracepoint_android_vh_typec_tcpm_get_timer @@ -2377,26 +2447,37 @@ unregister_virtio_driver up update_devfreq + ___update_load_avg __update_load_avg_blocked_se + ___update_load_sum update_rq_clock up_read up_write usb_add_function usb_add_hcd + usb_assign_descriptors usb_copy_descriptors __usb_create_hcd usb_disabled usb_enable_autosuspend + usb_ep_alloc_request usb_ep_autoconfig usb_ep_disable usb_ep_enable + usb_ep_free_request + usb_ep_queue + usb_free_all_descriptors usb_function_register usb_function_unregister + usb_gadget_activate + usb_gadget_deactivate usb_gadget_set_state + usb_gstrings_attach usb_hcd_is_primary_hcd usb_hcd_platform_shutdown usb_hub_find_child usb_interface_id + usb_os_desc_prepare_interf_dir usb_otg_state_string usb_put_function_instance usb_put_hcd diff --git a/android/abi_gki_aarch64_hikey960 b/android/abi_gki_aarch64_hikey960 index 0609f21fcd3b7c8079188e9df073b25d77ccf4b5..eb9e5e380990982b0f7f73c8ae34f204bfd5e0b3 100644 --- a/android/abi_gki_aarch64_hikey960 +++ b/android/abi_gki_aarch64_hikey960 @@ -791,7 +791,6 @@ of_get_next_available_child of_parse_phandle of_property_read_u64 - __page_pinner_migration_failed __put_page put_unused_fd rb_erase diff --git a/android/abi_gki_aarch64_virtual_device b/android/abi_gki_aarch64_virtual_device index 932cb8b3520d74d285131af65ff4dde3ca3a20ab..9968c643ed6bdfb5a4626ac2cc303a2156c054b1 100644 --- a/android/abi_gki_aarch64_virtual_device +++ b/android/abi_gki_aarch64_virtual_device @@ -28,9 +28,6 @@ bt_warn cancel_delayed_work_sync cancel_work_sync - capable - cfg80211_inform_bss_data - cfg80211_put_bss __cfi_slowpath __check_object_size __class_create @@ -62,15 +59,12 @@ delayed_work_timer_fn del_gendisk del_timer - del_timer_sync destroy_workqueue dev_close _dev_err device_add_disk device_create - device_initialize device_init_wakeup - device_register device_release_driver device_unregister _dev_info @@ -82,7 +76,6 @@ devm_request_threaded_irq _dev_notice dev_queue_xmit - dev_set_name _dev_warn dma_alloc_attrs dma_buf_export @@ -96,7 +89,6 @@ dma_set_mask dma_sync_sg_for_device dma_unmap_sg_attrs - down_read down_write ether_setup ethtool_op_get_link @@ -123,14 +115,8 @@ hci_recv_frame hci_register_dev hci_unregister_dev - hwrng_register - hwrng_unregister ida_alloc_range ida_free - idr_alloc - idr_destroy - idr_remove - __init_rwsem __init_swait_queue_head init_timer_key init_wait_entry @@ -160,12 +146,10 @@ kmem_cache_free kmemdup kobject_uevent - krealloc kstrdup kstrndup kstrtoint kstrtouint - kstrtoull ktime_get ktime_get_mono_fast_ns ktime_get_raw_ts64 @@ -184,13 +168,10 @@ memcpy memmove memparse - memremap memset memstart_addr - memunmap misc_deregister misc_register - mod_timer module_layout module_put __msecs_to_jiffies @@ -216,15 +197,11 @@ nf_conntrack_destroy no_llseek nonseekable_open - noop_llseek nr_cpu_ids __num_online_cpus - of_find_property - of_get_property of_property_read_variable_u32_array - __page_pinner_migration_failed + __page_pinner_put_page param_ops_bool - param_ops_charp param_ops_int param_ops_uint passthru_features_check @@ -250,11 +227,8 @@ platform_get_irq platform_get_resource pm_runtime_allow - __pm_runtime_disable - pm_runtime_enable pm_runtime_force_resume pm_runtime_force_suspend - __pm_runtime_idle __pm_runtime_resume pm_runtime_set_autosuspend_delay __pm_runtime_suspend @@ -305,9 +279,7 @@ schedule schedule_timeout scnprintf - seq_lseek seq_printf - seq_read serio_close serio_interrupt serio_open @@ -330,7 +302,6 @@ snd_card_free snd_card_new snd_card_register - snd_ctl_enum_info snd_ctl_sync_vmaster snd_device_new snd_jack_new @@ -355,13 +326,11 @@ strncmp strncpy strscpy - strsep sync_file_create synchronize_rcu sysfs_create_group __sysfs_match_string sysfs_remove_group - sysfs_remove_link system_wq trace_event_buffer_commit trace_event_buffer_reserve @@ -385,7 +354,6 @@ unregister_netdevice_queue unregister_virtio_device unregister_virtio_driver - up_read up_write usb_alloc_urb usb_anchor_urb @@ -396,7 +364,6 @@ usb_register_driver usb_submit_urb usb_unanchor_urb - __usecs_to_jiffies usleep_range vabits_actual vfree @@ -457,10 +424,12 @@ mmc_remove_host mmc_request_done mmc_send_tuning + of_get_property pinctrl_lookup_state pinctrl_pm_select_sleep_state pinctrl_select_default_state pinctrl_select_state + __pm_runtime_idle regulator_disable regulator_enable reset_control_assert @@ -525,26 +494,9 @@ netdev_master_upper_dev_link rtnl_is_locked -# required by gnss-cmdline.ko - bus_find_device - device_find_child - device_match_name - platform_bus_type - strstr - -# required by gnss-serial.ko - gnss_allocate_device - gnss_deregister_device - gnss_insert_raw - gnss_put_device - gnss_register_device - serdev_device_close - serdev_device_open - serdev_device_set_baudrate - serdev_device_set_flow_control - serdev_device_wait_until_sent - serdev_device_write - serdev_device_write_wakeup +# required by goldfish_address_space.ko + memremap + memunmap # required by goldfish_battery.ko power_supply_changed @@ -584,12 +536,6 @@ skb_queue_head skb_queue_purge -# required by ledtrig-audio.ko - led_set_brightness_nosleep - led_trigger_event - led_trigger_register - led_trigger_unregister - # required by lzo-rle.ko lzorle1x_1_compress @@ -699,11 +645,15 @@ # required by open-dice.ko devm_memremap devm_memunmap + of_reserved_mem_lookup + __platform_driver_probe + simple_read_from_buffer vm_iomap_memory # required by psmouse.ko bus_register_notifier bus_unregister_notifier + del_timer_sync device_add_groups device_create_file device_remove_file @@ -724,6 +674,7 @@ input_set_capability kstrtobool kstrtou8 + mod_timer ps2_begin_command ps2_cmd_aborted ps2_command @@ -737,6 +688,7 @@ serio_rescan serio_unregister_child_port strcasecmp + strsep # required by pulse8-cec.ko cec_allocate_adapter @@ -759,6 +711,7 @@ rtc_update_irq # required by slcan.ko + capable hex_asc_upper hex_to_bin msleep_interruptible @@ -769,7 +722,6 @@ # required by snd-hda-codec-generic.ko _ctype - devm_led_classdev_register_ext snd_ctl_boolean_stereo_info strlcat __sw_hweight32 @@ -783,6 +735,8 @@ get_device_system_crosststamp kvasprintf ns_to_timespec64 + __pm_runtime_disable + pm_runtime_enable pm_runtime_forbid __printk_ratelimit regcache_mark_dirty @@ -794,6 +748,7 @@ snd_ctl_add_vmaster_hook snd_ctl_apply_vmaster_followers snd_ctl_boolean_mono_info + snd_ctl_enum_info snd_ctl_find_id snd_ctl_make_virtual_master snd_ctl_new1 @@ -817,11 +772,14 @@ bus_unregister device_add device_del + device_initialize + dev_set_name kasprintf kobject_add kobject_create_and_add kobject_init kobject_put + krealloc pm_runtime_get_if_active __pm_runtime_set_status prepare_to_wait @@ -840,6 +798,7 @@ param_array_ops param_get_int param_ops_bint + param_ops_charp param_set_int pci_dev_put pci_disable_msi @@ -873,35 +832,6 @@ vmap vunmap -# required by tpm.ko - alloc_chrdev_region - cdev_device_add - cdev_device_del - cdev_init - compat_only_sysfs_link_entry_to_kobj - devm_add_action - efi - efi_tpm_final_log_size - hash_digest_size - idr_get_next - idr_replace - jiffies_to_usecs - memchr_inv - of_property_match_string - pm_suspend_global_flags - securityfs_create_dir - securityfs_create_file - securityfs_remove - seq_open - seq_putc - seq_release - seq_write - unregister_chrdev_region - -# required by tpm_vtpm_proxy.ko - anon_inode_getfile - compat_ptr_ioctl - # required by usbip-core.ko iov_iter_kvec param_ops_ulong @@ -917,10 +847,12 @@ devres_free of_device_is_compatible of_find_compatible_node + of_find_property of_get_next_parent of_parse_phandle of_platform_populate of_root + __usecs_to_jiffies # required by vexpress-sysreg.ko bgpio_init @@ -937,6 +869,7 @@ platform_bus platform_device_add_data sockfd_lookup + sysfs_remove_link usb_add_hcd usb_create_hcd usb_create_shared_hcd @@ -958,6 +891,8 @@ # required by virt_wifi.ko cfg80211_connect_done cfg80211_disconnected + cfg80211_inform_bss_data + cfg80211_put_bss cfg80211_scan_done __dev_get_by_index dev_printk @@ -970,9 +905,6 @@ wiphy_register wiphy_unregister -# required by virt_wifi_sim.ko - ieee80211_get_channel_khz - # required by virtio-gpu.ko __devm_request_region dma_fence_match_context @@ -1090,6 +1022,7 @@ is_vmalloc_addr kmalloc_order_trace memdup_user + noop_llseek seq_puts sync_file_get_fence __traceiter_dma_fence_emit @@ -1102,6 +1035,8 @@ ww_mutex_unlock # required by virtio-rng.ko + hwrng_register + hwrng_unregister wait_for_completion_killable # required by virtio_blk.ko @@ -1151,6 +1086,8 @@ pipe_unlock __refrigerator __register_chrdev + seq_lseek + seq_read single_open single_release __splice_from_pipe @@ -1159,6 +1096,7 @@ # required by virtio_mmio.ko device_for_each_child + device_register devm_platform_ioremap_resource platform_device_register_full @@ -1307,16 +1245,23 @@ crypto_has_alg disk_end_io_acct disk_start_io_acct + down_read flush_dcache_page free_percpu fsync_bdev + idr_alloc + idr_destroy idr_find idr_for_each + idr_remove + __init_rwsem kstrtou16 + kstrtoull memset64 mutex_is_locked page_endio sysfs_streq + up_read vzalloc # required by zsmalloc.ko @@ -1339,3 +1284,4 @@ register_shrinker __SetPageMovable unregister_shrinker + diff --git a/arch/Kconfig b/arch/Kconfig index 9528d0bd544dd94825f9a3c0af8be0498b55a9df..d39f92e9cf51e0de0d30aa88571baebe90b03ce8 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1180,6 +1180,15 @@ config ARCH_SPLIT_ARG64 If a 32-bit architecture requires 64-bit arguments to be split into pairs of 32-bit arguments, select this option. +config ARCH_HAS_NONLEAF_PMD_YOUNG + bool + depends on PGTABLE_LEVELS > 2 + help + Architectures that select this option are capable of setting the + accessed bit in non-leaf PMD entries when using them as part of linear + address translations. Page table walkers that clear the accessed bit + may use this capability to reduce their search space. + source "kernel/gcov/Kconfig" source "scripts/gcc-plugins/Kconfig" diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index a85e9c625ab50b693337ad1ebbf1f5b36372b68f..37f724ad5e3992297b4513bc7498bd4e981cdac7 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -43,7 +43,7 @@ SYSCALL_DEFINE0(arc_gettls) return task_thread_info(current)->thr_ptr; } -SYSCALL_DEFINE3(arc_usr_cmpxchg, int __user *, uaddr, int, expected, int, new) +SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new) { struct pt_regs *regs = current_pt_regs(); u32 uval; diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index b50229c3102fabe58d02ab4f027de282883726cd..e46a3f4ad350a54815d6570aec357566fd387a16 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -433,26 +433,12 @@ #size-cells = <0>; enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit - /* Source for d/i-cache-line-size and d/i-cache-sets - * https://developer.arm.com/documentation/100095/0003 - * /Level-1-Memory-System/About-the-L1-memory-system?lang=en - * Source for d/i-cache-size - * https://www.raspberrypi.com/documentation/computers - * /processors.html#bcm2711 - */ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000d8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; }; cpu1: cpu@1 { @@ -461,13 +447,6 @@ reg = <1>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; }; cpu2: cpu@2 { @@ -476,13 +455,6 @@ reg = <2>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; }; cpu3: cpu@3 { @@ -491,28 +463,6 @@ reg = <3>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000f0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - i-cache-size = <0xc000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 48KiB(size)/64(line-size)=768ways/3-way set - next-level-cache = <&l2>; - }; - - /* Source for d/i-cache-line-size and d/i-cache-sets - * https://developer.arm.com/documentation/100095/0003 - * /Level-2-Memory-System/About-the-L2-memory-system?lang=en - * Source for d/i-cache-size - * https://www.raspberrypi.com/documentation/computers - * /processors.html#bcm2711 - */ - l2: l2-cache0 { - compatible = "cache"; - cache-size = <0x100000>; - cache-line-size = <64>; - cache-sets = <1024>; // 1MiB(size)/64(line-size)=16384ways/16-way set - cache-level = <2>; }; }; diff --git a/arch/arm/boot/dts/bcm2837.dtsi b/arch/arm/boot/dts/bcm2837.dtsi index 5dbdebc4625946a266d2c3f1719256086d5a2a59..0199ec98cd61690ad964c1bbe782fcf64583b236 100644 --- a/arch/arm/boot/dts/bcm2837.dtsi +++ b/arch/arm/boot/dts/bcm2837.dtsi @@ -40,26 +40,12 @@ #size-cells = <0>; enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit - /* Source for d/i-cache-line-size and d/i-cache-sets - * https://developer.arm.com/documentation/ddi0500/e/level-1-memory-system - * /about-the-l1-memory-system?lang=en - * - * Source for d/i-cache-size - * https://magpi.raspberrypi.com/articles/raspberry-pi-3-specs-benchmarks - */ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000d8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; }; cpu1: cpu@1 { @@ -68,13 +54,6 @@ reg = <1>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; }; cpu2: cpu@2 { @@ -83,13 +62,6 @@ reg = <2>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000e8>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; }; cpu3: cpu@3 { @@ -98,27 +70,6 @@ reg = <3>; enable-method = "spin-table"; cpu-release-addr = <0x0 0x000000f0>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; // 32KiB(size)/64(line-size)=512ways/4-way set - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <256>; // 32KiB(size)/64(line-size)=512ways/2-way set - next-level-cache = <&l2>; - }; - - /* Source for cache-line-size + cache-sets - * https://developer.arm.com/documentation/ddi0500 - * /e/level-2-memory-system/about-the-l2-memory-system?lang=en - * Source for cache-size - * https://datasheets.raspberrypi.com/cm/cm1-and-cm3-datasheet.pdf - */ - l2: l2-cache0 { - compatible = "cache"; - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; // 512KiB(size)/64(line-size)=8192ways/16-way set - cache-level = <2>; }; }; }; diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi index f8c0eee7a62b99728989a68d867e3c0d0282528a..30b72f4318501181c543dd028971d5eccf40c567 100644 --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -3448,7 +3448,8 @@ ti,timer-pwm; }; }; - timer15_target: target-module@2c000 { /* 0x4882c000, ap 17 02.0 */ + + target-module@2c000 { /* 0x4882c000, ap 17 02.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; reg = <0x2c000 0x4>, <0x2c010 0x4>; @@ -3476,7 +3477,7 @@ }; }; - timer16_target: target-module@2e000 { /* 0x4882e000, ap 19 14.0 */ + target-module@2e000 { /* 0x4882e000, ap 19 14.0 */ compatible = "ti,sysc-omap4-timer", "ti,sysc"; reg = <0x2e000 0x4>, <0x2e010 0x4>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 9989321366560fd2f03d6837c8d63192a1dbf4c3..7ecf8f86ac747ce2c4af9cd1d17d82937509a19a 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1093,20 +1093,20 @@ }; /* Local timers, see ARM architected timer wrap erratum i940 */ -&timer15_target { +&timer3_target { ti,no-reset-on-init; ti,no-idle; timer@0 { - assigned-clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER15_CLKCTRL 24>; + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER3_CLKCTRL 24>; assigned-clock-parents = <&timer_sys_clk_div>; }; }; -&timer16_target { +&timer4_target { ti,no-reset-on-init; ti,no-idle; timer@0 { - assigned-clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER16_CLKCTRL 24>; + assigned-clocks = <&l4per_clkctrl DRA7_L4PER_TIMER4_CLKCTRL 24>; assigned-clock-parents = <&timer_sys_clk_div>; }; }; diff --git a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi index d7d756614edd1f27e125bd7b791a8ae196eba99b..d31a68672bfacb3a2f6575c26790db05b5498d6c 100644 --- a/arch/arm/boot/dts/exynos5250-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos5250-pinctrl.dtsi @@ -260,7 +260,7 @@ }; uart3_data: uart3-data { - samsung,pins = "gpa1-4", "gpa1-5"; + samsung,pins = "gpa1-4", "gpa1-4"; samsung,pin-function = ; samsung,pin-pud = ; samsung,pin-drv = ; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 572198b6834e6b2aecee01a121fce38a1d97761a..d0e48c10aec2bfc0624baf8417b3a2d7b242a551 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -118,9 +118,6 @@ status = "okay"; ddc = <&i2c_2>; hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>; - vdd-supply = <&ldo8_reg>; - vdd_osc-supply = <&ldo10_reg>; - vdd_pll-supply = <&ldo8_reg>; }; &i2c_0 { diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index 741294bd564e7f455baacbc31fba2bc324ef12e5..4e49d8095b2927d8d31849916d1bee1637824429 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -124,9 +124,6 @@ hpd-gpios = <&gpx3 7 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&hdmi_hpd_irq>; - vdd-supply = <&ldo6_reg>; - vdd_osc-supply = <&ldo7_reg>; - vdd_pll-supply = <&ldo6_reg>; }; &hsi2c_4 { diff --git a/arch/arm/boot/dts/imx53-m53menlo.dts b/arch/arm/boot/dts/imx53-m53menlo.dts index d5c68d1ea707c6610ff1ef2b1c3bb9883ad5e803..4f88e96d81ddbdd42078409d0a94e43f3e194566 100644 --- a/arch/arm/boot/dts/imx53-m53menlo.dts +++ b/arch/arm/boot/dts/imx53-m53menlo.dts @@ -53,31 +53,6 @@ }; }; - lvds-decoder { - compatible = "ti,ds90cf364a", "lvds-decoder"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - lvds_decoder_in: endpoint { - remote-endpoint = <&lvds0_out>; - }; - }; - - port@1 { - reg = <1>; - - lvds_decoder_out: endpoint { - remote-endpoint = <&panel_in>; - }; - }; - }; - }; - panel { compatible = "edt,etm0700g0dh6"; pinctrl-0 = <&pinctrl_display_gpio>; @@ -86,7 +61,7 @@ port { panel_in: endpoint { - remote-endpoint = <&lvds_decoder_out>; + remote-endpoint = <&lvds0_out>; }; }; }; @@ -475,7 +450,7 @@ reg = <2>; lvds0_out: endpoint { - remote-endpoint = <&lvds_decoder_in>; + remote-endpoint = <&panel_in>; }; }; }; diff --git a/arch/arm/boot/dts/imx7-colibri.dtsi b/arch/arm/boot/dts/imx7-colibri.dtsi index f1c60b0cb143edad66f9376f34b0a856bfc86187..62b771c1d5a9a71058dfb478a6f6f14b4641dbaa 100644 --- a/arch/arm/boot/dts/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/imx7-colibri.dtsi @@ -40,7 +40,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&codec>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -293,7 +293,7 @@ compatible = "fsl,sgtl5000"; #sound-dai-cells = <0>; reg = <0x0a>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai1_mclk>; VDDA-supply = <®_module_3v3_avdd>; diff --git a/arch/arm/boot/dts/imx7-mba7.dtsi b/arch/arm/boot/dts/imx7-mba7.dtsi index 887497e3bb4b8ff0e608835bc01bfe86ec07a78f..50abf18ad30b20dc530c3b558d19956e98443c2f 100644 --- a/arch/arm/boot/dts/imx7-mba7.dtsi +++ b/arch/arm/boot/dts/imx7-mba7.dtsi @@ -250,7 +250,7 @@ tlv320aic32x4: audio-codec@18 { compatible = "ti,tlv320aic32x4"; reg = <0x18>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; clock-names = "mclk"; ldoin-supply = <®_audio_3v3>; iov-supply = <®_audio_3v3>; diff --git a/arch/arm/boot/dts/imx7d-nitrogen7.dts b/arch/arm/boot/dts/imx7d-nitrogen7.dts index a31de900139d6d10f0c849756bbf95e83ec5157d..e0751e6ba3c0f7e0d4709a5c1106eaeb7ab4f33b 100644 --- a/arch/arm/boot/dts/imx7d-nitrogen7.dts +++ b/arch/arm/boot/dts/imx7d-nitrogen7.dts @@ -288,7 +288,7 @@ codec: wm8960@1a { compatible = "wlf,wm8960"; reg = <0x1a>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; clock-names = "mclk"; wlf,shared-lrclk; }; diff --git a/arch/arm/boot/dts/imx7d-pico-hobbit.dts b/arch/arm/boot/dts/imx7d-pico-hobbit.dts index d917dc4f2f22759bc546c18248bbff7fcc3d726f..7b2198a9372c621e0276bd509c3b373cf02c4072 100644 --- a/arch/arm/boot/dts/imx7d-pico-hobbit.dts +++ b/arch/arm/boot/dts/imx7d-pico-hobbit.dts @@ -31,7 +31,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&sgtl5000>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -41,7 +41,7 @@ #sound-dai-cells = <0>; reg = <0x0a>; compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_vref_1v8>; }; diff --git a/arch/arm/boot/dts/imx7d-pico-pi.dts b/arch/arm/boot/dts/imx7d-pico-pi.dts index f263e391e24cbb6c44d569cf284dde74020f58ac..70bea95c06d83f84737d13478d1d7b37dca2272d 100644 --- a/arch/arm/boot/dts/imx7d-pico-pi.dts +++ b/arch/arm/boot/dts/imx7d-pico-pi.dts @@ -31,7 +31,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&sgtl5000>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -41,7 +41,7 @@ #sound-dai-cells = <0>; reg = <0x0a>; compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_vref_1v8>; }; diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts index 6823b9f1a2a32a960b1940d878f716af6bf857e8..ac0751bc1177e1544c3c00b9a9073a7e89252d71 100644 --- a/arch/arm/boot/dts/imx7d-sdb.dts +++ b/arch/arm/boot/dts/imx7d-sdb.dts @@ -378,14 +378,14 @@ codec: wm8960@1a { compatible = "wlf,wm8960"; reg = <0x1a>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; clock-names = "mclk"; wlf,shared-lrclk; wlf,hp-cfg = <2 2 3>; wlf,gpio-cfg = <1 3>; assigned-clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_SRC>, <&clks IMX7D_PLL_AUDIO_POST_DIV>, - <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>; assigned-clock-rates = <0>, <884736000>, <12288000>; }; diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-warp.dts index e035dd5bf4f62ec6f6a687fb97e25c3650fe8e0d..d6b4888fa686bcc8b33699c4078429da53fb762f 100644 --- a/arch/arm/boot/dts/imx7s-warp.dts +++ b/arch/arm/boot/dts/imx7s-warp.dts @@ -75,7 +75,7 @@ dailink_master: simple-audio-card,codec { sound-dai = <&codec>; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; }; }; }; @@ -232,7 +232,7 @@ #sound-dai-cells = <0>; reg = <0x0a>; compatible = "fsl,sgtl5000"; - clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>; + clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai1_mclk>; VDDA-supply = <&vgen4_reg>; diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi index 3defd47fd8fabb026f1972afa78680c1f787815d..74d8e2c8e4b343f55742b49ed8797793b67d2d20 100644 --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi @@ -142,8 +142,7 @@ clocks { sleep_clk: sleep_clk { compatible = "fixed-clock"; - clock-frequency = <32000>; - clock-output-names = "gcc_sleep_clk_src"; + clock-frequency = <32768>; #clock-cells = <0>; }; diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi index c197927e7435f5434a2a3e97ee15c0b0b51cbbd1..172ea3c70eac200e85f89917ba3c1533ee9ea036 100644 --- a/arch/arm/boot/dts/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom-msm8960.dtsi @@ -146,9 +146,7 @@ reg = <0x108000 0x1000>; qcom,ipc = <&l2cc 0x8 2>; - interrupts = , - , - ; + interrupts = <0 19 0>, <0 21 0>, <0 22 0>; interrupt-names = "ack", "err", "wakeup"; regulators { @@ -194,7 +192,7 @@ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x16440000 0x1000>, <0x16400000 0x1000>; - interrupts = ; + interrupts = <0 154 0x0>; clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; clock-names = "core", "iface"; status = "disabled"; @@ -320,7 +318,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x16080000 0x1000>; - interrupts = ; + interrupts = <0 147 0>; spi-max-frequency = <24000000>; cs-gpios = <&msmgpio 8 0>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 12f57278ba4a53b9ff948f36917f5b672f5669c6..2c4952427296efc6ba96428096a6cf71b59e455b 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -413,7 +413,7 @@ pmecc: ecc-engine@f8014070 { compatible = "atmel,sama5d2-pmecc"; reg = <0xf8014070 0x490>, - <0xf8014500 0x200>; + <0xf8014500 0x100>; }; }; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index 66cd473ecb61796b9f919e0b50c1df5ee1fc7df8..1a8f5e8b10e3a2fd472634d852c66b8131eaae2e 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -136,9 +136,9 @@ reg = <0xb4100000 0x1000>; interrupts = <0 105 0x4>; status = "disabled"; - dmas = <&dwdma0 13 0 1>, - <&dwdma0 12 1 0>; - dma-names = "rx", "tx"; + dmas = <&dwdma0 12 0 1>, + <&dwdma0 13 1 0>; + dma-names = "tx", "rx"; }; thermal@e07008c4 { diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 9135533676879e8abb0d24aeb9a6c14b4701261d..c87b881b2c8bb244fc43cdc37c97c6bd0f7657eb 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -284,9 +284,9 @@ #size-cells = <0>; interrupts = <0 31 0x4>; status = "disabled"; - dmas = <&dwdma0 5 0 0>, - <&dwdma0 4 0 0>; - dma-names = "rx", "tx"; + dmas = <&dwdma0 4 0 0>, + <&dwdma0 5 0 0>; + dma-names = "tx", "rx"; }; rtc@e0580000 { diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index b21ecb820b133055caf17d8c7be3f584d42365d2..89abd4cc7e23a381953d70de63e4b40539cae4ea 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -524,17 +524,6 @@ #size-cells = <0>; }; - gic: interrupt-controller@1c81000 { - compatible = "arm,gic-400"; - reg = <0x01c81000 0x1000>, - <0x01c82000 0x2000>, - <0x01c84000 0x2000>, - <0x01c86000 0x2000>; - interrupt-controller; - #interrupt-cells = <3>; - interrupts = ; - }; - csi1: camera@1cb4000 { compatible = "allwinner,sun8i-v3s-csi"; reg = <0x01cb4000 0x3000>; @@ -546,5 +535,16 @@ resets = <&ccu RST_BUS_CSI>; status = "disabled"; }; + + gic: interrupt-controller@1c81000 { + compatible = "arm,gic-400"; + reg = <0x01c81000 0x1000>, + <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupts = ; + }; }; }; diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi index 7f14f0d005c3e2055103943c4f7ac93997a9ba14..dd4d506683de7dcf07c45b173e57077ce79acbf0 100644 --- a/arch/arm/boot/dts/tegra20-tamonten.dtsi +++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi @@ -183,8 +183,8 @@ }; conf_ata { nvidia,pins = "ata", "atb", "atc", "atd", "ate", - "cdev1", "cdev2", "dap1", "dtb", "dtf", - "gma", "gmb", "gmc", "gmd", "gme", "gpu7", + "cdev1", "cdev2", "dap1", "dtb", "gma", + "gmb", "gmc", "gmd", "gme", "gpu7", "gpv", "i2cp", "irrx", "irtx", "pta", "rm", "slxa", "slxk", "spia", "spib", "uac"; @@ -203,7 +203,7 @@ }; conf_crtp { nvidia,pins = "crtp", "dap2", "dap3", "dap4", - "dtc", "dte", "gpu", "sdio1", + "dtc", "dte", "dtf", "gpu", "sdio1", "slxc", "slxd", "spdi", "spdo", "spig", "uda"; nvidia,pull = ; diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 4393e689f2354cb9a79da77e11c729ac6905873e..e00be9faa23bfa7e1a28a8b8f8d0bd8ba0c60a2b 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -187,7 +187,6 @@ CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_PLATFORM_SUPPORT=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_ASPEED=m CONFIG_VIDEO_ATMEL_ISI=m diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index e4dba5461cb3eafbe2a07649148c11c298a6da52..2b575792363e55ea8f5fc1c32d92da2428be26dd 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -102,8 +102,6 @@ config CRYPTO_AES_ARM_BS depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_LIB_AES - select CRYPTO_AES - select CRYPTO_CBC select CRYPTO_SIMD help Use a faster and more secure NEON based implementation of AES in CBC, diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index 5f1b1ce10473aa80c8fae70d130d45723c2bfdf2..a74289ebc803699955155b4f31bd387c8f23b9bd 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -22,7 +22,10 @@ * mcount can be thought of as a function called in the middle of a subroutine * call. As such, it needs to be transparent for both the caller and the * callee: the original lr needs to be restored when leaving mcount, and no - * registers should be clobbered. + * registers should be clobbered. (In the __gnu_mcount_nc implementation, we + * clobber the ip register. This is OK because the ARM calling convention + * allows it to be clobbered in subroutines and doesn't use it to hold + * parameters.) * * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}" * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). @@ -67,25 +70,26 @@ .macro __ftrace_regs_caller - str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0, + sub sp, sp, #8 @ space for PC and CPSR OLD_R0, @ OLD_R0 will overwrite previous LR - ldr lr, [sp, #8] @ get previous LR + add ip, sp, #12 @ move in IP the value of SP as it was + @ before the push {lr} of the mcount mechanism - str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR + str lr, [sp, #0] @ store LR instead of PC - str lr, [sp, #-4]! @ store previous LR as LR + ldr lr, [sp, #8] @ get previous LR - add lr, sp, #16 @ move in LR the value of SP as it was - @ before the push {lr} of the mcount mechanism + str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR - push {r0-r11, ip, lr} + stmdb sp!, {ip, lr} + stmdb sp!, {r0-r11, lr} @ stack content at this point: @ 0 4 48 52 56 60 64 68 72 - @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 | + @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | - mov r3, sp @ struct pt_regs* + mov r3, sp @ struct pt_regs* ldr r2, =function_trace_op ldr r2, [r2] @ pointer to the current @@ -108,9 +112,11 @@ ftrace_graph_regs_call: #endif @ pop saved regs - pop {r0-r11, ip, lr} @ restore r0 through r12 - ldr lr, [sp], #4 @ restore LR - ldr pc, [sp], #12 + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8] @ restore PC + ldr lr, [sp, #4] @ restore LR + ldr sp, [sp, #0] @ restore SP + mov pc, ip @ return .endm #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -126,9 +132,11 @@ ftrace_graph_regs_call: bl prepare_ftrace_return @ pop registers saved in ftrace_regs_caller - pop {r0-r11, ip, lr} @ restore r0 through r12 - ldr lr, [sp], #4 @ restore LR - ldr pc, [sp], #12 + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8] @ restore PC + ldr lr, [sp, #4] @ restore LR + ldr sp, [sp, #0] @ restore SP + mov pc, ip @ return .endm #endif @@ -194,17 +202,16 @@ ftrace_graph_call\suffix: .endm .macro mcount_exit - ldmia sp!, {r0-r3} - ldr lr, [sp, #4] - ldr pc, [sp], #8 + ldmia sp!, {r0-r3, ip, lr} + ret ip .endm ENTRY(__gnu_mcount_nc) UNWIND(.fnstart) #ifdef CONFIG_DYNAMIC_FTRACE - push {lr} - ldr lr, [sp, #4] - ldr pc, [sp], #8 + mov ip, lr + ldmia sp!, {lr} + ret ip #else __mcount #endif diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index b74bfcf94fb1a5ea85fea22756628afae9676630..6166ba38bf99479d62fa9f2e24c5a0f180ba4851 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -195,7 +195,7 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr) destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data); /* Check access in reasonable access range for both SWP and SWPB */ - if (!access_ok((void __user *)(address & ~3), 4)) { + if (!access_ok((address & ~3), 4)) { pr_debug("SWP{B} emulation: access to %p not allowed!\n", (void *)address); res = -EFAULT; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index a531afad87fdb984fc8444e9a9e971c7100dff73..2d9e72ad1b0f923d8afafa49fd4e5cd5d1feadb6 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -589,7 +589,7 @@ do_cache_op(unsigned long start, unsigned long end, int flags) if (end < start || flags) return -EINVAL; - if (!access_ok((void __user *)start, end - start)) + if (!access_ok(start, end - start)) return -EFAULT; return __do_cache_op(start, end); diff --git a/arch/arm/mach-iop32x/include/mach/entry-macro.S b/arch/arm/mach-iop32x/include/mach/entry-macro.S index 341e5d9a6616d3287a87dc45ff8fb711566093c5..8e6766d4621eb7c6bf53afbd575f2eb5ec6f056f 100644 --- a/arch/arm/mach-iop32x/include/mach/entry-macro.S +++ b/arch/arm/mach-iop32x/include/mach/entry-macro.S @@ -20,7 +20,7 @@ mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC cmp \irqstat, #0 clzne \irqnr, \irqstat - rsbne \irqnr, \irqnr, #32 + rsbne \irqnr, \irqnr, #31 .endm .macro arch_ret_to_user, tmp1, tmp2 diff --git a/arch/arm/mach-iop32x/include/mach/irqs.h b/arch/arm/mach-iop32x/include/mach/irqs.h index e09ae5f48aec5c558cbf2582480b6f41ad58ff18..c4e78df428e860e5b2b13b4bccd96eab8ea44ef2 100644 --- a/arch/arm/mach-iop32x/include/mach/irqs.h +++ b/arch/arm/mach-iop32x/include/mach/irqs.h @@ -9,6 +9,6 @@ #ifndef __IRQS_H #define __IRQS_H -#define NR_IRQS 33 +#define NR_IRQS 32 #endif diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index d1e8824cbd824a4620a045328e4b4025318b096f..2d48bf1398c10d26c41776b9dfa9d1d6bc505f29 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -32,14 +32,14 @@ static void intstr_write(u32 val) static void iop32x_irq_mask(struct irq_data *d) { - iop32x_mask &= ~(1 << (d->irq - 1)); + iop32x_mask &= ~(1 << d->irq); intctl_write(iop32x_mask); } static void iop32x_irq_unmask(struct irq_data *d) { - iop32x_mask |= 1 << (d->irq - 1); + iop32x_mask |= 1 << d->irq; intctl_write(iop32x_mask); } @@ -65,7 +65,7 @@ void __init iop32x_init_irq(void) machine_is_em7210()) *IOP3XX_PCIIRSR = 0x0f; - for (i = 1; i < NR_IRQS; i++) { + for (i = 0; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } diff --git a/arch/arm/mach-iop32x/irqs.h b/arch/arm/mach-iop32x/irqs.h index e1dfc8b4e7d7e3e503a5f57ea49448b4f91d0189..69858e4e905d13d37beb484f80459bf3c76cfe6a 100644 --- a/arch/arm/mach-iop32x/irqs.h +++ b/arch/arm/mach-iop32x/irqs.h @@ -7,40 +7,36 @@ #ifndef __IOP32X_IRQS_H #define __IOP32X_IRQS_H -/* Interrupts in Linux start at 1, hardware starts at 0 */ - -#define IOP_IRQ(x) ((x) + 1) - /* * IOP80321 chipset interrupts */ -#define IRQ_IOP32X_DMA0_EOT IOP_IRQ(0) -#define IRQ_IOP32X_DMA0_EOC IOP_IRQ(1) -#define IRQ_IOP32X_DMA1_EOT IOP_IRQ(2) -#define IRQ_IOP32X_DMA1_EOC IOP_IRQ(3) -#define IRQ_IOP32X_AA_EOT IOP_IRQ(6) -#define IRQ_IOP32X_AA_EOC IOP_IRQ(7) -#define IRQ_IOP32X_CORE_PMON IOP_IRQ(8) -#define IRQ_IOP32X_TIMER0 IOP_IRQ(9) -#define IRQ_IOP32X_TIMER1 IOP_IRQ(10) -#define IRQ_IOP32X_I2C_0 IOP_IRQ(11) -#define IRQ_IOP32X_I2C_1 IOP_IRQ(12) -#define IRQ_IOP32X_MESSAGING IOP_IRQ(13) -#define IRQ_IOP32X_ATU_BIST IOP_IRQ(14) -#define IRQ_IOP32X_PERFMON IOP_IRQ(15) -#define IRQ_IOP32X_CORE_PMU IOP_IRQ(16) -#define IRQ_IOP32X_BIU_ERR IOP_IRQ(17) -#define IRQ_IOP32X_ATU_ERR IOP_IRQ(18) -#define IRQ_IOP32X_MCU_ERR IOP_IRQ(19) -#define IRQ_IOP32X_DMA0_ERR IOP_IRQ(20) -#define IRQ_IOP32X_DMA1_ERR IOP_IRQ(21) -#define IRQ_IOP32X_AA_ERR IOP_IRQ(23) -#define IRQ_IOP32X_MSG_ERR IOP_IRQ(24) -#define IRQ_IOP32X_SSP IOP_IRQ(25) -#define IRQ_IOP32X_XINT0 IOP_IRQ(27) -#define IRQ_IOP32X_XINT1 IOP_IRQ(28) -#define IRQ_IOP32X_XINT2 IOP_IRQ(29) -#define IRQ_IOP32X_XINT3 IOP_IRQ(30) -#define IRQ_IOP32X_HPI IOP_IRQ(31) +#define IRQ_IOP32X_DMA0_EOT 0 +#define IRQ_IOP32X_DMA0_EOC 1 +#define IRQ_IOP32X_DMA1_EOT 2 +#define IRQ_IOP32X_DMA1_EOC 3 +#define IRQ_IOP32X_AA_EOT 6 +#define IRQ_IOP32X_AA_EOC 7 +#define IRQ_IOP32X_CORE_PMON 8 +#define IRQ_IOP32X_TIMER0 9 +#define IRQ_IOP32X_TIMER1 10 +#define IRQ_IOP32X_I2C_0 11 +#define IRQ_IOP32X_I2C_1 12 +#define IRQ_IOP32X_MESSAGING 13 +#define IRQ_IOP32X_ATU_BIST 14 +#define IRQ_IOP32X_PERFMON 15 +#define IRQ_IOP32X_CORE_PMU 16 +#define IRQ_IOP32X_BIU_ERR 17 +#define IRQ_IOP32X_ATU_ERR 18 +#define IRQ_IOP32X_MCU_ERR 19 +#define IRQ_IOP32X_DMA0_ERR 20 +#define IRQ_IOP32X_DMA1_ERR 21 +#define IRQ_IOP32X_AA_ERR 23 +#define IRQ_IOP32X_MSG_ERR 24 +#define IRQ_IOP32X_SSP 25 +#define IRQ_IOP32X_XINT0 27 +#define IRQ_IOP32X_XINT1 28 +#define IRQ_IOP32X_XINT2 29 +#define IRQ_IOP32X_XINT3 30 +#define IRQ_IOP32X_HPI 31 #endif diff --git a/arch/arm/mach-mmp/sram.c b/arch/arm/mach-mmp/sram.c index ecc46c31004f660961a450027a6d1bfd8e86a053..6794e2db1ad5f5ae1f0ea7026b73bf5fb7894b38 100644 --- a/arch/arm/mach-mmp/sram.c +++ b/arch/arm/mach-mmp/sram.c @@ -72,8 +72,6 @@ static int sram_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - platform_set_drvdata(pdev, info); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "no memory resource defined\n"); @@ -109,6 +107,8 @@ static int sram_probe(struct platform_device *pdev) list_add(&info->node, &sram_bank_list); mutex_unlock(&sram_lock); + platform_set_drvdata(pdev, info); + dev_info(&pdev->dev, "initialized\n"); return 0; @@ -127,19 +127,17 @@ static int sram_remove(struct platform_device *pdev) struct sram_bank_info *info; info = platform_get_drvdata(pdev); + if (info == NULL) + return -ENODEV; - if (info->sram_size) { - mutex_lock(&sram_lock); - list_del(&info->node); - mutex_unlock(&sram_lock); - - gen_pool_destroy(info->gpool); - iounmap(info->sram_virt); - kfree(info->pool_name); - } + mutex_lock(&sram_lock); + list_del(&info->node); + mutex_unlock(&sram_lock); + gen_pool_destroy(info->gpool); + iounmap(info->sram_virt); + kfree(info->pool_name); kfree(info); - return 0; } diff --git a/arch/arm/mach-mstar/Kconfig b/arch/arm/mach-mstar/Kconfig index 30560fdf87ed224c29d106f930bc12571745098e..576d1ab293c8734c587d2dd2d918c21358fbf874 100644 --- a/arch/arm/mach-mstar/Kconfig +++ b/arch/arm/mach-mstar/Kconfig @@ -3,7 +3,6 @@ menuconfig ARCH_MSTARV7 depends on ARCH_MULTI_V7 select ARM_GIC select ARM_HEAVY_MB - select HAVE_ARM_ARCH_TIMER select MST_IRQ help Support for newer MStar/Sigmastar SoC families that are diff --git a/arch/arm/mach-s3c/mach-jive.c b/arch/arm/mach-s3c/mach-jive.c index ae6a1c9ebf78cb01ee4faefa4298f0ed51dd6b78..2a29c3eca559eb6bf1c2448d9a5cfd12d522e216 100644 --- a/arch/arm/mach-s3c/mach-jive.c +++ b/arch/arm/mach-s3c/mach-jive.c @@ -236,11 +236,11 @@ static int __init jive_mtdset(char *options) unsigned long set; if (options == NULL || options[0] == '\0') - return 1; + return 0; if (kstrtoul(options, 10, &set)) { printk(KERN_ERR "failed to parse mtdset=%s\n", options); - return 1; + return 0; } switch (set) { @@ -255,7 +255,7 @@ static int __init jive_mtdset(char *options) "using default.", set); } - return 1; + return 0; } /* parse the mtdset= option given to the kernel command line */ diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts index 12a4b1c03390c0e2be02d6b2f2f921a1f6dc3d05..ec19fbf928a142db6d9e853fee7e98f1e31d66b2 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2-svk.dts @@ -111,8 +111,8 @@ compatible = "silabs,si3226x"; reg = <0>; spi-max-frequency = <5000000>; - spi-cpha; - spi-cpol; + spi-cpha = <1>; + spi-cpol = <1>; pl022,hierarchy = <0>; pl022,interface = <0>; pl022,slave-tx-disable = <0>; @@ -135,8 +135,8 @@ at25,byte-len = <0x8000>; at25,addr-mode = <2>; at25,page-size = <64>; - spi-cpha; - spi-cpol; + spi-cpha = <1>; + spi-cpol = <1>; pl022,hierarchy = <0>; pl022,interface = <0>; pl022,slave-tx-disable = <0>; diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi index 8c218689fef70e745061ea92047179cfb53613a3..2cfeaf3b0a87685cc270b22f8e6bf862721e529f 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi @@ -687,7 +687,7 @@ }; }; - sata: sata@663f2000 { + sata: ahci@663f2000 { compatible = "brcm,iproc-ahci", "generic-ahci"; reg = <0x663f2000 0x1000>; dma-coherent; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 9beb3c34fcdb5f8ed4eaf38ad92e4d680560f14b..ea6e3a11e641b0f4df11600f6ea56ba5a9672995 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3406,10 +3406,10 @@ #clock-cells = <0>; clock-frequency = <9600000>; clock-output-names = "mclk"; - qcom,micbias1-microvolt = <1800000>; - qcom,micbias2-microvolt = <1800000>; - qcom,micbias3-microvolt = <1800000>; - qcom,micbias4-microvolt = <1800000>; + qcom,micbias1-millivolt = <1800>; + qcom,micbias2-millivolt = <1800>; + qcom,micbias3-millivolt = <1800>; + qcom,micbias4-millivolt = <1800>; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index a8a47378ba689b09af24dc2b2e6722c769e63715..1aec54590a11aba8170d7293680f374521a837b7 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1114,9 +1114,9 @@ qcom,tcs-offset = <0xd00>; qcom,drv-id = <2>; qcom,tcs-config = , - , - , - ; + , + , + ; rpmhcc: clock-controller { compatible = "qcom,sm8150-rpmh-clk"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts index dc45ec372ada46bd4b97ba24456b4fe3dac93679..6db18808b9c54be1f9c91398b7aa71545c8c446b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -665,8 +665,8 @@ sd-uhs-sdr104; /* Power supply */ - vqmmc-supply = <&vcc1v8_s3>; /* IO line */ - vmmc-supply = <&vcc_sdio>; /* card's power */ + vqmmc-supply = &vcc1v8_s3; /* IO line */ + vmmc-supply = &vcc_sdio; /* card's power */ #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index d04189771c773d08c1ec7f6d4591af77f56fd6a0..b9662205be9bf95b8c4efb160f457a169d926b21 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -35,10 +35,7 @@ #interrupt-cells = <3>; interrupt-controller; reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01880000 0x00 0x90000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + <0x00 0x01880000 0x00 0x90000>; /* GICR */ /* * vcpumntirq: * virtual CPU interface maintenance interrupt diff --git a/arch/arm64/boot/dts/ti/k3-am65.dtsi b/arch/arm64/boot/dts/ti/k3-am65.dtsi index c6a3fecc7518ef4f90afd09d9ff41a7af848a7cb..d84c0bc05023373e7cbebdd41c2c21655be79bb0 100644 --- a/arch/arm64/boot/dts/ti/k3-am65.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65.dtsi @@ -84,7 +84,6 @@ <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, <0x00 0x50000000 0x00 0x50000000 0x00 0x8000000>, - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A53 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x200000>, <0x05 0x00000000 0x05 0x00000000 0x01 0x0000000>, <0x07 0x00000000 0x07 0x00000000 0x01 0x0000000>; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi index bef47f96376d997b827a4234f2c2379f791bfe29..1ab9f9604af6c569788745ccd829df182407f2d5 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -47,10 +47,7 @@ #interrupt-cells = <3>; interrupt-controller; reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + <0x00 0x01900000 0x00 0x100000>; /* GICR */ /* vcpumntirq: virtual CPU interface maintenance interrupt */ interrupts = ; diff --git a/arch/arm64/boot/dts/ti/k3-j7200.dtsi b/arch/arm64/boot/dts/ti/k3-j7200.dtsi index 59f5113e657dd62c18ee13bc26709f47bbb23f4d..03a9623f0f9562e902184cc68490a27b175aac81 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200.dtsi @@ -127,7 +127,6 @@ <0x00 0x00a40000 0x00 0x00a40000 0x00 0x00000800>, /* timesync router */ <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x00 0x70000000 0x00 0x70000000 0x00 0x00800000>, /* MSMC RAM */ <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ <0x41 0x00000000 0x41 0x00000000 0x01 0x00000000>, /* PCIe1 DAT1 */ diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 0350ddfe2c72384313539d98a23ab50c33dbe4e1..85526f72b4616c888fc953bc21d4b7f25dc0c48d 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -108,10 +108,7 @@ #interrupt-cells = <3>; interrupt-controller; reg = <0x00 0x01800000 0x00 0x10000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + <0x00 0x01900000 0x00 0x100000>; /* GICR */ /* vcpumntirq: virtual CPU interface maintenance interrupt */ interrupts = ; diff --git a/arch/arm64/boot/dts/ti/k3-j721e.dtsi b/arch/arm64/boot/dts/ti/k3-j721e.dtsi index ba4fe3f9831586921472504bc00cb3148747c168..a199227327ed299907f84fb925d9ca52832d7724 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e.dtsi @@ -136,7 +136,6 @@ <0x00 0x0e000000 0x00 0x0e000000 0x00 0x01800000>, /* PCIe Core*/ <0x00 0x10000000 0x00 0x10000000 0x00 0x10000000>, /* PCIe DAT */ <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71 */ - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ <0x44 0x00000000 0x44 0x00000000 0x00 0x08000000>, /* PCIe2 DAT */ <0x44 0x10000000 0x44 0x10000000 0x00 0x08000000>, /* PCIe3 DAT */ <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */ diff --git a/arch/arm64/configs/db845c_gki.fragment b/arch/arm64/configs/db845c_gki.fragment index 5ba41f2d8ddcb64264156794a66b3dbafb38ec91..7260af26f4a36ada76372142c87d33de0d0f04b0 100644 --- a/arch/arm64/configs/db845c_gki.fragment +++ b/arch/arm64/configs/db845c_gki.fragment @@ -1,7 +1,6 @@ CONFIG_QRTR=m CONFIG_QRTR_TUN=m CONFIG_SCSI_UFS_QCOM=m -CONFIG_USB_NET_AX88179_178A=m CONFIG_INPUT_PM8941_PWRKEY=m CONFIG_SERIAL_MSM=m CONFIG_SERIAL_QCOM_GENI=m diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 394c4411518a8269806664e1756fbf2e2133c102..5fcd09e505b4cd17309bece5808e4998eb583dfb 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -840,7 +840,7 @@ CONFIG_DMADEVICES=y CONFIG_DMA_BCM2835=y CONFIG_DMA_SUN6I=m CONFIG_FSL_EDMA=y -CONFIG_IMX_SDMA=m +CONFIG_IMX_SDMA=y CONFIG_K3_DMA=y CONFIG_MV_XOR=y CONFIG_MV_XOR_V2=y diff --git a/arch/arm64/configs/gki_defconfig b/arch/arm64/configs/gki_defconfig index 25698c34c673cccdd482395b1d49f25a70d62fa4..86f63c51de4d7ba8209f104c95f13f9914943dda 100644 --- a/arch/arm64/configs/gki_defconfig +++ b/arch/arm64/configs/gki_defconfig @@ -124,6 +124,10 @@ CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=16 CONFIG_READ_ONLY_THP_FOR_FS=y CONFIG_ANON_VMA_NAME=y +CONFIG_LRU_GEN=y +CONFIG_DAMON=y +CONFIG_DAMON_PADDR=y +CONFIG_DAMON_RECLAIM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -331,6 +335,7 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_WIREGUARD=y CONFIG_IFB=y +CONFIG_MACSEC=y CONFIG_TUN=y CONFIG_VETH=y CONFIG_PPP=y @@ -342,7 +347,6 @@ CONFIG_PPPOL2TP=y CONFIG_USB_RTL8150=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y -# CONFIG_USB_NET_AX88179_178A is not set CONFIG_USB_NET_CDC_EEM=y # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set @@ -394,6 +398,7 @@ CONFIG_HVC_DCC=y CONFIG_HVC_DCC_SERIALIZE_SMP=y CONFIG_SERIAL_DEV_BUS=y CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_CAVIUM is not set # CONFIG_DEVMEM is not set # CONFIG_DEVPORT is not set CONFIG_RANDOM_TRUST_CPU=y @@ -574,6 +579,7 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_F2FS_UNFAIR_RWSEM=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index bda918948471df9a842dbfc0c36b58bd52ab1e6b..1bc198a5faadeb606d9ede01eb36120b26e1331a 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -149,6 +149,20 @@ msr spsr_el2, x0 .endm +.macro __init_el2_mpam + /* Memory Partioning And Monitoring: disable EL2 traps */ + mrs x1, id_aa64pfr0_el1 + ubfx x0, x1, #ID_AA64PFR0_MPAM_SHIFT, #4 + cbz x0, .Lskip_mpam_\@ // skip if no MPAM + msr_s SYS_MPAM0_EL1, xzr // use the default partition.. + msr_s SYS_MPAM2_EL2, xzr // ..and disable lower traps + msr_s SYS_MPAM1_EL1, xzr + mrs_s x0, SYS_MPAMIDR_EL1 + tbz x0, #17, .Lskip_mpam_\@ // skip if no MPAMHCR reg + msr_s SYS_MPAMHCR_EL2, xzr // clear TRAP_MPAMIDR_EL1 -> EL2 +.Lskip_mpam_\@: +.endm + /** * Initialize EL2 registers to sane values. This should be called early on all * cores that were booted in EL2. Note that everything gets initialised as @@ -165,6 +179,7 @@ __init_el2_stage2 __init_el2_gicv3 __init_el2_hstr + __init_el2_mpam __init_el2_nvhe_idregs __init_el2_nvhe_cptr __init_el2_nvhe_sve diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 8ce6444d861ae6f1b380e4cb093de7fa3f1186f7..ef1cf41ea394fae3fc20fc1e4248f12f62994777 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -82,6 +82,7 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___pkvm_iommu_driver_init, __KVM_HOST_SMCCC_FUNC___pkvm_iommu_register, __KVM_HOST_SMCCC_FUNC___pkvm_iommu_pm_notify, + __KVM_HOST_SMCCC_FUNC___pkvm_iommu_finalize, }; #define DECLARE_KVM_VHE_SYM(sym) extern char sym[] @@ -112,7 +113,7 @@ enum __kvm_host_smccc_func { #define per_cpu_ptr_nvhe_sym(sym, cpu) \ ({ \ unsigned long base, off; \ - base = kvm_arm_hyp_percpu_base[cpu]; \ + base = kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu]; \ off = (unsigned long)&CHOOSE_NVHE_SYM(sym) - \ (unsigned long)&CHOOSE_NVHE_SYM(__per_cpu_start); \ base ? (typeof(CHOOSE_NVHE_SYM(sym))*)(base + off) : NULL; \ @@ -200,7 +201,7 @@ DECLARE_KVM_HYP_SYM(__kvm_hyp_vector); #define __kvm_hyp_init CHOOSE_NVHE_SYM(__kvm_hyp_init) #define __kvm_hyp_vector CHOOSE_HYP_SYM(__kvm_hyp_vector) -extern unsigned long kvm_arm_hyp_percpu_base[NR_CPUS]; +extern unsigned long kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[]; DECLARE_KVM_NVHE_SYM(__per_cpu_start); DECLARE_KVM_NVHE_SYM(__per_cpu_end); diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 7e0ff042be8861c5a81e337f7a6882712e656713..f583373ff8abed8778c98b777642c70313797592 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -41,6 +41,11 @@ void kvm_inject_vabt(struct kvm_vcpu *vcpu); void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); +unsigned long get_except64_offset(unsigned long psr, unsigned long target_mode, + enum exception_type type); +unsigned long get_except64_cpsr(unsigned long old, bool has_mte, + unsigned long sctlr, unsigned long mode); + static inline int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) { /* diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 08bf6cc0974313286efada0fd8960e754d3d1e95..f73ed0c867be0febb3c8fb19512d814e60264dca 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -212,8 +212,6 @@ struct kvm_arch { u8 pfr0_csv3; struct kvm_protected_vm pkvm; - - u64 hypercall_exit_enabled; }; struct kvm_protected_vcpu { @@ -378,6 +376,7 @@ extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS]; enum pkvm_iommu_driver_id { PKVM_IOMMU_DRIVER_S2MPU, + PKVM_IOMMU_DRIVER_SYSMMU_SYNC, PKVM_IOMMU_NR_DRIVERS, }; @@ -388,11 +387,15 @@ enum pkvm_iommu_pm_event { int pkvm_iommu_driver_init(enum pkvm_iommu_driver_id drv_id, void *data, size_t size); int pkvm_iommu_register(struct device *dev, enum pkvm_iommu_driver_id drv_id, - phys_addr_t pa, size_t size); + phys_addr_t pa, size_t size, struct device *parent); int pkvm_iommu_suspend(struct device *dev); int pkvm_iommu_resume(struct device *dev); int pkvm_iommu_s2mpu_register(struct device *dev, phys_addr_t pa); +int pkvm_iommu_sysmmu_sync_register(struct device *dev, phys_addr_t pa, + struct device *parent); +/* Reject future calls to pkvm_iommu_driver_init() and pkvm_iommu_register(). */ +int pkvm_iommu_finalize(void); struct vcpu_reset_state { unsigned long pc; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 7a8dc3f343ec88390fc09b59925d3caa06010718..b3b03f1549ebf1f534df79fd95c31a2f1f9d48ac 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -118,6 +118,10 @@ alternative_cb_end void kvm_update_va_mask(struct alt_instr *alt, __le32 *origptr, __le32 *updptr, int nr_inst); +void kvm_get__text(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); +void kvm_get__etext(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); void kvm_compute_layout(void); void kvm_apply_hyp_relocations(void); diff --git a/arch/arm64/include/asm/kvm_s2mpu.h b/arch/arm64/include/asm/kvm_s2mpu.h index 4d517bc1d0ebff0df918c06f778335909c86ee4f..b1075abd604caef6a6a12b26623a48fd23a2dbce 100644 --- a/arch/arm64/include/asm/kvm_s2mpu.h +++ b/arch/arm64/include/asm/kvm_s2mpu.h @@ -12,6 +12,10 @@ #include #define S2MPU_MMIO_SIZE SZ_64K +#define SYSMMU_SYNC_MMIO_SIZE SZ_64K +#define SYSMMU_SYNC_S2_OFFSET SZ_32K +#define SYSMMU_SYNC_S2_MMIO_SIZE (SYSMMU_SYNC_MMIO_SIZE - \ + SYSMMU_SYNC_S2_OFFSET) #define NR_VIDS 8 #define NR_CTX_IDS 8 @@ -24,6 +28,7 @@ #define REG_NS_INTERRUPT_ENABLE_PER_VID_SET 0x20 #define REG_NS_INTERRUPT_CLEAR 0x2c #define REG_NS_VERSION 0x60 +#define REG_NS_INFO 0x64 #define REG_NS_STATUS 0x68 #define REG_NS_NUM_CONTEXT 0x100 #define REG_NS_CONTEXT_CFG_VALID_VID 0x104 @@ -35,6 +40,10 @@ #define REG_NS_FAULT_PA_LOW(vid) (0x2004 + ((vid) * 0x20)) #define REG_NS_FAULT_PA_HIGH(vid) (0x2008 + ((vid) * 0x20)) #define REG_NS_FAULT_INFO(vid) (0x2010 + ((vid) * 0x20)) +#define REG_NS_READ_MPTC 0x3000 +#define REG_NS_READ_MPTC_TAG_PPN 0x3004 +#define REG_NS_READ_MPTC_TAG_OTHERS 0x3008 +#define REG_NS_READ_MPTC_DATA 0x3010 #define REG_NS_L1ENTRY_L2TABLE_ADDR(vid, gb) (0x4000 + ((vid) * 0x200) + ((gb) * 0x8)) #define REG_NS_L1ENTRY_ATTR(vid, gb) (0x4004 + ((vid) * 0x200) + ((gb) * 0x8)) @@ -42,15 +51,30 @@ #define CTRL0_INTERRUPT_ENABLE BIT(1) #define CTRL0_FAULT_RESP_TYPE_SLVERR BIT(2) /* for v8 */ #define CTRL0_FAULT_RESP_TYPE_DECERR BIT(2) /* for v9 */ +#define CTRL0_MASK (CTRL0_ENABLE | \ + CTRL0_INTERRUPT_ENABLE | \ + CTRL0_FAULT_RESP_TYPE_SLVERR | \ + CTRL0_FAULT_RESP_TYPE_DECERR) #define CTRL1_DISABLE_CHK_S1L1PTW BIT(0) #define CTRL1_DISABLE_CHK_S1L2PTW BIT(1) #define CTRL1_ENABLE_PAGE_SIZE_AWARENESS BIT(2) #define CTRL1_DISABLE_CHK_USER_MATCHED_REQ BIT(3) +#define CTRL1_MASK (CTRL1_DISABLE_CHK_S1L1PTW | \ + CTRL1_DISABLE_CHK_S1L2PTW | \ + CTRL1_ENABLE_PAGE_SIZE_AWARENESS | \ + CTRL1_DISABLE_CHK_USER_MATCHED_REQ) #define CFG_MPTW_CACHE_OVERRIDE BIT(0) +#define CFG_MPTW_CACHE_VALUE GENMASK(7, 4) #define CFG_MPTW_QOS_OVERRIDE BIT(8) +#define CFG_MPTW_QOS_VALUE GENMASK(15, 12) #define CFG_MPTW_SHAREABLE BIT(16) +#define CFG_MASK (CFG_MPTW_CACHE_OVERRIDE | \ + CFG_MPTW_CACHE_VALUE | \ + CFG_MPTW_QOS_OVERRIDE | \ + CFG_MPTW_QOS_VALUE | \ + CFG_MPTW_SHAREABLE) /* For use with hi_lo_readq_relaxed(). */ #define REG_NS_FAULT_PA_HIGH_LOW(vid) REG_NS_FAULT_PA_LOW(vid) @@ -68,6 +92,8 @@ VERSION_MINOR_ARCH_VER_MASK | \ VERSION_REV_ARCH_VER_MASK) +#define INFO_NUM_SET_MASK GENMASK(15, 0) + #define STATUS_BUSY BIT(0) #define STATUS_ON_INVALIDATING BIT(1) @@ -90,14 +116,31 @@ #define FAULT_INFO_LEN_MASK GENMASK(19, 16) #define FAULT_INFO_ID_MASK GENMASK(15, 0) -#define L1ENTRY_L2TABLE_ADDR(pa) ((pa) >> 4) +#define L1ENTRY_L2TABLE_ADDR_SHIFT 4 +#define L1ENTRY_L2TABLE_ADDR(pa) ((pa) >> L1ENTRY_L2TABLE_ADDR_SHIFT) + +#define READ_MPTC_WAY_MASK GENMASK(18, 16) +#define READ_MPTC_SET_MASK GENMASK(15, 0) +#define READ_MPTC_MASK (READ_MPTC_WAY_MASK | READ_MPTC_SET_MASK) +#define READ_MPTC_WAY(way) FIELD_PREP(READ_MPTC_WAY_MASK, (way)) +#define READ_MPTC_SET(set) FIELD_PREP(READ_MPTC_SET_MASK, (set)) +#define READ_MPTC(set, way) (READ_MPTC_SET(set) | READ_MPTC_WAY(way)) +#define READ_MPTC_TAG_PPN_MASK GENMASK(23, 0) +#define READ_MPTC_TAG_OTHERS_VID_MASK GENMASK(10, 8) +#define READ_MPTC_TAG_OTHERS_GRAN_MASK GENMASK(5, 4) +#define READ_MPTC_TAG_OTHERS_VALID_BIT BIT(0) +#define READ_MPTC_TAG_OTHERS_MASK (READ_MPTC_TAG_OTHERS_VID_MASK | \ + READ_MPTC_TAG_OTHERS_GRAN_MASK | \ + READ_MPTC_TAG_OTHERS_VALID_BIT) #define L1ENTRY_ATTR_L2TABLE_EN BIT(0) #define L1ENTRY_ATTR_GRAN_4K 0x0 #define L1ENTRY_ATTR_GRAN_64K 0x1 #define L1ENTRY_ATTR_GRAN_2M 0x2 -#define L1ENTRY_ATTR_PROT(prot) FIELD_PREP(GENMASK(2, 1), prot) -#define L1ENTRY_ATTR_GRAN(gran) FIELD_PREP(GENMASK(5, 4), gran) +#define L1ENTRY_ATTR_PROT_MASK GENMASK(2, 1) +#define L1ENTRY_ATTR_GRAN_MASK GENMASK(5, 4) +#define L1ENTRY_ATTR_PROT(prot) FIELD_PREP(L1ENTRY_ATTR_PROT_MASK, prot) +#define L1ENTRY_ATTR_GRAN(gran) FIELD_PREP(L1ENTRY_ATTR_GRAN_MASK, gran) #define L1ENTRY_ATTR_1G(prot) L1ENTRY_ATTR_PROT(prot) #define L1ENTRY_ATTR_L2(gran) (L1ENTRY_ATTR_GRAN(gran) | \ L1ENTRY_ATTR_L2TABLE_EN) @@ -128,6 +171,13 @@ static_assert(SMPT_GRAN <= PAGE_SIZE); #define SMPT_NUM_PAGES (SMPT_SIZE / PAGE_SIZE) #define SMPT_ORDER get_order(SMPT_SIZE) +/* SysMMU_SYNC registers, relative to SYSMMU_SYNC_S2_OFFSET. */ +#define REG_NS_SYNC_CMD 0x0 +#define REG_NS_SYNC_COMP 0x4 + +#define SYNC_CMD_SYNC BIT(0) +#define SYNC_COMP_COMPLETE BIT(0) + /* * Iterate over S2MPU gigabyte regions. Skip those that cannot be modified * (the MMIO registers are read only, with reset value MPT_PROT_NONE). diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 40321a57088df9e2a9e009508ad86e8e7ece03a3..e4796c3ad19acf04efecdd07ff1b15758b780cba 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -1011,23 +1011,13 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, * page after fork() + CoW for pfn mappings. We don't always have a * hardware-managed access flag on arm64. */ -static inline bool arch_faults_on_old_pte(void) -{ - WARN_ON(preemptible()); - - return !cpu_has_hw_af(); -} -#define arch_faults_on_old_pte arch_faults_on_old_pte +#define arch_has_hw_pte_young cpu_has_hw_af /* * Experimentally, it's cheap to set the access flag in hardware and we * benefit from prefaulting mappings as 'old' to start with. */ -static inline bool arch_wants_old_prefaulted_pte(void) -{ - return !arch_faults_on_old_pte(); -} -#define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte +#define arch_wants_old_prefaulted_pte cpu_has_hw_af #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 3567520ac7012ed10e017a3ec951804a02ef46aa..e706e55c6494d173932c590891887e55402c24e3 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -394,7 +394,10 @@ #define SYS_LOREA_EL1 sys_reg(3, 0, 10, 4, 1) #define SYS_LORN_EL1 sys_reg(3, 0, 10, 4, 2) #define SYS_LORC_EL1 sys_reg(3, 0, 10, 4, 3) +#define SYS_MPAMIDR_EL1 sys_reg(3, 0, 10, 4, 4) #define SYS_LORID_EL1 sys_reg(3, 0, 10, 4, 7) +#define SYS_MPAM1_EL1 sys_reg(3, 0, 10, 5, 0) +#define SYS_MPAM0_EL1 sys_reg(3, 0, 10, 5, 1) #define SYS_VBAR_EL1 sys_reg(3, 0, 12, 0, 0) #define SYS_DISR_EL1 sys_reg(3, 0, 12, 1, 1) @@ -536,6 +539,10 @@ #define SYS_TFSR_EL2 sys_reg(3, 4, 5, 6, 0) #define SYS_FAR_EL2 sys_reg(3, 4, 6, 0, 0) +#define SYS_MPAMHCR_EL2 sys_reg(3, 4, 10, 4, 0) +#define SYS_MPAMVPMV_EL2 sys_reg(3, 4, 10, 4, 1) +#define SYS_MPAM2_EL2 sys_reg(3, 4, 10, 5, 0) + #define SYS_VDISR_EL2 sys_reg(3, 4, 12, 1, 1) #define __SYS__AP0Rx_EL2(x) sys_reg(3, 4, 12, 8, x) #define SYS_ICH_AP0R0_EL2 __SYS__AP0Rx_EL2(0) diff --git a/arch/arm64/include/asm/vectors.h b/arch/arm64/include/asm/vectors.h index bc9a2145f4194e5d8bff099f36a9c1e9a568df91..f64613a96d5300de67dba128d13e091298967512 100644 --- a/arch/arm64/include/asm/vectors.h +++ b/arch/arm64/include/asm/vectors.h @@ -56,14 +56,14 @@ enum arm64_bp_harden_el1_vectors { DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector); #ifndef CONFIG_UNMAP_KERNEL_AT_EL0 -#define TRAMP_VALIAS 0ul +#define TRAMP_VALIAS 0 #endif static inline const char * arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot) { if (arm64_kernel_unmapped_at_el0()) - return (char *)(TRAMP_VALIAS + SZ_2K * slot); + return (char *)TRAMP_VALIAS + SZ_2K * slot; WARN_ON_ONCE(slot == EL1_VECTOR_KPTI); diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h index 3218ca17f819e286fdb719d92294db0b0a06bd8d..8bc48dec69528e0a6256e3ab83da690452ebae67 100644 --- a/arch/arm64/include/asm/virt.h +++ b/arch/arm64/include/asm/virt.h @@ -72,6 +72,12 @@ void __hyp_reset_vectors(void); DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); +static inline bool is_pkvm_initialized(void) +{ + return IS_ENABLED(CONFIG_KVM) && + static_branch_likely(&kvm_protected_mode_initialized); +} + /* Reports the availability of HYP mode */ static inline bool is_hyp_mode_available(void) { @@ -79,8 +85,7 @@ static inline bool is_hyp_mode_available(void) * If KVM protected mode is initialized, all CPUs must have been booted * in EL2. Avoid checking __boot_cpu_mode as CPUs now come up in EL1. */ - if (IS_ENABLED(CONFIG_KVM) && - static_branch_likely(&kvm_protected_mode_initialized)) + if (is_pkvm_initialized()) return true; return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 && @@ -94,8 +99,7 @@ static inline bool is_hyp_mode_mismatched(void) * If KVM protected mode is initialized, all CPUs must have been booted * in EL2. Avoid checking __boot_cpu_mode as CPUs now come up in EL1. */ - if (IS_ENABLED(CONFIG_KVM) && - static_branch_likely(&kvm_protected_mode_initialized)) + if (is_pkvm_initialized()) return false; return __boot_cpu_mode[0] != __boot_cpu_mode[1]; diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 2858ed8a4220693c80daa09cb4d5ca759bf29a91..8f674fbab573dd3c089313719282026e95ff2592 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -65,6 +65,8 @@ __efistub__ctype = _ctype; KVM_NVHE_ALIAS(kvm_patch_vector_branch); KVM_NVHE_ALIAS(kvm_update_va_mask); KVM_NVHE_ALIAS(kvm_get_kimage_voffset); +KVM_NVHE_ALIAS(kvm_get__text); +KVM_NVHE_ALIAS(kvm_get__etext); KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0); KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter); KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable); @@ -99,9 +101,6 @@ KVM_NVHE_ALIAS(gic_nonsecure_priorities); KVM_NVHE_ALIAS(__start___kvm_ex_table); KVM_NVHE_ALIAS(__stop___kvm_ex_table); -/* Array containing bases of nVHE per-CPU memory regions. */ -KVM_NVHE_ALIAS(kvm_arm_hyp_percpu_base); - /* PMU available static key */ KVM_NVHE_ALIAS(kvm_arm_pmu_available); @@ -116,12 +115,6 @@ KVM_NVHE_ALIAS_HYP(__memcpy, __pi_memcpy); KVM_NVHE_ALIAS_HYP(__memset, __pi_memset); #endif -/* Kernel memory sections */ -KVM_NVHE_ALIAS(__start_rodata); -KVM_NVHE_ALIAS(__end_rodata); -KVM_NVHE_ALIAS(__bss_start); -KVM_NVHE_ALIAS(__bss_stop); - /* Hyp memory sections */ KVM_NVHE_ALIAS(__hyp_idmap_text_start); KVM_NVHE_ALIAS(__hyp_idmap_text_end); diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c index c07d7a03494108a9a75fea9e9bb6b98830b3d0fa..bd26866b864553d47d17924dd6a668d87caa77b5 100644 --- a/arch/arm64/kernel/paravirt.c +++ b/arch/arm64/kernel/paravirt.c @@ -47,7 +47,9 @@ early_param("no-steal-acc", parse_no_stealacc); /* return stolen time in ns by asking the hypervisor */ static u64 pv_steal_clock(int cpu) { + struct pvclock_vcpu_stolen_time *kaddr = NULL; struct pv_time_stolen_time_region *reg; + u64 ret = 0; reg = per_cpu_ptr(&stolen_time_region, cpu); @@ -56,28 +58,38 @@ static u64 pv_steal_clock(int cpu) * online notification callback runs. Until the callback * has run we just return zero. */ - if (!reg->kaddr) + rcu_read_lock(); + kaddr = rcu_dereference(reg->kaddr); + if (!kaddr) { + rcu_read_unlock(); return 0; + } - return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time)); + ret = le64_to_cpu(READ_ONCE(kaddr->stolen_time)); + rcu_read_unlock(); + return ret; } static int stolen_time_cpu_down_prepare(unsigned int cpu) { + struct pvclock_vcpu_stolen_time *kaddr = NULL; struct pv_time_stolen_time_region *reg; reg = this_cpu_ptr(&stolen_time_region); if (!reg->kaddr) return 0; - memunmap(reg->kaddr); - memset(reg, 0, sizeof(*reg)); + kaddr = reg->kaddr; + rcu_assign_pointer(reg->kaddr, NULL); + synchronize_rcu(); + memunmap(kaddr); return 0; } static int stolen_time_cpu_online(unsigned int cpu) { + struct pvclock_vcpu_stolen_time *kaddr = NULL; struct pv_time_stolen_time_region *reg; struct arm_smccc_res res; @@ -88,10 +100,12 @@ static int stolen_time_cpu_online(unsigned int cpu) if (res.a0 == SMCCC_RET_NOT_SUPPORTED) return -EINVAL; - reg->kaddr = memremap(res.a0, + kaddr = memremap(res.a0, sizeof(struct pvclock_vcpu_stolen_time), MEMREMAP_WB); + rcu_assign_pointer(reg->kaddr, kaddr); + if (!reg->kaddr) { pr_warn("Failed to map stolen time data structure\n"); return -ENOMEM; diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 0dab5679a97d58ab746868c9dc8cdfdc9731fc73..e62005317ce2946dc62b5d54b3d061166217960a 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -572,12 +572,10 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, { int err; - if (system_supports_fpsimd()) { - err = sigframe_alloc(user, &user->fpsimd_offset, - sizeof(struct fpsimd_context)); - if (err) - return err; - } + err = sigframe_alloc(user, &user->fpsimd_offset, + sizeof(struct fpsimd_context)); + if (err) + return err; /* fault information, if valid */ if (add_all || current->thread.fault_code) { diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 26d52c39c15f9411081973ebda08835ee3eb41f4..f0e282244752754afc63944589d92f057bbc5ebd 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -50,7 +50,6 @@ DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector); static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); -unsigned long kvm_arm_hyp_percpu_base[NR_CPUS]; DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); /* The VMID used in the VTTBR */ @@ -63,10 +62,6 @@ static bool vgic_present; static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled); DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use); -/* KVM "vendor" hypercalls which may be forwarded to userspace on request. */ -#define KVM_EXIT_HYPERCALL_VALID_MASK (BIT(ARM_SMCCC_KVM_FUNC_MEM_SHARE) | \ - BIT(ARM_SMCCC_KVM_FUNC_MEM_UNSHARE)) - int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) { return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE; @@ -117,16 +112,6 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, } mutex_unlock(&kvm->lock); break; - case KVM_CAP_EXIT_HYPERCALL: - if (cap->args[0] & ~KVM_EXIT_HYPERCALL_VALID_MASK) - return -EINVAL; - - if (cap->args[1] || cap->args[2] || cap->args[3]) - return -EINVAL; - - WRITE_ONCE(kvm->arch.hypercall_exit_enabled, cap->args[0]); - r = 0; - break; default: r = -EINVAL; break; @@ -314,9 +299,6 @@ static int kvm_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ARM_PTRAUTH_GENERIC: r = system_has_full_ptr_auth(); break; - case KVM_CAP_EXIT_HYPERCALL: - r = KVM_EXIT_HYPERCALL_VALID_MASK; - break; default: r = 0; } @@ -341,7 +323,6 @@ static int pkvm_check_extension(struct kvm *kvm, long ext, int kvm_cap) case KVM_CAP_MAX_VCPU_ID: case KVM_CAP_MSI_DEVID: case KVM_CAP_ARM_VM_IPA_SIZE: - case KVM_CAP_EXIT_HYPERCALL: r = kvm_cap; break; case KVM_CAP_GUEST_DEBUG_HW_BPS: @@ -892,12 +873,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) ret = kvm_handle_mmio_return(vcpu); if (ret) return ret; - } else if (run->exit_reason == KVM_EXIT_HYPERCALL) { - smccc_set_retval(vcpu, - vcpu->run->hypercall.ret, - vcpu->run->hypercall.args[0], - vcpu->run->hypercall.args[1], - vcpu->run->hypercall.args[2]); } vcpu_load(vcpu); @@ -1923,13 +1898,13 @@ static void teardown_hyp_mode(void) free_hyp_pgds(); for_each_possible_cpu(cpu) { free_page(per_cpu(kvm_arm_hyp_stack_page, cpu)); - free_pages(kvm_arm_hyp_percpu_base[cpu], nvhe_percpu_order()); + free_pages(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu], nvhe_percpu_order()); } } static int do_pkvm_init(u32 hyp_va_bits) { - void *per_cpu_base = kvm_ksym_ref(kvm_arm_hyp_percpu_base); + void *per_cpu_base = kvm_ksym_ref(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)); int ret; preempt_disable(); @@ -2030,7 +2005,7 @@ static int init_hyp_mode(void) page_addr = page_address(page); memcpy(page_addr, CHOOSE_NVHE_SYM(__per_cpu_start), nvhe_percpu_size()); - kvm_arm_hyp_percpu_base[cpu] = (unsigned long)page_addr; + kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu] = (unsigned long)page_addr; } /* @@ -2098,7 +2073,7 @@ static int init_hyp_mode(void) } for_each_possible_cpu(cpu) { - char *percpu_begin = (char *)kvm_arm_hyp_percpu_base[cpu]; + char *percpu_begin = (char *)kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu]; char *percpu_end = percpu_begin + nvhe_percpu_size(); /* Map Hyp percpu pages */ diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 2b988ba29f408fb0277246343e331072d2bec9e4..dbb7097396f128f9f4a4e06a052c6c72fea02451 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -349,3 +349,4 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%016lx\n", spsr, elr_virt, esr, far, hpfar, par, vcpu); } +EXPORT_SYMBOL_GPL(nvhe_hyp_panic_handler); diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c index c5d0097154020a11410b821e3bcfaa2013ebd9a0..14a80b0e2f91de9e1e3b9c97d5bef47100817602 100644 --- a/arch/arm64/kvm/hyp/exception.c +++ b/arch/arm64/kvm/hyp/exception.c @@ -60,31 +60,12 @@ static void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val) vcpu->arch.ctxt.spsr_und = val; } -/* - * This performs the exception entry at a given EL (@target_mode), stashing PC - * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE. - * The EL passed to this function *must* be a non-secure, privileged mode with - * bit 0 being set (PSTATE.SP == 1). - * - * When an exception is taken, most PSTATE fields are left unchanged in the - * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all - * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx - * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0. - * - * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429. - * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426. - * - * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from - * MSB to LSB. - */ -static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, - enum exception_type type) +unsigned long get_except64_offset(unsigned long psr, unsigned long target_mode, + enum exception_type type) { - unsigned long sctlr, vbar, old, new, mode; + u64 mode = psr & (PSR_MODE_MASK | PSR_MODE32_BIT); u64 exc_offset; - mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT); - if (mode == target_mode) exc_offset = CURRENT_EL_SP_ELx_VECTOR; else if ((mode | PSR_MODE_THREAD_BIT) == target_mode) @@ -94,28 +75,32 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, else exc_offset = LOWER_EL_AArch32_VECTOR; - switch (target_mode) { - case PSR_MODE_EL1h: - vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1); - sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1); - __vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1); - break; - default: - /* Don't do that */ - BUG(); - } - - *vcpu_pc(vcpu) = vbar + exc_offset + type; + return exc_offset + type; +} - old = *vcpu_cpsr(vcpu); - new = 0; +/* + * When an exception is taken, most PSTATE fields are left unchanged in the + * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all + * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx + * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0. + * + * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429. + * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426. + * + * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from + * MSB to LSB. + */ +unsigned long get_except64_cpsr(unsigned long old, bool has_mte, + unsigned long sctlr, unsigned long target_mode) +{ + u64 new = 0; new |= (old & PSR_N_BIT); new |= (old & PSR_Z_BIT); new |= (old & PSR_C_BIT); new |= (old & PSR_V_BIT); - if (kvm_has_mte(vcpu->kvm)) + if (has_mte) new |= PSR_TCO_BIT; new |= (old & PSR_DIT_BIT); @@ -151,6 +136,36 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, new |= target_mode; + return new; +} + +/* + * This performs the exception entry at a given EL (@target_mode), stashing PC + * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE. + * The EL passed to this function *must* be a non-secure, privileged mode with + * bit 0 being set (PSTATE.SP == 1). + */ +static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, + enum exception_type type) +{ + u64 offset = get_except64_offset(*vcpu_cpsr(vcpu), target_mode, type); + unsigned long sctlr, vbar, old, new; + + switch (target_mode) { + case PSR_MODE_EL1h: + vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1); + sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1); + __vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1); + break; + default: + /* Don't do that */ + BUG(); + } + + *vcpu_pc(vcpu) = vbar + offset; + + old = *vcpu_cpsr(vcpu); + new = get_except64_cpsr(old, kvm_has_mte(vcpu->kvm), sctlr, target_mode); *vcpu_cpsr(vcpu) = new; __vcpu_write_spsr(vcpu, old); } diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h index 2367fe153ad351631714a52c7444a10b3efab6ee..69bce1f017174dd49d9e7986155dd555c4e78daf 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h +++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h @@ -15,15 +15,24 @@ struct pkvm_iommu_ops { * Driver-specific arguments are passed in a buffer shared by the host. * The buffer memory has been pinned in EL2 but host retains R/W access. * Extra care must be taken when reading from it to avoid TOCTOU bugs. + * If the driver maintains its own page tables, it is expected to + * initialize them to all memory owned by the host. * Driver initialization lock held during callback. */ int (*init)(void *data, size_t size); /* - * Driver-specific validation of device registration inputs. - * This should be stateless. No locks are held at entry. + * Driver-specific validation of a device that is being registered. + * All fields of the device struct have been populated. + * Called with the host lock held. */ - int (*validate)(phys_addr_t base, size_t size); + int (*validate)(struct pkvm_iommu *dev); + + /* + * Validation of a new child device that is being register by + * the parent device the child selected. Called with the host lock held. + */ + int (*validate_child)(struct pkvm_iommu *dev, struct pkvm_iommu *child); /* * Callback to apply a host stage-2 mapping change at driver level. @@ -56,7 +65,10 @@ struct pkvm_iommu_ops { }; struct pkvm_iommu { + struct pkvm_iommu *parent; struct list_head list; + struct list_head siblings; + struct list_head children; unsigned long id; const struct pkvm_iommu_ops *ops; phys_addr_t pa; @@ -70,9 +82,11 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si int __pkvm_iommu_register(unsigned long dev_id, enum pkvm_iommu_driver_id drv_id, phys_addr_t dev_pa, size_t dev_size, + unsigned long parent_id, void *kern_mem_va, size_t mem_size); int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event); +int __pkvm_iommu_finalize(void); int pkvm_iommu_host_stage2_adjust_range(phys_addr_t addr, phys_addr_t *start, phys_addr_t *end); bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, @@ -81,5 +95,6 @@ void pkvm_iommu_host_stage2_idmap(phys_addr_t start, phys_addr_t end, enum kvm_pgtable_prot prot); extern const struct pkvm_iommu_ops pkvm_s2mpu_ops; +extern const struct pkvm_iommu_ops pkvm_sysmmu_sync_ops; #endif /* __ARM64_KVM_NVHE_IOMMU_H__ */ diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index 3f4f90f55c5c4961fddc18fa8c4638b148c1eacc..e796ff5e74fb16fd698e48ab751ddf36b458fb83 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -91,6 +91,9 @@ int refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages, struct kvm_hyp_memcache *host_mc); void reclaim_guest_pages(struct kvm_shadow_vm *vm, struct kvm_hyp_memcache *mc); +void psci_mem_protect_inc(void); +void psci_mem_protect_dec(void); + static __always_inline void __load_host_stage2(void) { if (static_branch_likely(&kvm_protected_mode_initialized)) diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c index 4dbd42a867565c932e1e6ac5db36917b90011943..1fd6c6e267babca8bb2479ed7221667ddd6e1f65 100644 --- a/arch/arm64/kvm/hyp/nvhe/ffa.c +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c @@ -176,6 +176,7 @@ static void do_ffa_rxtx_map(struct arm_smccc_res *res, DECLARE_REG(phys_addr_t, rx, ctxt, 2); DECLARE_REG(u32, npages, ctxt, 3); int ret = 0; + void *rx_virt, *tx_virt; if (npages != (KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) / FFA_PAGE_SIZE) { ret = FFA_RET_INVALID_PARAMETERS; @@ -209,8 +210,22 @@ static void do_ffa_rxtx_map(struct arm_smccc_res *res, goto err_unshare_tx; } - host_kvm.ffa.tx = hyp_phys_to_virt(tx); - host_kvm.ffa.rx = hyp_phys_to_virt(rx); + tx_virt = hyp_phys_to_virt(tx); + ret = hyp_pin_shared_mem(tx_virt, tx_virt + 1); + if (ret) { + ret = FFA_RET_INVALID_PARAMETERS; + goto err_unshare_rx; + } + + rx_virt = hyp_phys_to_virt(rx); + ret = hyp_pin_shared_mem(rx_virt, rx_virt + 1); + if (ret) { + ret = FFA_RET_INVALID_PARAMETERS; + goto err_unpin_tx; + } + + host_kvm.ffa.tx = tx_virt; + host_kvm.ffa.rx = rx_virt; out_unlock: hyp_spin_unlock(&host_kvm.ffa.lock); @@ -218,6 +233,10 @@ out: ffa_to_smccc_res(res, ret); return; +err_unpin_tx: + hyp_unpin_shared_mem(tx_virt, tx_virt + 1); +err_unshare_rx: + __pkvm_host_unshare_hyp(hyp_phys_to_pfn(rx)); err_unshare_tx: __pkvm_host_unshare_hyp(hyp_phys_to_pfn(tx)); err_unmap: @@ -242,9 +261,11 @@ static void do_ffa_rxtx_unmap(struct arm_smccc_res *res, goto out_unlock; } + hyp_unpin_shared_mem(host_kvm.ffa.tx, host_kvm.ffa.tx + 1); WARN_ON(__pkvm_host_unshare_hyp(hyp_virt_to_pfn(host_kvm.ffa.tx))); host_kvm.ffa.tx = NULL; + hyp_unpin_shared_mem(host_kvm.ffa.rx, host_kvm.ffa.rx + 1); WARN_ON(__pkvm_host_unshare_hyp(hyp_virt_to_pfn(host_kvm.ffa.rx))); host_kvm.ffa.rx = NULL; @@ -263,10 +284,13 @@ static u32 __ffa_host_share_ranges(struct ffa_mem_region_addr_range *ranges, for (i = 0; i < nranges; ++i) { struct ffa_mem_region_addr_range *range = &ranges[i]; - u64 npages = (range->pg_cnt * FFA_PAGE_SIZE) / PAGE_SIZE; + u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE; u64 pfn = hyp_phys_to_pfn(range->address); - if (__pkvm_host_share_ffa(pfn, npages)) + if (!PAGE_ALIGNED(sz)) + break; + + if (__pkvm_host_share_ffa(pfn, sz / PAGE_SIZE)) break; } @@ -280,10 +304,13 @@ static u32 __ffa_host_unshare_ranges(struct ffa_mem_region_addr_range *ranges, for (i = 0; i < nranges; ++i) { struct ffa_mem_region_addr_range *range = &ranges[i]; - u64 npages = (range->pg_cnt * FFA_PAGE_SIZE) / PAGE_SIZE; + u64 sz = (u64)range->pg_cnt * FFA_PAGE_SIZE; u64 pfn = hyp_phys_to_pfn(range->address); - if (__pkvm_host_unshare_ffa(pfn, npages)) + if (!PAGE_ALIGNED(sz)) + break; + + if (__pkvm_host_unshare_ffa(pfn, sz / PAGE_SIZE)) break; } diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S index 8fc25633d6cc906e23f7230aa12ea49695af4058..85788e511156af9f927a4807498f6b7a71ff30ed 100644 --- a/arch/arm64/kvm/hyp/nvhe/host.S +++ b/arch/arm64/kvm/hyp/nvhe/host.S @@ -198,15 +198,15 @@ SYM_CODE_START(__kvm_hyp_host_vector) invalid_host_el2_vect // FIQ EL2h invalid_host_el2_vect // Error EL2h - host_el1_sync_vect // Synchronous 64-bit EL1 - invalid_host_el1_vect // IRQ 64-bit EL1 - invalid_host_el1_vect // FIQ 64-bit EL1 - invalid_host_el1_vect // Error 64-bit EL1 - - invalid_host_el1_vect // Synchronous 32-bit EL1 - invalid_host_el1_vect // IRQ 32-bit EL1 - invalid_host_el1_vect // FIQ 32-bit EL1 - invalid_host_el1_vect // Error 32-bit EL1 + host_el1_sync_vect // Synchronous 64-bit EL1/EL0 + invalid_host_el1_vect // IRQ 64-bit EL1/EL0 + invalid_host_el1_vect // FIQ 64-bit EL1/EL0 + invalid_host_el1_vect // Error 64-bit EL1/EL0 + + host_el1_sync_vect // Synchronous 32-bit EL1/EL0 + invalid_host_el1_vect // IRQ 32-bit EL1/EL0 + invalid_host_el1_vect // FIQ 32-bit EL1/EL0 + invalid_host_el1_vect // Error 32-bit EL1/EL0 SYM_CODE_END(__kvm_hyp_host_vector) /* diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index fae3dd83bbdf41743e74691e17bae9804761e066..14f9da9f87b90659330a3052bd4fd49d8bc03b5f 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -696,21 +696,63 @@ static void handle___pkvm_vcpu_sync_state(struct kvm_cpu_context *host_ctxt) } } +static struct kvm_vcpu *__get_current_vcpu(struct kvm_vcpu *vcpu, + struct pkvm_loaded_state **state) +{ + struct pkvm_loaded_state *sstate = NULL; + + vcpu = kern_hyp_va(vcpu); + + if (unlikely(is_protected_kvm_enabled())) { + sstate = this_cpu_ptr(&loaded_state); + + if (!sstate || vcpu != sstate->vcpu->arch.pkvm.host_vcpu) { + sstate = NULL; + vcpu = NULL; + } + } + + *state = sstate; + return vcpu; +} + +#define get_current_vcpu(ctxt, regnr, statepp) \ + ({ \ + DECLARE_REG(struct kvm_vcpu *, __vcpu, ctxt, regnr); \ + __get_current_vcpu(__vcpu, statepp); \ + }) + +#define get_current_vcpu_from_cpu_if(ctxt, regnr, statepp) \ + ({ \ + DECLARE_REG(struct vgic_v3_cpu_if *, cif, ctxt, regnr); \ + struct kvm_vcpu *__vcpu; \ + __vcpu = container_of(cif, \ + struct kvm_vcpu, \ + arch.vgic_cpu.vgic_v3); \ + \ + __get_current_vcpu(__vcpu, statepp); \ + }) + static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1); + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; int ret; - if (unlikely(is_protected_kvm_enabled())) { - struct pkvm_loaded_state *state = this_cpu_ptr(&loaded_state); + vcpu = get_current_vcpu(host_ctxt, 1, &shadow_state); + if (!vcpu) { + cpu_reg(host_ctxt, 1) = -EINVAL; + return; + } - flush_shadow_state(state); + if (unlikely(shadow_state)) { + flush_shadow_state(shadow_state); - ret = __kvm_vcpu_run(state->vcpu); + ret = __kvm_vcpu_run(shadow_state->vcpu); - sync_shadow_state(state, ret); + sync_shadow_state(shadow_state, ret); - if (state->vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { + if (shadow_state->vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { /* * The guest has used the FP, trap all accesses * from the host (both FP and SVE). @@ -722,7 +764,7 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt) sysreg_clear_set(cptr_el2, 0, reg); } } else { - ret = __kvm_vcpu_run(kern_hyp_va(vcpu)); + ret = __kvm_vcpu_run(vcpu); } cpu_reg(host_ctxt, 1) = ret; @@ -759,20 +801,19 @@ out: static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1); - - vcpu = kern_hyp_va(vcpu); + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; - if (unlikely(is_protected_kvm_enabled())) { - struct pkvm_loaded_state *state = this_cpu_ptr(&loaded_state); + vcpu = get_current_vcpu(host_ctxt, 1, &shadow_state); + if (!vcpu) + return; - /* - * A shadow vcpu can never be updated from EL1, and we - * must have a vcpu loaded when protected mode is - * enabled. - */ - if (!state->vcpu || state->is_protected) + if (shadow_state) { + /* This only applies to non-protected VMs */ + if (shadow_state->is_protected) return; + + vcpu = shadow_state->vcpu; } __kvm_adjust_pc(vcpu); @@ -835,56 +876,50 @@ static void handle___kvm_get_mdcr_el2(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __kvm_get_mdcr_el2(); } -static struct vgic_v3_cpu_if *get_shadow_vgic_v3_cpu_if(struct vgic_v3_cpu_if *cpu_if) -{ - if (unlikely(is_protected_kvm_enabled())) { - struct pkvm_loaded_state *state = this_cpu_ptr(&loaded_state); - struct kvm_vcpu *host_vcpu; - - if (!state->vcpu) - return NULL; - - host_vcpu = state->vcpu->arch.pkvm.host_vcpu; - - if (&host_vcpu->arch.vgic_cpu.vgic_v3 != cpu_if) - return NULL; - } - - return cpu_if; -} - static void handle___vgic_v3_save_vmcr_aprs(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1); - struct vgic_v3_cpu_if *shadow_cpu_if; - - cpu_if = kern_hyp_va(cpu_if); - shadow_cpu_if = get_shadow_vgic_v3_cpu_if(cpu_if); + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; - __vgic_v3_save_vmcr_aprs(shadow_cpu_if); + vcpu = get_current_vcpu_from_cpu_if(host_ctxt, 1, &shadow_state); + if (!vcpu) + return; - if (cpu_if != shadow_cpu_if) { + if (shadow_state) { + struct vgic_v3_cpu_if *shadow_cpu_if, *cpu_if; int i; + shadow_cpu_if = &shadow_state->vcpu->arch.vgic_cpu.vgic_v3; + __vgic_v3_save_vmcr_aprs(shadow_cpu_if); + + cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; + cpu_if->vgic_vmcr = shadow_cpu_if->vgic_vmcr; for (i = 0; i < ARRAY_SIZE(cpu_if->vgic_ap0r); i++) { cpu_if->vgic_ap0r[i] = shadow_cpu_if->vgic_ap0r[i]; cpu_if->vgic_ap1r[i] = shadow_cpu_if->vgic_ap1r[i]; } + } else { + __vgic_v3_save_vmcr_aprs(&vcpu->arch.vgic_cpu.vgic_v3); } } static void handle___vgic_v3_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt) { - DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1); - struct vgic_v3_cpu_if *shadow_cpu_if; + struct pkvm_loaded_state *shadow_state; + struct kvm_vcpu *vcpu; - cpu_if = kern_hyp_va(cpu_if); - shadow_cpu_if = get_shadow_vgic_v3_cpu_if(cpu_if); + vcpu = get_current_vcpu_from_cpu_if(host_ctxt, 1, &shadow_state); + if (!vcpu) + return; - if (cpu_if != shadow_cpu_if) { + if (shadow_state) { + struct vgic_v3_cpu_if *shadow_cpu_if, *cpu_if; int i; + shadow_cpu_if = &shadow_state->vcpu->arch.vgic_cpu.vgic_v3; + cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; + shadow_cpu_if->vgic_vmcr = cpu_if->vgic_vmcr; /* Should be a one-off */ shadow_cpu_if->vgic_sre = (ICC_SRE_EL1_DIB | @@ -894,9 +929,11 @@ static void handle___vgic_v3_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt shadow_cpu_if->vgic_ap0r[i] = cpu_if->vgic_ap0r[i]; shadow_cpu_if->vgic_ap1r[i] = cpu_if->vgic_ap1r[i]; } - } - __vgic_v3_restore_vmcr_aprs(shadow_cpu_if); + __vgic_v3_restore_vmcr_aprs(shadow_cpu_if); + } else { + __vgic_v3_restore_vmcr_aprs(&vcpu->arch.vgic_cpu.vgic_v3); + } } static void handle___pkvm_init(struct kvm_cpu_context *host_ctxt) @@ -991,11 +1028,13 @@ static void handle___pkvm_iommu_register(struct kvm_cpu_context *host_ctxt) DECLARE_REG(enum pkvm_iommu_driver_id, drv_id, host_ctxt, 2); DECLARE_REG(phys_addr_t, dev_pa, host_ctxt, 3); DECLARE_REG(size_t, dev_size, host_ctxt, 4); - DECLARE_REG(void *, mem, host_ctxt, 5); - DECLARE_REG(size_t, mem_size, host_ctxt, 6); + DECLARE_REG(unsigned long, parent_id, host_ctxt, 5); + DECLARE_REG(void *, mem, host_ctxt, 6); + DECLARE_REG(size_t, mem_size, host_ctxt, 7); cpu_reg(host_ctxt, 1) = __pkvm_iommu_register(dev_id, drv_id, dev_pa, - dev_size, mem, mem_size); + dev_size, parent_id, + mem, mem_size); } static void handle___pkvm_iommu_pm_notify(struct kvm_cpu_context *host_ctxt) @@ -1006,6 +1045,11 @@ static void handle___pkvm_iommu_pm_notify(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __pkvm_iommu_pm_notify(dev_id, event); } +static void handle___pkvm_iommu_finalize(struct kvm_cpu_context *host_ctxt) +{ + cpu_reg(host_ctxt, 1) = __pkvm_iommu_finalize(); +} + typedef void (*hcall_t)(struct kvm_cpu_context *); #define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x @@ -1042,14 +1086,48 @@ static const hcall_t host_hcall[] = { HANDLE_FUNC(__pkvm_iommu_driver_init), HANDLE_FUNC(__pkvm_iommu_register), HANDLE_FUNC(__pkvm_iommu_pm_notify), + HANDLE_FUNC(__pkvm_iommu_finalize), }; +static inline u64 kernel__text_addr(void) +{ + u64 val; + + asm volatile(ALTERNATIVE_CB("movz %0, #0\n" + "movk %0, #0, lsl #16\n" + "movk %0, #0, lsl #32\n" + "movk %0, #0, lsl #48\n", + kvm_get__text) + : "=r" (val)); + + return val; +} + +static inline u64 kernel__etext_addr(void) +{ + u64 val; + + asm volatile(ALTERNATIVE_CB("movz %0, #0\n" + "movk %0, #0, lsl #16\n" + "movk %0, #0, lsl #32\n" + "movk %0, #0, lsl #48\n", + kvm_get__etext) + : "=r" (val)); + + return val; +} + static void handle_host_hcall(struct kvm_cpu_context *host_ctxt) { DECLARE_REG(unsigned long, id, host_ctxt, 0); + u64 elr = read_sysreg_el2(SYS_ELR) - 4; unsigned long hcall_min = 0; hcall_t hfn; + /* Check for the provenance of the HC */ + if (unlikely(elr < kernel__text_addr() || elr >= kernel__etext_addr())) + goto inval; + /* * If pKVM has been initialised then reject any calls to the * early "privileged" hypercalls. Note that we cannot reject diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-smp.c b/arch/arm64/kvm/hyp/nvhe/hyp-smp.c index 9f54833af400972670ceddec0a7904d190a005e5..04d194583f1e47a42079726276bc941cdc146641 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-smp.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-smp.c @@ -23,6 +23,8 @@ u64 cpu_logical_map(unsigned int cpu) return hyp_cpu_logical_map[cpu]; } +unsigned long __ro_after_init kvm_arm_hyp_percpu_base[NR_CPUS]; + unsigned long __hyp_per_cpu_offset(unsigned int cpu) { unsigned long *cpu_base_array; diff --git a/arch/arm64/kvm/hyp/nvhe/iommu.c b/arch/arm64/kvm/hyp/nvhe/iommu.c index 9b659abc79570ed2b93cfb511b91e07e0450289d..3fe47e54208834657f58aca7480569614eed6b4f 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu.c @@ -31,6 +31,12 @@ static struct pkvm_iommu_driver iommu_drivers[PKVM_IOMMU_NR_DRIVERS]; /* IOMMU device list. Must only be accessed with host_kvm.lock held. */ static LIST_HEAD(iommu_list); +static bool iommu_finalized; +static DEFINE_HYP_SPINLOCK(iommu_registration_lock); + +static void *iommu_mem_pool; +static size_t iommu_mem_remaining; + static void assert_host_component_locked(void) { hyp_assert_lock_held(&host_kvm.lock); @@ -65,6 +71,8 @@ static const struct pkvm_iommu_ops *get_driver_ops(enum pkvm_iommu_driver_id id) switch (id) { case PKVM_IOMMU_DRIVER_S2MPU: return IS_ENABLED(CONFIG_KVM_S2MPU) ? &pkvm_s2mpu_ops : NULL; + case PKVM_IOMMU_DRIVER_SYSMMU_SYNC: + return IS_ENABLED(CONFIG_KVM_S2MPU) ? &pkvm_sysmmu_sync_ops : NULL; default: return NULL; } @@ -89,41 +97,56 @@ static inline bool is_driver_ready(struct pkvm_iommu_driver *drv) return atomic_read(&drv->state) == IOMMU_DRIVER_READY; } +static size_t __iommu_alloc_size(struct pkvm_iommu_driver *drv) +{ + return ALIGN(sizeof(struct pkvm_iommu) + drv->ops->data_size, + sizeof(unsigned long)); +} + /* Global memory pool for allocating IOMMU list entry structs. */ -static inline struct pkvm_iommu * -alloc_iommu_list_entry(struct pkvm_iommu_driver *drv, void *mem, size_t mem_size) +static inline struct pkvm_iommu *alloc_iommu(struct pkvm_iommu_driver *drv, + void *mem, size_t mem_size) { - static void *pool; - static size_t remaining; - static DEFINE_HYP_SPINLOCK(lock); - size_t size = sizeof(struct pkvm_iommu) + drv->ops->data_size; + size_t size = __iommu_alloc_size(drv); void *ptr; - size = ALIGN(size, sizeof(unsigned long)); - - hyp_spin_lock(&lock); + assert_host_component_locked(); /* * If new memory is being provided, replace the existing pool with it. * Any remaining memory in the pool is discarded. */ if (mem && mem_size) { - pool = mem; - remaining = mem_size; + iommu_mem_pool = mem; + iommu_mem_remaining = mem_size; } - if (size <= remaining) { - ptr = pool; - pool += size; - remaining -= size; - } else { - ptr = NULL; - } + if (size > iommu_mem_remaining) + return NULL; - hyp_spin_unlock(&lock); + ptr = iommu_mem_pool; + iommu_mem_pool += size; + iommu_mem_remaining -= size; return ptr; } +static inline void free_iommu(struct pkvm_iommu_driver *drv, struct pkvm_iommu *ptr) +{ + size_t size = __iommu_alloc_size(drv); + + assert_host_component_locked(); + + if (!ptr) + return; + + /* Only allow freeing the last allocated buffer. */ + if ((void*)ptr + size != iommu_mem_pool) + return; + + iommu_mem_pool -= size; + iommu_mem_remaining += size; +} + static bool is_overlap(phys_addr_t r1_start, size_t r1_size, phys_addr_t r2_start, size_t r2_size) { @@ -151,22 +174,23 @@ static bool is_mmio_range(phys_addr_t base, size_t size) return true; } -static int __snapshot_host_stage2(u64 start, u64 end, u32 level, +static int __snapshot_host_stage2(u64 start, u64 pa_max, u32 level, kvm_pte_t *ptep, enum kvm_pgtable_walk_flags flags, void * const arg) { struct pkvm_iommu_driver * const drv = arg; - enum kvm_pgtable_prot prot; + u64 end = start + kvm_granule_size(level); kvm_pte_t pte = *ptep; /* * Valid stage-2 entries are created lazily, invalid ones eagerly. * Note: In the future we may need to check if [start,end) is MMIO. + * Note: Drivers initialize their PTs to all memory owned by the host, + * so we only call the driver on regions where that is not the case. */ - prot = (!pte || kvm_pte_valid(pte)) ? PKVM_HOST_MEM_PROT : 0; - - drv->ops->host_stage2_idmap_prepare(start, end, prot); + if (pte && !kvm_pte_valid(pte)) + drv->ops->host_stage2_idmap_prepare(start, end, /*prot*/ 0); return 0; } @@ -231,13 +255,24 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si data = kern_hyp_va(data); + /* New driver initialization not allowed after __pkvm_iommu_finalize(). */ + hyp_spin_lock(&iommu_registration_lock); + if (iommu_finalized) { + ret = -EPERM; + goto out_unlock; + } + drv = get_driver(id); ops = get_driver_ops(id); - if (!drv || !ops) - return -EINVAL; + if (!drv || !ops) { + ret = -EINVAL; + goto out_unlock; + } - if (!driver_acquire_init(drv)) - return -EBUSY; + if (!driver_acquire_init(drv)) { + ret = -EBUSY; + goto out_unlock; + } drv->ops = ops; @@ -249,7 +284,7 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si hyp_unpin_shared_mem(data, data + size); } if (ret) - goto out; + goto out_release; } /* @@ -262,36 +297,47 @@ int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t si driver_release_init(drv, /*success=*/true); host_unlock_component(); -out: +out_release: if (ret) driver_release_init(drv, /*success=*/false); + +out_unlock: + hyp_spin_unlock(&iommu_registration_lock); return ret; } int __pkvm_iommu_register(unsigned long dev_id, enum pkvm_iommu_driver_id drv_id, phys_addr_t dev_pa, size_t dev_size, + unsigned long parent_id, void *kern_mem_va, size_t mem_size) { struct pkvm_iommu *dev = NULL; struct pkvm_iommu_driver *drv; - void *dev_va, *mem_va = NULL; + void *mem_va = NULL; int ret = 0; - drv = get_driver(drv_id); - if (!drv || !is_driver_ready(drv)) - return -ENOENT; + /* New device registration not allowed after __pkvm_iommu_finalize(). */ + hyp_spin_lock(&iommu_registration_lock); + if (iommu_finalized) { + ret = -EPERM; + goto out_unlock; + } - if (!PAGE_ALIGNED(dev_pa) || !PAGE_ALIGNED(dev_size)) - return -EINVAL; + drv = get_driver(drv_id); + if (!drv || !is_driver_ready(drv)) { + ret = -ENOENT; + goto out_unlock; + } - if (!is_mmio_range(dev_pa, dev_size)) - return -EINVAL; + if (!PAGE_ALIGNED(dev_pa) || !PAGE_ALIGNED(dev_size)) { + ret = -EINVAL; + goto out_unlock; + } - if (drv->ops->validate) { - ret = drv->ops->validate(dev_pa, dev_size); - if (ret) - return ret; + if (!is_mmio_range(dev_pa, dev_size)) { + ret = -EINVAL; + goto out_unlock; } /* @@ -301,52 +347,102 @@ int __pkvm_iommu_register(unsigned long dev_id, if (kern_mem_va && mem_size) { mem_va = kern_hyp_va(kern_mem_va); - if (!PAGE_ALIGNED(mem_va) || !PAGE_ALIGNED(mem_size)) - return -EINVAL; + if (!PAGE_ALIGNED(mem_va) || !PAGE_ALIGNED(mem_size)) { + ret = -EINVAL; + goto out_unlock; + } ret = __pkvm_host_donate_hyp(hyp_virt_to_pfn(mem_va), mem_size >> PAGE_SHIFT); if (ret) - return ret; + goto out_unlock; } - /* Allocate memory for the new device entry. */ - dev = alloc_iommu_list_entry(drv, mem_va, mem_size); - if (!dev) - return -ENOMEM; + host_lock_component(); - /* Create EL2 mapping for the device. */ - dev_va = (void *)__pkvm_create_private_mapping(dev_pa, dev_size, - PAGE_HYP_DEVICE); - if (IS_ERR(dev_va)) - return PTR_ERR(dev_va); + /* Allocate memory for the new device entry. */ + dev = alloc_iommu(drv, mem_va, mem_size); + if (!dev) { + ret = -ENOMEM; + goto out_free; + } /* Populate the new device entry. */ *dev = (struct pkvm_iommu){ + .children = LIST_HEAD_INIT(dev->children), .id = dev_id, .ops = drv->ops, .pa = dev_pa, - .va = dev_va, .size = dev_size, }; - /* Take the host_kvm lock to block host stage-2 changes. */ - host_lock_component(); if (!validate_against_existing_iommus(dev)) { ret = -EBUSY; - goto out; + goto out_free; + } + + if (parent_id) { + dev->parent = find_iommu_by_id(parent_id); + if (!dev->parent) { + ret = -EINVAL; + goto out_free; + } + + if (dev->parent->ops->validate_child) { + ret = dev->parent->ops->validate_child(dev->parent, dev); + if (ret) + goto out_free; + } } - /* Unmap the device's MMIO range from host stage-2. */ + if (dev->ops->validate) { + ret = dev->ops->validate(dev); + if (ret) + goto out_free; + } + + /* + * Unmap the device's MMIO range from host stage-2. If registration + * is successful, future attempts to re-map will be blocked by + * pkvm_iommu_host_stage2_adjust_range. + */ ret = host_stage2_unmap_dev_locked(dev_pa, dev_size); if (ret) - goto out; + goto out_free; + + /* Create EL2 mapping for the device. Do it last as it is irreversible. */ + dev->va = (void *)__pkvm_create_private_mapping(dev_pa, dev_size, + PAGE_HYP_DEVICE); + if (IS_ERR(dev->va)) { + ret = PTR_ERR(dev->va); + goto out_free; + } /* Register device and prevent host from mapping the MMIO range. */ list_add_tail(&dev->list, &iommu_list); + if (dev->parent) + list_add_tail(&dev->siblings, &dev->parent->children); -out: +out_free: + if (ret) + free_iommu(drv, dev); host_unlock_component(); + +out_unlock: + hyp_spin_unlock(&iommu_registration_lock); + return ret; +} + +int __pkvm_iommu_finalize(void) +{ + int ret = 0; + + hyp_spin_lock(&iommu_registration_lock); + if (!iommu_finalized) + iommu_finalized = true; + else + ret = -EPERM; + hyp_spin_unlock(&iommu_registration_lock); return ret; } @@ -360,10 +456,12 @@ int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event) if (dev) { if (event == PKVM_IOMMU_PM_SUSPEND) { ret = dev->ops->suspend ? dev->ops->suspend(dev) : 0; - dev->powered = !!ret; + if (!ret) + dev->powered = false; } else if (event == PKVM_IOMMU_PM_RESUME) { ret = dev->ops->resume ? dev->ops->resume(dev) : 0; - dev->powered = !ret; + if (!ret) + dev->powered = true; } else { ret = -EINVAL; } @@ -418,7 +516,8 @@ bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, if (pa < dev->pa || pa >= dev->pa + dev->size) continue; - if (!dev->powered || !dev->ops->host_dabt_handler || + /* No 'powered' check - the host assumes it is powered. */ + if (!dev->ops->host_dabt_handler || !dev->ops->host_dabt_handler(dev, host_ctxt, esr, pa - dev->pa)) return false; diff --git a/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c b/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c index 3fbd68c84218641038839107c8bcc87c1eea03c4..ff5d7d1044e522e4340a39c92badf83141ccabbf 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu/s2mpu.c @@ -28,6 +28,9 @@ (CONTEXT_CFG_VALID_VID_CTX_VID(ctxid, vid) \ | (((ctxid) < (nr_ctx)) ? CONTEXT_CFG_VALID_VID_CTX_VALID(ctxid) : 0)) +#define for_each_child(child, dev) \ + list_for_each_entry((child), &(dev)->children, siblings) + struct s2mpu_drv_data { u32 version; u32 context_cfg_valid_vid; @@ -155,6 +158,13 @@ static void __set_control_regs(struct pkvm_iommu *dev) writel_relaxed(ctrl0, dev->va + REG_NS_CTRL0); } +/* Poll the given SFR until its value has all bits of a given mask set. */ +static void __wait_until(void __iomem *addr, u32 mask) +{ + while ((readl_relaxed(addr) & mask) != mask) + continue; +} + /* Poll the given SFR as long as its value has all bits of a given mask set. */ static void __wait_while(void __iomem *addr, u32 mask) { @@ -164,6 +174,17 @@ static void __wait_while(void __iomem *addr, u32 mask) static void __wait_for_invalidation_complete(struct pkvm_iommu *dev) { + struct pkvm_iommu *sync; + + /* + * Wait for transactions to drain if SysMMU_SYNCs were registered. + * Assumes that they are in the same power domain as the S2MPU. + */ + for_each_child(sync, dev) { + writel_relaxed(SYNC_CMD_SYNC, sync->va + REG_NS_SYNC_CMD); + __wait_until(sync->va + REG_NS_SYNC_COMP, SYNC_COMP_COMPLETE); + } + /* Must not access SFRs while S2MPU is busy invalidating (v9 only). */ if (is_version(dev, S2MPU_VERSION_9)) { __wait_while(dev->va + REG_NS_STATUS, @@ -372,15 +393,44 @@ static u32 host_mmio_reg_access_mask(size_t off, bool is_write) const u32 write_only = is_write ? read_write : no_access; u32 masked_off; - /* IRQ handler can clear interrupts. */ - if (off == REG_NS_INTERRUPT_CLEAR) + switch (off) { + /* Allow reading control registers for debugging. */ + case REG_NS_CTRL0: + return read_only & CTRL0_MASK; + case REG_NS_CTRL1: + return read_only & CTRL1_MASK; + case REG_NS_CFG: + return read_only & CFG_MASK; + /* Allow EL1 IRQ handler to clear interrupts. */ + case REG_NS_INTERRUPT_CLEAR: return write_only & ALL_VIDS_BITMAP; - - /* IRQ handler can read bitmap of pending interrupts. */ - if (off == REG_NS_FAULT_STATUS) + /* Allow reading number of sets used by MPTC. */ + case REG_NS_INFO: + return read_only & INFO_NUM_SET_MASK; + /* Allow EL1 IRQ handler to read bitmap of pending interrupts. */ + case REG_NS_FAULT_STATUS: return read_only & ALL_VIDS_BITMAP; + /* + * Allow reading MPTC entries for debugging. That involves: + * - writing (set,way) to READ_MPTC + * - reading READ_MPTC_* + */ + case REG_NS_READ_MPTC: + return write_only & READ_MPTC_MASK; + case REG_NS_READ_MPTC_TAG_PPN: + return read_only & READ_MPTC_TAG_PPN_MASK; + case REG_NS_READ_MPTC_TAG_OTHERS: + return read_only & READ_MPTC_TAG_OTHERS_MASK; + case REG_NS_READ_MPTC_DATA: + return read_only; + } + + /* Allow reading L1ENTRY registers for debugging. */ + if (off >= REG_NS_L1ENTRY_L2TABLE_ADDR(0, 0) && + off < REG_NS_L1ENTRY_ATTR(NR_VIDS, 0)) + return read_only; - /* IRQ handler can read fault information. */ + /* Allow EL1 IRQ handler to read fault information. */ masked_off = off & ~REG_NS_FAULT_VID_MASK; if ((masked_off == REG_NS_FAULT_PA_LOW(0)) || (masked_off == REG_NS_FAULT_PA_HIGH(0)) || @@ -445,7 +495,7 @@ static int s2mpu_init(void *data, size_t size) host_mpt.fmpt[gb] = (struct fmpt){ .smpt = smpt, .gran_1g = true, - .prot = MPT_PROT_NONE, + .prot = MPT_PROT_RW, }; } @@ -465,9 +515,28 @@ static int s2mpu_init(void *data, size_t size) return ret; } -static int s2mpu_validate(phys_addr_t pa, size_t size) +static int s2mpu_validate(struct pkvm_iommu *dev) { - if (size != S2MPU_MMIO_SIZE) + if (dev->size != S2MPU_MMIO_SIZE) + return -EINVAL; + + return 0; +} + +static int s2mpu_validate_child(struct pkvm_iommu *dev, struct pkvm_iommu *child) +{ + if (child->ops != &pkvm_sysmmu_sync_ops) + return -EINVAL; + + return 0; +} + +static int sysmmu_sync_validate(struct pkvm_iommu *dev) +{ + if (dev->size != SYSMMU_SYNC_S2_MMIO_SIZE) + return -EINVAL; + + if (!dev->parent || dev->parent->ops != &pkvm_s2mpu_ops) return -EINVAL; return 0; @@ -476,6 +545,7 @@ static int s2mpu_validate(phys_addr_t pa, size_t size) const struct pkvm_iommu_ops pkvm_s2mpu_ops = (struct pkvm_iommu_ops){ .init = s2mpu_init, .validate = s2mpu_validate, + .validate_child = s2mpu_validate_child, .resume = s2mpu_resume, .suspend = s2mpu_suspend, .host_stage2_idmap_prepare = s2mpu_host_stage2_idmap_prepare, @@ -483,3 +553,7 @@ const struct pkvm_iommu_ops pkvm_s2mpu_ops = (struct pkvm_iommu_ops){ .host_dabt_handler = s2mpu_host_dabt_handler, .data_size = sizeof(struct s2mpu_drv_data), }; + +const struct pkvm_iommu_ops pkvm_sysmmu_sync_ops = (struct pkvm_iommu_ops){ + .validate = sysmmu_sync_validate, +}; diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 750eab9678f93b96c9df9ca4c3e4ac94eeae14eb..76703b2b6f3c55be815c95db9a2a399f5babe6e6 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -620,6 +620,50 @@ static bool is_dabt(u64 esr) return ESR_ELx_EC(esr) == ESR_ELx_EC_DABT_LOW; } +static void host_inject_abort(struct kvm_cpu_context *host_ctxt) +{ + u64 spsr = read_sysreg_el2(SYS_SPSR); + u64 esr = read_sysreg_el2(SYS_ESR); + u64 ventry, ec; + + /* Repaint the ESR to report a same-level fault if taken from EL1 */ + if ((spsr & PSR_MODE_MASK) != PSR_MODE_EL0t) { + ec = ESR_ELx_EC(esr); + if (ec == ESR_ELx_EC_DABT_LOW) + ec = ESR_ELx_EC_DABT_CUR; + else if (ec == ESR_ELx_EC_IABT_LOW) + ec = ESR_ELx_EC_IABT_CUR; + else + WARN_ON(1); + esr &= ~ESR_ELx_EC_MASK; + esr |= ec << ESR_ELx_EC_SHIFT; + } + + /* + * Since S1PTW should only ever be set for stage-2 faults, we're pretty + * much guaranteed that it won't be set in ESR_EL1 by the hardware. So, + * let's use that bit to allow the host abort handler to differentiate + * this abort from normal userspace faults. + * + * Note: although S1PTW is RES0 at EL1, it is guaranteed by the + * architecture to be backed by flops, so it should be safe to use. + */ + esr |= ESR_ELx_S1PTW; + + write_sysreg_el1(esr, SYS_ESR); + write_sysreg_el1(spsr, SYS_SPSR); + write_sysreg_el1(read_sysreg_el2(SYS_ELR), SYS_ELR); + write_sysreg_el1(read_sysreg_el2(SYS_FAR), SYS_FAR); + + ventry = read_sysreg_el1(SYS_VBAR); + ventry += get_except64_offset(spsr, PSR_MODE_EL1h, except_type_sync); + write_sysreg_el2(ventry, SYS_ELR); + + spsr = get_except64_cpsr(spsr, system_supports_mte(), + read_sysreg_el1(SYS_SCTLR), PSR_MODE_EL1h); + write_sysreg_el2(spsr, SYS_SPSR); +} + void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt) { struct kvm_vcpu_fault_info fault; @@ -644,7 +688,11 @@ void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt) ret = host_stage2_idmap(addr); host_unlock_component(); - BUG_ON(ret && ret != -EAGAIN); + + if (ret == -EPERM) + host_inject_abort(host_ctxt); + else + BUG_ON(ret && ret != -EAGAIN); } /* This corresponds to locking order */ @@ -1073,10 +1121,14 @@ static int guest_complete_donation(u64 addr, const struct pkvm_mem_transition *t u64 size = tx->nr_pages * PAGE_SIZE; int err; - if (tx->initiator.id == PKVM_ID_HOST && ipa_in_pvmfw_region(vm, addr)) { - err = pkvm_load_pvmfw_pages(vm, addr, phys, size); - if (err) - return err; + if (tx->initiator.id == PKVM_ID_HOST) { + psci_mem_protect_inc(); + + if (ipa_in_pvmfw_region(vm, addr)) { + err = pkvm_load_pvmfw_pages(vm, addr, phys, size); + if (err) + return err; + } } return kvm_pgtable_stage2_map(&vm->pgt, addr, size, phys, prot, @@ -1893,6 +1945,7 @@ int __pkvm_host_reclaim_page(u64 pfn) if (ret) goto unlock; page->flags &= ~HOST_PAGE_NEED_POISONING; + psci_mem_protect_dec(); } ret = host_stage2_set_owner_locked(addr, PAGE_SIZE, pkvm_host_id); diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index 6239fea7496b94457db42e3a64e870e241b651d7..4e86a2123c054ea4368e5f843e8a4618651a12ae 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c @@ -331,6 +331,12 @@ static void *admit_host_page(void *arg) int refill_memcache(struct kvm_hyp_memcache *mc, unsigned long min_pages, struct kvm_hyp_memcache *host_mc) { - return __topup_hyp_memcache(mc, min_pages, admit_host_page, - hyp_virt_to_phys, host_mc); + struct kvm_hyp_memcache tmp = *host_mc; + int ret; + + ret = __topup_hyp_memcache(mc, min_pages, admit_host_page, + hyp_virt_to_phys, &tmp); + *host_mc = tmp; + + return ret; } diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 6d1eeacc559bc11fb687ef8b4694c2132dbc91eb..701684a2d24a066d8306113fde8904421bf578b4 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -225,6 +225,11 @@ static int index_to_shadow_handle(int index) extern unsigned long hyp_nr_cpus; +/* + * Track the vcpu most recently loaded on each physical CPU. + */ +static DEFINE_PER_CPU(struct kvm_vcpu *, last_loaded_vcpu); + /* * Spinlock for protecting the shadow table related state. * Protects writes to shadow_table, num_shadow_entries, and next_shadow_alloc, @@ -267,6 +272,7 @@ struct kvm_vcpu *get_shadow_vcpu(int shadow_handle, unsigned int vcpu_idx) { struct kvm_vcpu *vcpu = NULL; struct kvm_shadow_vm *vm; + bool flush_context = false; hyp_spin_lock(&shadow_lock); vm = find_shadow_by_handle(shadow_handle); @@ -279,12 +285,28 @@ struct kvm_vcpu *get_shadow_vcpu(int shadow_handle, unsigned int vcpu_idx) vcpu = NULL; goto unlock; } + + /* + * Guarantee that both TLBs and I-cache are private to each vcpu. + * The check below is conservative and could lead to over-invalidation, + * because there is no need to nuke the contexts if the vcpu belongs to + * a different vm. + */ + if (vcpu != __this_cpu_read(last_loaded_vcpu)) { + flush_context = true; + __this_cpu_write(last_loaded_vcpu, vcpu); + } + vcpu->arch.pkvm.loaded_on_cpu = true; hyp_page_ref_inc(hyp_virt_to_page(vm)); unlock: hyp_spin_unlock(&shadow_lock); + /* No need for the lock while flushing the context. */ + if (flush_context) + __kvm_flush_cpu_context(vcpu->arch.hw_mmu); + return vcpu; } @@ -354,8 +376,19 @@ static void unpin_host_vcpus(struct shadow_vcpu_state *shadow_vcpus, int nr_vcpu for (i = 0; i < nr_vcpus; i++) { struct kvm_vcpu *host_vcpu = shadow_vcpus[i].vcpu.arch.pkvm.host_vcpu; + struct kvm_vcpu *shadow_vcpu = &shadow_vcpus[i].vcpu; + size_t sve_state_size; + void *sve_state; hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1); + + if (!test_bit(KVM_ARM_VCPU_SVE, shadow_vcpu->arch.features)) + continue; + + sve_state = shadow_vcpu->arch.sve_state; + sve_state = kern_hyp_va(sve_state); + sve_state_size = vcpu_sve_state_size(shadow_vcpu); + hyp_unpin_shared_mem(sve_state, sve_state + sve_state_size); } } @@ -405,6 +438,27 @@ static int init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, if (ret) return ret; + if (test_bit(KVM_ARM_VCPU_SVE, shadow_vcpu->arch.features)) { + size_t sve_state_size; + void *sve_state; + + shadow_vcpu->arch.sve_state = READ_ONCE(host_vcpu->arch.sve_state); + shadow_vcpu->arch.sve_max_vl = READ_ONCE(host_vcpu->arch.sve_max_vl); + + sve_state = kern_hyp_va(shadow_vcpu->arch.sve_state); + sve_state_size = vcpu_sve_state_size(shadow_vcpu); + + if (!shadow_vcpu->arch.sve_state || !sve_state_size || + hyp_pin_shared_mem(sve_state, + sve_state + sve_state_size)) { + clear_bit(KVM_ARM_VCPU_SVE, + shadow_vcpu->arch.features); + shadow_vcpu->arch.sve_state = NULL; + shadow_vcpu->arch.sve_max_vl = 0; + return -EINVAL; + } + } + if (vm->arch.pkvm.enabled) pkvm_vcpu_init_traps(shadow_vcpu); kvm_reset_pvm_sys_regs(shadow_vcpu); @@ -664,6 +718,7 @@ int __pkvm_teardown_shadow(int shadow_handle) u64 pfn; u64 nr_pages; void *addr; + int i; /* Lookup then remove entry from the shadow table. */ hyp_spin_lock(&shadow_lock); @@ -678,6 +733,21 @@ int __pkvm_teardown_shadow(int shadow_handle) goto err_unlock; } + /* + * Clear the tracking for last_loaded_vcpu for all cpus for this vm in + * case the same addresses for those vcpus are reused for future vms. + */ + for (i = 0; i < hyp_nr_cpus; i++) { + struct kvm_vcpu **last_loaded_vcpu_ptr = + per_cpu_ptr(&last_loaded_vcpu, i); + struct kvm_vcpu *vcpu = *last_loaded_vcpu_ptr; + + if (vcpu && vcpu->arch.pkvm.shadow_handle == shadow_handle) + *last_loaded_vcpu_ptr = NULL; + } + + /* Ensure the VMID is clean before it can be reallocated */ + __kvm_tlb_flush_vmid(&vm->arch.mmu); remove_shadow_table(shadow_handle); hyp_spin_unlock(&shadow_lock); @@ -799,6 +869,10 @@ void pkvm_reset_vcpu(struct kvm_vcpu *vcpu) *vcpu_pc(vcpu) = entry; vm->pvmfw_entry_vcpu = NULL; + + /* Auto enroll MMIO guard */ + set_bit(KVM_ARCH_FLAG_MMIO_GUARD, + &vcpu->arch.pkvm.shadow_vm->arch.flags); } else { *vcpu_pc(vcpu) = reset_state->pc; vcpu_set_reg(vcpu, 0, reset_state->r0); diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c index cee6d4a2821fdabcb2ab0457c3394d531a95d140..85f7cad956d54712d530bad380c528104dd89e36 100644 --- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c +++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c @@ -222,6 +222,44 @@ asmlinkage void __noreturn kvm_host_psci_cpu_entry(bool is_cpu_on) __host_enter(host_ctxt); } +static DEFINE_HYP_SPINLOCK(mem_protect_lock); + +static u64 psci_mem_protect(s64 offset) +{ + static u64 cnt; + u64 new = cnt + offset; + + hyp_assert_lock_held(&mem_protect_lock); + + if (!offset || kvm_host_psci_config.version < PSCI_VERSION(1, 1)) + return cnt; + + if (!cnt || !new) + psci_call(PSCI_1_1_FN64_MEM_PROTECT, offset < 0 ? 0 : 1, 0, 0); + + cnt = new; + return cnt; +} + +static bool psci_mem_protect_active(void) +{ + return psci_mem_protect(0); +} + +void psci_mem_protect_inc(void) +{ + hyp_spin_lock(&mem_protect_lock); + psci_mem_protect(1); + hyp_spin_unlock(&mem_protect_lock); +} + +void psci_mem_protect_dec(void) +{ + hyp_spin_lock(&mem_protect_lock); + psci_mem_protect(-1); + hyp_spin_unlock(&mem_protect_lock); +} + static unsigned long psci_0_1_handler(u64 func_id, struct kvm_cpu_context *host_ctxt) { if (is_psci_0_1(cpu_off, func_id) || is_psci_0_1(migrate, func_id)) @@ -251,6 +289,8 @@ static unsigned long psci_0_2_handler(u64 func_id, struct kvm_cpu_context *host_ case PSCI_0_2_FN_SYSTEM_OFF: case PSCI_0_2_FN_SYSTEM_RESET: pkvm_clear_pvmfw_pages(); + /* Avoid racing with a MEM_PROTECT call. */ + hyp_spin_lock(&mem_protect_lock); return psci_forward(host_ctxt); case PSCI_0_2_FN64_CPU_SUSPEND: return psci_cpu_suspend(func_id, host_ctxt); @@ -266,6 +306,11 @@ static unsigned long psci_1_0_handler(u64 func_id, struct kvm_cpu_context *host_ switch (func_id) { case PSCI_1_1_FN64_SYSTEM_RESET2: pkvm_clear_pvmfw_pages(); + hyp_spin_lock(&mem_protect_lock); + if (psci_mem_protect_active()) { + return psci_0_2_handler(PSCI_0_2_FN_SYSTEM_RESET, + host_ctxt); + } fallthrough; case PSCI_1_0_FN_PSCI_FEATURES: case PSCI_1_0_FN_SET_SUSPEND_MODE: diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index 18638652f06d669f3722d1e00f8643cff59cc802..1a6f3eba50358eff118f1d3ed1e5324b5ab3cd52 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -133,20 +133,16 @@ static int recreate_hyp_mappings(phys_addr_t phys, unsigned long size, } /* - * Map the host's .bss and .rodata sections RO in the hypervisor, but - * transfer the ownership from the host to the hypervisor itself to - * make sure it can't be donated or shared with another entity. + * Map the host sections RO in the hypervisor, but transfer the + * ownership from the host to the hypervisor itself to make sure they + * can't be donated or shared with another entity. * * The ownership transition requires matching changes in the host * stage-2. This will be done later (see finalize_host_mappings()) once * the hyp_vmemmap is addressable. */ prot = pkvm_mkstate(PAGE_HYP_RO, PKVM_PAGE_SHARED_OWNED); - ret = pkvm_create_mappings(__start_rodata, __end_rodata, prot); - if (ret) - return ret; - - ret = pkvm_create_mappings(__hyp_bss_end, __bss_stop, prot); + ret = pkvm_create_mappings(&kvm_vgic_global_state, &kvm_vgic_global_state + 1, prot); if (ret) return ret; diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c index 024e6633058469875e18575a1a463fb16f12b3f2..1729b4d6059e021f0e0fa26366ab2984608d1eaa 100644 --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c @@ -232,15 +232,9 @@ u64 pvm_read_id_reg(const struct kvm_vcpu *vcpu, u32 id) case SYS_ID_AA64MMFR2_EL1: return get_pvm_id_aa64mmfr2(vcpu); default: - /* - * Should never happen because all cases are covered in - * pvm_sys_reg_descs[]. - */ - WARN_ON(1); - break; + /* Unhandled ID register, RAZ */ + return 0; } - - return 0; } static u64 read_id_reg(const struct kvm_vcpu *vcpu, @@ -321,6 +315,16 @@ static bool pvm_gic_read_sre(struct kvm_vcpu *vcpu, /* Mark the specified system register as an AArch64 feature id register. */ #define AARCH64(REG) { SYS_DESC(REG), .access = pvm_access_id_aarch64 } +/* + * sys_reg_desc initialiser for architecturally unallocated cpufeature ID + * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2 + * (1 <= crm < 8, 0 <= Op2 < 8). + */ +#define ID_UNALLOCATED(crm, op2) { \ + Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \ + .access = pvm_access_id_aarch64, \ +} + /* Mark the specified system register as Read-As-Zero/Write-Ignored */ #define RAZ_WI(REG) { SYS_DESC(REG), .access = pvm_access_raz_wi } @@ -375,24 +379,46 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = { AARCH32(SYS_MVFR0_EL1), AARCH32(SYS_MVFR1_EL1), AARCH32(SYS_MVFR2_EL1), + ID_UNALLOCATED(3,3), AARCH32(SYS_ID_PFR2_EL1), AARCH32(SYS_ID_DFR1_EL1), AARCH32(SYS_ID_MMFR5_EL1), + ID_UNALLOCATED(3,7), /* AArch64 ID registers */ /* CRm=4 */ AARCH64(SYS_ID_AA64PFR0_EL1), AARCH64(SYS_ID_AA64PFR1_EL1), + ID_UNALLOCATED(4,2), + ID_UNALLOCATED(4,3), AARCH64(SYS_ID_AA64ZFR0_EL1), + ID_UNALLOCATED(4,5), + ID_UNALLOCATED(4,6), + ID_UNALLOCATED(4,7), AARCH64(SYS_ID_AA64DFR0_EL1), AARCH64(SYS_ID_AA64DFR1_EL1), + ID_UNALLOCATED(5,2), + ID_UNALLOCATED(5,3), AARCH64(SYS_ID_AA64AFR0_EL1), AARCH64(SYS_ID_AA64AFR1_EL1), + ID_UNALLOCATED(5,6), + ID_UNALLOCATED(5,7), AARCH64(SYS_ID_AA64ISAR0_EL1), AARCH64(SYS_ID_AA64ISAR1_EL1), + AARCH64(SYS_ID_AA64ISAR2_EL1), + ID_UNALLOCATED(6,3), + ID_UNALLOCATED(6,4), + ID_UNALLOCATED(6,5), + ID_UNALLOCATED(6,6), + ID_UNALLOCATED(6,7), AARCH64(SYS_ID_AA64MMFR0_EL1), AARCH64(SYS_ID_AA64MMFR1_EL1), AARCH64(SYS_ID_AA64MMFR2_EL1), + ID_UNALLOCATED(7,3), + ID_UNALLOCATED(7,4), + ID_UNALLOCATED(7,5), + ID_UNALLOCATED(7,6), + ID_UNALLOCATED(7,7), /* Scalable Vector Registers are restricted. */ diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index e7c71396b7e061f4d00925720765a63b4d98e2c6..bb04eb91e5e61b1bc42394190d0747d11d5ca6e5 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -58,24 +58,6 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) val[3] = lower_32_bits(cycles); } -static int kvm_vcpu_exit_hcall(struct kvm_vcpu *vcpu, u32 nr, u32 nr_args) -{ - u64 mask = vcpu->kvm->arch.hypercall_exit_enabled; - u32 i; - - if (nr_args > 6 || !(mask & BIT(nr))) - return -EINVAL; - - vcpu->run->exit_reason = KVM_EXIT_HYPERCALL; - vcpu->run->hypercall.nr = nr; - - for (i = 0; i < nr_args; ++i) - vcpu->run->hypercall.args[i] = vcpu_get_reg(vcpu, i + 1); - - vcpu->run->hypercall.longmode = !vcpu_mode_is_32bit(vcpu); - return 0; -} - int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { u32 func_id = smccc_get_function(vcpu); @@ -163,14 +145,6 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: kvm_ptp_get_time(vcpu, val); break; - case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID: - if (!kvm_vcpu_exit_hcall(vcpu, ARM_SMCCC_KVM_FUNC_MEM_SHARE, 3)) - return 0; - break; - case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID: - if (!kvm_vcpu_exit_hcall(vcpu, ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, 3)) - return 0; - break; case ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_MAP_FUNC_ID: if (kvm_vm_is_protected(vcpu->kvm) && !topup_hyp_memcache(vcpu)) val[0] = SMCCC_RET_SUCCESS; diff --git a/arch/arm64/kvm/iommu.c b/arch/arm64/kvm/iommu.c index e13d36ec57e71f47f3acbbbda0a710c28d14bb17..6ca171327b289b01ba211c073c1c790632cf7ebe 100644 --- a/arch/arm64/kvm/iommu.c +++ b/arch/arm64/kvm/iommu.c @@ -18,7 +18,7 @@ int pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t size } int pkvm_iommu_register(struct device *dev, enum pkvm_iommu_driver_id drv_id, - phys_addr_t pa, size_t size) + phys_addr_t pa, size_t size, struct device *parent) { void *mem; int ret; @@ -29,14 +29,15 @@ int pkvm_iommu_register(struct device *dev, enum pkvm_iommu_driver_id drv_id, * We assume that hyp never allocates more than a page per hypcall. */ ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev), - drv_id, pa, size, NULL, 0); + drv_id, pa, size, dev_to_id(parent), NULL, 0); if (ret == -ENOMEM) { mem = (void *)__get_free_page(GFP_KERNEL); if (!mem) return -ENOMEM; ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev), - drv_id, pa, size, mem, PAGE_SIZE); + drv_id, pa, size, dev_to_id(parent), + mem, PAGE_SIZE); } return ret; } @@ -54,3 +55,9 @@ int pkvm_iommu_resume(struct device *dev) PKVM_IOMMU_PM_RESUME); } EXPORT_SYMBOL_GPL(pkvm_iommu_resume); + +int pkvm_iommu_finalize(void) +{ + return kvm_call_hyp_nvhe(__pkvm_iommu_finalize); +} +EXPORT_SYMBOL_GPL(pkvm_iommu_finalize); diff --git a/arch/arm64/kvm/iommu/s2mpu.c b/arch/arm64/kvm/iommu/s2mpu.c index be2b1ad094808fe9c1a851d0da52efb5be4a1ba5..733451d741007eb6a26023c48d6d695d687052f2 100644 --- a/arch/arm64/kvm/iommu/s2mpu.c +++ b/arch/arm64/kvm/iommu/s2mpu.c @@ -81,6 +81,40 @@ int pkvm_iommu_s2mpu_register(struct device *dev, phys_addr_t addr) return ret; return pkvm_iommu_register(dev, PKVM_IOMMU_DRIVER_S2MPU, - addr, S2MPU_MMIO_SIZE); + addr, S2MPU_MMIO_SIZE, NULL); } EXPORT_SYMBOL_GPL(pkvm_iommu_s2mpu_register); + +static int init_sysmmu_sync_driver(void) +{ + static DEFINE_MUTEX(lock); + static bool init_done; + + int ret = 0; + + mutex_lock(&lock); + if (!init_done) { + ret = pkvm_iommu_driver_init(PKVM_IOMMU_DRIVER_SYSMMU_SYNC, NULL, 0); + init_done = !ret; + } + mutex_unlock(&lock); + return ret; +} + +int pkvm_iommu_sysmmu_sync_register(struct device *dev, phys_addr_t addr, + struct device *parent) +{ + int ret; + + if (!is_protected_kvm_enabled()) + return -ENODEV; + + ret = init_sysmmu_sync_driver(); + if (ret) + return ret; + + return pkvm_iommu_register(dev, PKVM_IOMMU_DRIVER_SYSMMU_SYNC, + addr + SYSMMU_SYNC_S2_OFFSET, + SYSMMU_SYNC_S2_MMIO_SIZE, parent); +} +EXPORT_SYMBOL_GPL(pkvm_iommu_sysmmu_sync_register); diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 80fed4cf0512ab36d4fc0c50d4013741d085a2e0..69771a6f7c830b6cae8fecfeb943efc285f14920 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1163,10 +1163,7 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, unsigned long hva) { struct mm_struct *mm = current->mm; - unsigned int flags = FOLL_FORCE | - FOLL_HWPOISON | - FOLL_LONGTERM | - FOLL_WRITE; + unsigned int flags = FOLL_HWPOISON | FOLL_LONGTERM | FOLL_WRITE; struct kvm_pinned_page *ppage; struct kvm *kvm = vcpu->kvm; struct page *page; @@ -1196,6 +1193,21 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } else if (ret != 1) { ret = -EFAULT; goto dec_account; + } else if (!PageSwapBacked(page)) { + /* + * We really can't deal with page-cache pages returned by GUP + * because (a) we may trigger writeback of a page for which we + * no longer have access and (b) page_mkclean() won't find the + * stage-2 mapping in the rmap so we can get out-of-whack with + * the filesystem when marking the page dirty during unpinning. + * + * Ideally we'd just restrict ourselves to anonymous pages, but + * we also want to allow memfd (i.e. shmem) pages, so check for + * pages backed by swap in the knowledge that the GUP pin will + * prevent try_to_unmap() from succeeding. + */ + ret = -EIO; + goto dec_account; } spin_lock(&kvm->mmu_lock); @@ -1841,6 +1853,13 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, hva_t reg_end = hva + mem->memory_size; int ret = 0; + /* In protected mode, cannot modify memslots once a VM has run. */ + if (is_protected_kvm_enabled() && + (change == KVM_MR_DELETE || change == KVM_MR_MOVE) && + kvm->arch.pkvm.shadow_handle) { + return -EPERM; + } + if (change != KVM_MR_CREATE && change != KVM_MR_MOVE && change != KVM_MR_FLAGS_ONLY) return 0; @@ -1914,6 +1933,10 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm, gpa_t gpa = slot->base_gfn << PAGE_SHIFT; phys_addr_t size = slot->npages << PAGE_SHIFT; + /* Stage-2 is managed by hyp in protected mode. */ + if (is_protected_kvm_enabled()) + return; + spin_lock(&kvm->mmu_lock); unmap_stage2_range(&kvm->arch.mmu, gpa, size); spin_unlock(&kvm->mmu_lock); diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c index 03a6c1f4a09af0a3e2321054e31640163cf79650..a8878fd8b696caa9ba68ffd996ff0ae91b74bcc8 100644 --- a/arch/arm64/kvm/pmu.c +++ b/arch/arm64/kvm/pmu.c @@ -31,9 +31,13 @@ static bool kvm_pmu_switch_needed(struct perf_event_attr *attr) */ void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) { - struct kvm_host_data *ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + struct kvm_host_data *ctx; - if (!kvm_arm_support_pmu_v3() || !ctx || !kvm_pmu_switch_needed(attr)) + if (!kvm_arm_support_pmu_v3()) + return; + + ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + if (!ctx || !kvm_pmu_switch_needed(attr)) return; if (!attr->exclude_host) @@ -47,9 +51,13 @@ void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) */ void kvm_clr_pmu_events(u32 clr) { - struct kvm_host_data *ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + struct kvm_host_data *ctx; + + if (!kvm_arm_support_pmu_v3()) + return; - if (!kvm_arm_support_pmu_v3() || !ctx) + ctx = this_cpu_ptr_hyp_sym(kvm_host_data); + if (!ctx) return; ctx->pmu_events.events_host &= ~clr; diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c index acdb7b3cc97d65aaa9a540ea3773e46af1ea04cf..f0b678d24e25de98966fcecd2458fa3557de86e5 100644 --- a/arch/arm64/kvm/va_layout.c +++ b/arch/arm64/kvm/va_layout.c @@ -295,3 +295,15 @@ void kvm_compute_final_ctr_el0(struct alt_instr *alt, generate_mov_q(read_sanitised_ftr_reg(SYS_CTR_EL0), origptr, updptr, nr_inst); } + +void kvm_get__text(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst) +{ + generate_mov_q((u64)_text, origptr, updptr, nr_inst); +} + +void kvm_get__etext(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst) +{ + generate_mov_q((u64)_etext, origptr, updptr, nr_inst); +} diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 540ef3cd0a36a52158b7049e0cd02a3883f5c377..9af359f68356102a1524b76b363f0c2c62abaa02 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -253,6 +254,15 @@ static inline bool is_el1_permission_fault(unsigned long addr, unsigned int esr, return false; } +static bool is_pkvm_stage2_abort(unsigned int esr) +{ + /* + * S1PTW should only ever be set in ESR_EL1 if the pkvm hypervisor + * injected a stage-2 abort -- see host_inject_abort(). + */ + return is_pkvm_initialized() && (esr & ESR_ELx_S1PTW); +} + static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) @@ -264,6 +274,9 @@ static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr, (esr & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT) return false; + if (is_pkvm_stage2_abort(esr)) + return false; + local_irq_save(flags); asm volatile("at s1e1r, %0" :: "r" (addr)); isb(); @@ -379,6 +392,8 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, msg = "read from unreadable memory"; } else if (addr < PAGE_SIZE) { msg = "NULL pointer dereference"; + } else if (is_pkvm_stage2_abort(esr)) { + msg = "access to hypervisor-protected memory"; } else { if (kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs)) return; @@ -557,6 +572,13 @@ static int __kprobes do_page_fault(unsigned long far, unsigned int esr, addr, esr, regs); } + if (is_pkvm_stage2_abort(esr)) { + if (!user_mode(regs)) + goto no_context; + arm64_force_sig_fault(SIGSEGV, SEGV_ACCERR, far, "stage-2 fault"); + return 0; + } + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); /* diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 0cbb63cf955f1f8c420b42aa340642fe898006aa..33d93f800734a88ea568961ebfd403e6a9c36070 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -59,34 +59,8 @@ EXPORT_SYMBOL(memstart_addr); * unless restricted on specific platforms (e.g. 30-bit on Raspberry Pi 4). * In such case, ZONE_DMA32 covers the rest of the 32-bit addressable memory, * otherwise it is empty. - * - * Memory reservation for crash kernel either done early or deferred - * depending on DMA memory zones configs (ZONE_DMA) -- - * - * In absence of ZONE_DMA configs arm64_dma_phys_limit initialized - * here instead of max_zone_phys(). This lets early reservation of - * crash kernel memory which has a dependency on arm64_dma_phys_limit. - * Reserving memory early for crash kernel allows linear creation of block - * mappings (greater than page-granularity) for all the memory bank rangs. - * In this scheme a comparatively quicker boot is observed. - * - * If ZONE_DMA configs are defined, crash kernel memory reservation - * is delayed until DMA zone memory range size initilazation performed in - * zone_sizes_init(). The defer is necessary to steer clear of DMA zone - * memory range to avoid overlap allocation. So crash kernel memory boundaries - * are not known when mapping all bank memory ranges, which otherwise means - * not possible to exclude crash kernel range from creating block mappings - * so page-granularity mappings are created for the entire memory range. - * Hence a slightly slower boot is observed. - * - * Note: Page-granularity mapppings are necessary for crash kernel memory - * range for shrinking its size via /sys/kernel/kexec_crash_size interface. */ -#if IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32) -phys_addr_t __ro_after_init arm64_dma_phys_limit; -#else -phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1; -#endif +phys_addr_t arm64_dma_phys_limit __ro_after_init; /* * Provide a run-time mean of disabling ZONE_DMA32 if it is enabled via @@ -243,6 +217,8 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) if (!arm64_dma_phys_limit) arm64_dma_phys_limit = dma32_phys_limit; #endif + if (!arm64_dma_phys_limit) + arm64_dma_phys_limit = PHYS_MASK + 1; max_zone_pfns[ZONE_NORMAL] = max; free_area_init(max_zone_pfns); @@ -453,9 +429,6 @@ void __init arm64_memblock_init(void) reserve_elfcorehdr(); - if (!IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) - reserve_crashkernel(); - high_memory = __va(memblock_end_of_DRAM() - 1) + 1; } @@ -502,8 +475,7 @@ void __init bootmem_init(void) * request_standard_resources() depends on crashkernel's memory being * reserved, so do it here. */ - if (IS_ENABLED(CONFIG_ZONE_DMA) || IS_ENABLED(CONFIG_ZONE_DMA32)) - reserve_crashkernel(); + reserve_crashkernel(); memblock_dump_all(); } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 10ef44c938b73712309d8cfea461c053a32b5309..52483efde97f2984d9c029ecb82b4a8888bf5268 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -61,7 +61,6 @@ static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused; static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused; static DEFINE_SPINLOCK(swapper_pgdir_lock); -static DEFINE_MUTEX(fixmap_lock); void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd) { @@ -316,12 +315,6 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, } BUG_ON(p4d_bad(p4d)); - /* - * No need for locking during early boot. And it doesn't work as - * expected with KASLR enabled. - */ - if (system_state != SYSTEM_BOOTING) - mutex_lock(&fixmap_lock); pudp = pud_set_fixmap_offset(p4dp, addr); do { pud_t old_pud = READ_ONCE(*pudp); @@ -352,8 +345,6 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end, } while (pudp++, addr = next, addr != end); pud_clear_fixmap(); - if (system_state != SYSTEM_BOOTING) - mutex_unlock(&fixmap_lock); } static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, @@ -502,7 +493,7 @@ static void __init map_mem(pgd_t *pgdp) int flags = 0; u64 i; - if (rodata_full || debug_pagealloc_enabled() || + if (rodata_full || crash_mem_map || debug_pagealloc_enabled() || IS_ENABLED(CONFIG_KFENCE)) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; @@ -514,17 +505,6 @@ static void __init map_mem(pgd_t *pgdp) */ memblock_mark_nomap(kernel_start, kernel_end - kernel_start); -#ifdef CONFIG_KEXEC_CORE - if (crash_mem_map) { - if (IS_ENABLED(CONFIG_ZONE_DMA) || - IS_ENABLED(CONFIG_ZONE_DMA32)) - flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; - else if (crashk_res.end) - memblock_mark_nomap(crashk_res.start, - resource_size(&crashk_res)); - } -#endif - /* map all the memory banks */ for_each_mem_range(i, &start, &end) { if (start >= end) @@ -551,25 +531,6 @@ static void __init map_mem(pgd_t *pgdp) __map_memblock(pgdp, kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS); memblock_clear_nomap(kernel_start, kernel_end - kernel_start); - - /* - * Use page-level mappings here so that we can shrink the region - * in page granularity and put back unused memory to buddy system - * through /sys/kernel/kexec_crash_size interface. - */ -#ifdef CONFIG_KEXEC_CORE - if (crash_mem_map && - !IS_ENABLED(CONFIG_ZONE_DMA) && !IS_ENABLED(CONFIG_ZONE_DMA32)) { - if (crashk_res.end) { - __map_memblock(pgdp, crashk_res.start, - crashk_res.end + 1, - PAGE_KERNEL, - NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS); - memblock_clear_nomap(crashk_res.start, - resource_size(&crashk_res)); - } - } -#endif } void mark_rodata_ro(void) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 56b020b7ec59a409fda5656d0178dd7059fff2f3..8e1d5a37e5c94e14c283031607014c889fc35818 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1041,18 +1041,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) goto out_off; } - /* - * 1. Initial fake pass to compute ctx->idx and ctx->offset. - * - * BPF line info needs ctx->offset[i] to be the offset of - * instruction[i] in jited image, so build prologue first. - */ - if (build_prologue(&ctx, was_classic)) { + /* 1. Initial fake pass to compute ctx->idx. */ + + /* Fake pass to fill in ctx->offset. */ + if (build_body(&ctx, extra_pass)) { prog = orig_prog; goto out_off; } - if (build_body(&ctx, extra_pass)) { + if (build_prologue(&ctx, was_classic)) { prog = orig_prog; goto out_off; } @@ -1127,11 +1124,6 @@ skip_init_ctx: prog->jited_len = prog_size; if (!prog->is_func || extra_pass) { - int i; - - /* offset[prog->len] is the size of program */ - for (i = 0; i <= prog->len; i++) - ctx.offset[i] *= AARCH64_INSN_SIZE; bpf_prog_fill_jited_linfo(prog, ctx.offset + 1); out_off: kfree(ctx.offset); diff --git a/arch/csky/kernel/perf_callchain.c b/arch/csky/kernel/perf_callchain.c index 75e1f9df5f60449c6ec65c3e97ed3bd5ca2b07e2..35318a635a5fae7b6de24723f6f43338bab85b67 100644 --- a/arch/csky/kernel/perf_callchain.c +++ b/arch/csky/kernel/perf_callchain.c @@ -49,7 +49,7 @@ static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry, { struct stackframe buftail; unsigned long lr = 0; - unsigned long __user *user_frame_tail = (unsigned long __user *)fp; + unsigned long *user_frame_tail = (unsigned long *)fp; /* Check accessibility of one struct frame_tail beyond */ if (!access_ok(user_frame_tail, sizeof(buftail))) diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c index 243228b0aa075e4d9862905afeb88824f924f265..0ca49b5e3dd378145dda5f3fbbf52b5587ed0275 100644 --- a/arch/csky/kernel/signal.c +++ b/arch/csky/kernel/signal.c @@ -136,7 +136,7 @@ static inline void __user *get_sigframe(struct ksignal *ksig, static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe *frame; int err = 0; struct csky_vdso *vdso = current->mm->context.vdso; diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index a055616942a1eee821fb7207f9558856fbac8896..59f7dfe50a4d011b437c69c4db5ed440cbe11545 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -480,7 +480,7 @@ static struct platform_device mcf_i2c5 = { #endif /* MCFI2C_BASE5 */ #endif /* IS_ENABLED(CONFIG_I2C_IMX) */ -#ifdef MCFEDMA_BASE +#if IS_ENABLED(CONFIG_MCF_EDMA) static const struct dma_slave_map mcf_edma_map[] = { { "dreq0", "rx-tx", MCF_EDMA_FILTER_PARAM(0) }, @@ -552,7 +552,7 @@ static struct platform_device mcf_edma = { .platform_data = &mcf_edma_data, } }; -#endif /* MCFEDMA_BASE */ +#endif /* IS_ENABLED(CONFIG_MCF_EDMA) */ #ifdef MCFSDHC_BASE static struct mcf_esdhc_platform_data mcf_esdhc_data = { @@ -610,7 +610,7 @@ static struct platform_device *mcf_devices[] __initdata = { &mcf_i2c5, #endif #endif -#ifdef MCFEDMA_BASE +#if IS_ENABLED(CONFIG_MCF_EDMA) &mcf_edma, #endif #ifdef MCFSDHC_BASE diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 7c5d92e2915ca585ec076644770b22986a477aee..304b04ffea2faf4104cab64cfba5036ad010abf3 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -167,27 +167,27 @@ extern long __user_bad(void); #define __get_user(x, ptr) \ ({ \ + unsigned long __gu_val = 0; \ long __gu_err; \ switch (sizeof(*(ptr))) { \ case 1: \ - __get_user_asm("lbu", (ptr), x, __gu_err); \ + __get_user_asm("lbu", (ptr), __gu_val, __gu_err); \ break; \ case 2: \ - __get_user_asm("lhu", (ptr), x, __gu_err); \ + __get_user_asm("lhu", (ptr), __gu_val, __gu_err); \ break; \ case 4: \ - __get_user_asm("lw", (ptr), x, __gu_err); \ + __get_user_asm("lw", (ptr), __gu_val, __gu_err); \ break; \ - case 8: { \ - __u64 __x = 0; \ - __gu_err = raw_copy_from_user(&__x, ptr, 8) ? \ - -EFAULT : 0; \ - (x) = (typeof(x))(typeof((x) - (x)))__x; \ + case 8: \ + __gu_err = __copy_from_user(&__gu_val, ptr, 8); \ + if (__gu_err) \ + __gu_err = -EFAULT; \ break; \ - } \ default: \ /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ } \ + x = (__force __typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index 011d1d678840aa513166e0cfbf209bb975dc6a90..ea5b5a83f1e11b82fea00297ef50d966950a2d37 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -131,7 +131,7 @@ */ mfc0 t0,CP0_CAUSE # get pending interrupts mfc0 t1,CP0_STATUS -#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) +#ifdef CONFIG_32BIT lw t2,cpu_fpu_mask #endif andi t0,ST0_IM # CAUSE.CE may be non-zero! @@ -139,7 +139,7 @@ beqz t0,spurious -#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) +#ifdef CONFIG_32BIT and t2,t0 bnez t2,fpu # handle FPU immediately #endif @@ -280,7 +280,7 @@ handle_it: j dec_irq_dispatch nop -#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) +#ifdef CONFIG_32BIT fpu: lw t0,fpu_kstat_irq nop diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile index 2bad87551203b2714529f7bbd38a832bf2b30a1e..d95016016b42bef365d7b8bb6348888df9e386f2 100644 --- a/arch/mips/dec/prom/Makefile +++ b/arch/mips/dec/prom/Makefile @@ -6,4 +6,4 @@ lib-y += init.o memory.o cmdline.o identify.o console.o -lib-$(CONFIG_CPU_R3000) += locore.o +lib-$(CONFIG_32BIT) += locore.o diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 99b9b29750db3cd116467991a823777e8bada15c..eaad0ed4b523bbc0ee70c58c994f91a9c59d0818 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -746,8 +746,7 @@ void __init arch_init_irq(void) dec_interrupt[DEC_IRQ_HALT] = -1; /* Register board interrupts: FPU and cascade. */ - if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT) && - dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) { + if (dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) { struct irq_desc *desc_fpu; int irq_fpu; diff --git a/arch/mips/include/asm/dec/prom.h b/arch/mips/include/asm/dec/prom.h index 1e1247add1cf802b9abe3a5216b3a785f83e5988..62c7dfb90e06c35afa168fa999e408f3b240004d 100644 --- a/arch/mips/include/asm/dec/prom.h +++ b/arch/mips/include/asm/dec/prom.h @@ -43,11 +43,16 @@ */ #define REX_PROM_MAGIC 0x30464354 -/* KN04 and KN05 are REX PROMs, so only do the check for R3k systems. */ -static inline bool prom_is_rex(u32 magic) -{ - return !IS_ENABLED(CONFIG_CPU_R3000) || magic == REX_PROM_MAGIC; -} +#ifdef CONFIG_64BIT + +#define prom_is_rex(magic) 1 /* KN04 and KN05 are REX PROMs. */ + +#else /* !CONFIG_64BIT */ + +#define prom_is_rex(magic) ((magic) == REX_PROM_MAGIC) + +#endif /* !CONFIG_64BIT */ + /* * 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's and diff --git a/arch/mips/include/asm/pgalloc.h b/arch/mips/include/asm/pgalloc.h index 71153c369f2948ec25ea296bd410468bc2960d6f..139b4050259fab5b6971f3c0d153cb66b288e887 100644 --- a/arch/mips/include/asm/pgalloc.h +++ b/arch/mips/include/asm/pgalloc.h @@ -15,7 +15,6 @@ #define __HAVE_ARCH_PMD_ALLOC_ONE #define __HAVE_ARCH_PUD_ALLOC_ONE -#define __HAVE_ARCH_PGD_FREE #include static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, @@ -50,11 +49,6 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) extern void pgd_init(unsigned long page); extern pgd_t *pgd_alloc(struct mm_struct *mm); -static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - free_pages((unsigned long)pgd, PGD_ORDER); -} - #define __pte_free_tlb(tlb,pte,address) \ do { \ pgtable_pte_page_dtor(pte); \ diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 0e3c8d761a451b7d67239107b72fa86b32b60d9b..dd34f1b32b7976ca316f50235448788d20b49160 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -310,9 +310,11 @@ static int __init plat_setup_devices(void) static int __init setup_kmac(char *s) { printk(KERN_INFO "korina mac = %s\n", s); - if (!mac_pton(s, korina_dev0_data.mac)) + if (!mac_pton(s, korina_dev0_data.mac)) { printk(KERN_ERR "Invalid mac\n"); - return 1; + return -EINVAL; + } + return 0; } __setup("kmac=", setup_kmac); diff --git a/arch/nds32/include/asm/uaccess.h b/arch/nds32/include/asm/uaccess.h index 54500e81efe59a040531fc863b2658b5cb7981f4..010ba5f1d7dd6b45445e51faef8a1b0809d2f3a6 100644 --- a/arch/nds32/include/asm/uaccess.h +++ b/arch/nds32/include/asm/uaccess.h @@ -70,7 +70,9 @@ static inline void set_fs(mm_segment_t fs) * versions are void (ie, don't return a value as such). */ -#define get_user(x, ptr) \ +#define get_user __get_user \ + +#define __get_user(x, ptr) \ ({ \ long __gu_err = 0; \ __get_user_check((x), (ptr), __gu_err); \ @@ -83,14 +85,6 @@ static inline void set_fs(mm_segment_t fs) (void)0; \ }) -#define __get_user(x, ptr) \ -({ \ - long __gu_err = 0; \ - const __typeof__(*(ptr)) __user *__p = (ptr); \ - __get_user_err((x), __p, (__gu_err)); \ - __gu_err; \ -}) - #define __get_user_check(x, ptr, err) \ ({ \ const __typeof__(*(ptr)) __user *__p = (ptr); \ @@ -171,18 +165,12 @@ do { \ : "r"(addr), "i"(-EFAULT) \ : "cc") -#define put_user(x, ptr) \ -({ \ - long __pu_err = 0; \ - __put_user_check((x), (ptr), __pu_err); \ - __pu_err; \ -}) +#define put_user __put_user \ #define __put_user(x, ptr) \ ({ \ long __pu_err = 0; \ - __typeof__(*(ptr)) __user *__p = (ptr); \ - __put_user_err((x), __p, __pu_err); \ + __put_user_err((x), (ptr), __pu_err); \ __pu_err; \ }) diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h index 8a386e6c07df19905d7dd7413d75a11f7818be58..a741abbed6fbf5ae8738730e4abeebe6c1627cb0 100644 --- a/arch/nios2/include/asm/uaccess.h +++ b/arch/nios2/include/asm/uaccess.h @@ -89,7 +89,6 @@ extern __must_check long strnlen_user(const char __user *s, long n); /* Optimized macros */ #define __get_user_asm(val, insn, addr, err) \ { \ - unsigned long __gu_val; \ __asm__ __volatile__( \ " movi %0, %3\n" \ "1: " insn " %1, 0(%2)\n" \ @@ -98,20 +97,14 @@ extern __must_check long strnlen_user(const char __user *s, long n); " .section __ex_table,\"a\"\n" \ " .word 1b, 2b\n" \ " .previous" \ - : "=&r" (err), "=r" (__gu_val) \ + : "=&r" (err), "=r" (val) \ : "r" (addr), "i" (-EFAULT)); \ - val = (__force __typeof__(*(addr)))__gu_val; \ } -extern void __get_user_unknown(void); - -#define __get_user_8(val, ptr, err) do { \ - u64 __val = 0; \ +#define __get_user_unknown(val, size, ptr, err) do { \ err = 0; \ - if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ + if (__copy_from_user(&(val), ptr, size)) { \ err = -EFAULT; \ - } else { \ - val = (typeof(val))(typeof((val) - (val)))__val; \ } \ } while (0) @@ -127,11 +120,8 @@ do { \ case 4: \ __get_user_asm(val, "ldw", ptr, err); \ break; \ - case 8: \ - __get_user_8(val, ptr, err); \ - break; \ default: \ - __get_user_unknown(); \ + __get_user_unknown(val, size, ptr, err); \ break; \ } \ } while (0) @@ -140,7 +130,9 @@ do { \ ({ \ long __gu_err = -EFAULT; \ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ - __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ + unsigned long __gu_val = 0; \ + __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\ + (x) = (__force __typeof__(x))__gu_val; \ __gu_err; \ }) @@ -148,9 +140,11 @@ do { \ ({ \ long __gu_err = -EFAULT; \ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + unsigned long __gu_val = 0; \ if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ - __get_user_common(x, sizeof(*__gu_ptr), \ + __get_user_common(__gu_val, sizeof(*__gu_ptr), \ __gu_ptr, __gu_err); \ + (x) = (__force __typeof__(x))__gu_val; \ __gu_err; \ }) diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c index e45491d1d3e4425c6c6d288959f64b46773f1360..cf2dca2ac7c37d8f49af4a0a725a03509cd37629 100644 --- a/arch/nios2/kernel/signal.c +++ b/arch/nios2/kernel/signal.c @@ -36,10 +36,10 @@ struct rt_sigframe { static inline int rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, - struct ucontext __user *uc, int *pr2) + struct ucontext *uc, int *pr2) { int temp; - unsigned long __user *gregs = uc->uc_mcontext.gregs; + unsigned long *gregs = uc->uc_mcontext.gregs; int err; /* Always make any pending restarted system calls return -EINTR */ @@ -102,11 +102,10 @@ asmlinkage int do_rt_sigreturn(struct switch_stack *sw) { struct pt_regs *regs = (struct pt_regs *)(sw + 1); /* Verify, can we follow the stack back */ - struct rt_sigframe __user *frame; + struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp; sigset_t set; int rval; - frame = (struct rt_sigframe __user *) regs->sp; if (!access_ok(frame, sizeof(*frame))) goto badframe; @@ -125,10 +124,10 @@ badframe: return 0; } -static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs) +static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *)regs - 1; - unsigned long __user *gregs = uc->uc_mcontext.gregs; + unsigned long *gregs = uc->uc_mcontext.gregs; int err = 0; err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); @@ -163,9 +162,8 @@ static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs * return err; } -static inline void __user *get_sigframe(struct ksignal *ksig, - struct pt_regs *regs, - size_t frame_size) +static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, + size_t frame_size) { unsigned long usp; @@ -176,13 +174,13 @@ static inline void __user *get_sigframe(struct ksignal *ksig, usp = sigsp(usp, ksig); /* Verify, is it 32 or 64 bit aligned */ - return (void __user *)((usp - frame_size) & -8UL); + return (void *)((usp - frame_size) & -8UL); } static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe __user *frame; + struct rt_sigframe *frame; int err = 0; frame = get_sigframe(ksig, regs, sizeof(*frame)); diff --git a/arch/parisc/include/asm/traps.h b/arch/parisc/include/asm/traps.h index d0e090a2c000da4a94ee55fa84e2956ae96c3821..8ecc1f0c0483d5a4a60dd44c08b6e49b9d3b776e 100644 --- a/arch/parisc/include/asm/traps.h +++ b/arch/parisc/include/asm/traps.h @@ -17,7 +17,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err); const char *trap_name(unsigned long code); void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address); -int handle_nadtlb_fault(struct pt_regs *regs); #endif #endif diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index bce47e0fb692cb77cfc803d95b41939d2d8799c0..269b737d26299cf09dda74abb22266f457df0766 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -661,8 +661,6 @@ void notrace handle_interruption(int code, struct pt_regs *regs) by hand. Technically we need to emulate: fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw */ - if (code == 17 && handle_nadtlb_fault(regs)) - return; fault_address = regs->ior; fault_space = regs->isr; break; diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 5faa3cff47387ac289fe5792e260c4b1bde0bd2b..716960f5d92ea460a4b1084954e7bb69ac6cc476 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -424,92 +424,3 @@ no_context: goto no_context; pagefault_out_of_memory(); } - -/* Handle non-access data TLB miss faults. - * - * For probe instructions, accesses to userspace are considered allowed - * if they lie in a valid VMA and the access type matches. We are not - * allowed to handle MM faults here so there may be situations where an - * actual access would fail even though a probe was successful. - */ -int -handle_nadtlb_fault(struct pt_regs *regs) -{ - unsigned long insn = regs->iir; - int breg, treg, xreg, val = 0; - struct vm_area_struct *vma, *prev_vma; - struct task_struct *tsk; - struct mm_struct *mm; - unsigned long address; - unsigned long acc_type; - - switch (insn & 0x380) { - case 0x280: - /* FDC instruction */ - fallthrough; - case 0x380: - /* PDC and FIC instructions */ - if (printk_ratelimit()) { - pr_warn("BUG: nullifying cache flush/purge instruction\n"); - show_regs(regs); - } - if (insn & 0x20) { - /* Base modification */ - breg = (insn >> 21) & 0x1f; - xreg = (insn >> 16) & 0x1f; - if (breg && xreg) - regs->gr[breg] += regs->gr[xreg]; - } - regs->gr[0] |= PSW_N; - return 1; - - case 0x180: - /* PROBE instruction */ - treg = insn & 0x1f; - if (regs->isr) { - tsk = current; - mm = tsk->mm; - if (mm) { - /* Search for VMA */ - address = regs->ior; - mmap_read_lock(mm); - vma = find_vma_prev(mm, address, &prev_vma); - mmap_read_unlock(mm); - - /* - * Check if access to the VMA is okay. - * We don't allow for stack expansion. - */ - acc_type = (insn & 0x40) ? VM_WRITE : VM_READ; - if (vma - && address >= vma->vm_start - && (vma->vm_flags & acc_type) == acc_type) - val = 1; - } - } - if (treg) - regs->gr[treg] = val; - regs->gr[0] |= PSW_N; - return 1; - - case 0x300: - /* LPA instruction */ - if (insn & 0x20) { - /* Base modification */ - breg = (insn >> 21) & 0x1f; - xreg = (insn >> 16) & 0x1f; - if (breg && xreg) - regs->gr[breg] += regs->gr[xreg]; - } - treg = insn & 0x1f; - if (treg) - regs->gr[treg] = 0; - regs->gr[0] |= PSW_N; - return 1; - - default: - break; - } - - return 0; -} diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 2f98df296843ef0982de8f1f1b533a1bf67d0fe9..6a9a852c3d5667e3063738287078b4215940d914 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -172,7 +172,7 @@ else CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,$(call cc-option,-mtune=power5)) CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mcpu=power5,-mcpu=power4) endif -else ifdef CONFIG_PPC_BOOK3E_64 +else CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64 endif diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts b/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts deleted file mode 100644 index 73f8c998c64dfefa6859cd5bcda8ddafcdc51f38..0000000000000000000000000000000000000000 --- a/arch/powerpc/boot/dts/fsl/t1040rdb-rev-a.dts +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * T1040RDB-REV-A Device Tree Source - * - * Copyright 2014 - 2015 Freescale Semiconductor Inc. - * - */ - -#include "t1040rdb.dts" - -/ { - model = "fsl,T1040RDB-REV-A"; - compatible = "fsl,T1040RDB-REV-A"; -}; - -&seville_port0 { - label = "ETH5"; -}; - -&seville_port2 { - label = "ETH7"; -}; - -&seville_port4 { - label = "ETH9"; -}; - -&seville_port6 { - label = "ETH11"; -}; diff --git a/arch/powerpc/boot/dts/fsl/t1040rdb.dts b/arch/powerpc/boot/dts/fsl/t1040rdb.dts index b6733e7e65805e47fc52d345040dd190ca0ea2e7..af0c8a6f561385ce9fcf9f24a4effccf9df21fe2 100644 --- a/arch/powerpc/boot/dts/fsl/t1040rdb.dts +++ b/arch/powerpc/boot/dts/fsl/t1040rdb.dts @@ -119,7 +119,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_0>; phy-mode = "qsgmii"; - label = "ETH3"; + label = "ETH5"; status = "okay"; }; @@ -135,7 +135,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_2>; phy-mode = "qsgmii"; - label = "ETH5"; + label = "ETH7"; status = "okay"; }; @@ -151,7 +151,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_4>; phy-mode = "qsgmii"; - label = "ETH7"; + label = "ETH9"; status = "okay"; }; @@ -167,7 +167,7 @@ managed = "in-band-status"; phy-handle = <&phy_qsgmii_6>; phy-mode = "qsgmii"; - label = "ETH9"; + label = "ETH11"; status = "okay"; }; diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 0182b291248ace8e4cb2bbbe7ce3422524de322c..58635960403c058b6c0d29f5e7b77c015c004303 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -344,37 +344,25 @@ static inline void __raw_writeq_be(unsigned long v, volatile void __iomem *addr) */ static inline void __raw_rm_writeb(u8 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - stbcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("stbcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } static inline void __raw_rm_writew(u16 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - sthcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("sthcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } static inline void __raw_rm_writel(u32 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - stwcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("stwcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr) { - __asm__ __volatile__(".machine push; \ - .machine power6; \ - stdcix %0,0,%1; \ - .machine pop;" + __asm__ __volatile__("stdcix %0,0,%1" : : "r" (val), "r" (paddr) : "memory"); } @@ -386,10 +374,7 @@ static inline void __raw_rm_writeq_be(u64 val, volatile void __iomem *paddr) static inline u8 __raw_rm_readb(volatile void __iomem *paddr) { u8 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - lbzcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("lbzcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } @@ -397,10 +382,7 @@ static inline u8 __raw_rm_readb(volatile void __iomem *paddr) static inline u16 __raw_rm_readw(volatile void __iomem *paddr) { u16 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - lhzcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("lhzcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } @@ -408,10 +390,7 @@ static inline u16 __raw_rm_readw(volatile void __iomem *paddr) static inline u32 __raw_rm_readl(volatile void __iomem *paddr) { u32 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - lwzcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("lwzcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } @@ -419,10 +398,7 @@ static inline u32 __raw_rm_readl(volatile void __iomem *paddr) static inline u64 __raw_rm_readq(volatile void __iomem *paddr) { u64 ret; - __asm__ __volatile__(".machine push; \ - .machine power6; \ - ldcix %0,0, %1; \ - .machine pop;" + __asm__ __volatile__("ldcix %0,0, %1" : "=r" (ret) : "r" (paddr) : "memory"); return ret; } diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 6b808bcdecd52d4fb143ef77a319fa42e612ed2b..f53bfefb4a5773e15d2b36d4b9ee0bb3046e0831 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -229,11 +229,8 @@ extern long __get_user_bad(void); */ #define __get_user_atomic_128_aligned(kaddr, uaddr, err) \ __asm__ __volatile__( \ - ".machine push\n" \ - ".machine altivec\n" \ "1: lvx 0,0,%1 # get user\n" \ " stvx 0,0,%2 # put kernel\n" \ - ".machine pop\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index d89cf802d9aa771788b550cf9359571b77c5a4a8..617eba82531cb9916c5d34c7a5f087849a724601 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c @@ -669,7 +669,7 @@ static void __init kvm_use_magic_page(void) on_each_cpu(kvm_map_magic_page, &features, 1); /* Quick self-test to see if the mapping works */ - if (fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) { + if (!fault_in_pages_readable((const char *)KVM_MAGIC_PAGE, sizeof(u32))) { kvm_patching_worked = false; return; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 38b7a3491aac080a26aef0120c09fc32db7176af..527c205d5a5f5f4f05d7416ef83ede53d5479d23 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -5752,11 +5752,8 @@ static int kvmppc_book3s_init_hv(void) if (r) return r; - if (kvmppc_radix_possible()) { + if (kvmppc_radix_possible()) r = kvmppc_radix_init(); - if (r) - return r; - } /* * POWER9 chips before version 2.02 can't have some threads in diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index ef8077a739b8813c6fcb4be11b616a560c06615f..543db9157f3b1578ed4c3da17a4819f278c79876 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -1500,7 +1500,7 @@ int kvmppc_handle_vmx_load(struct kvm_vcpu *vcpu, { enum emulation_result emulated = EMULATE_DONE; - if (vcpu->arch.mmio_vmx_copy_nums > 2) + if (vcpu->arch.mmio_vsx_copy_nums > 2) return EMULATE_FAIL; while (vcpu->arch.mmio_vmx_copy_nums) { @@ -1597,7 +1597,7 @@ int kvmppc_handle_vmx_store(struct kvm_vcpu *vcpu, unsigned int index = rs & KVM_MMIO_REG_MASK; enum emulation_result emulated = EMULATE_DONE; - if (vcpu->arch.mmio_vmx_copy_nums > 2) + if (vcpu->arch.mmio_vsx_copy_nums > 2) return EMULATE_FAIL; vcpu->arch.io_gpr = rs; diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 2d19655328f12c7d7b9c3141b7251b71874c3444..0edebbbffcdcaa00f41f86f4e1d8e56f8e9feae9 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -108,9 +108,9 @@ static nokprobe_inline long address_ok(struct pt_regs *regs, { if (!user_mode(regs)) return 1; - if (access_ok((void __user *)ea, nb)) + if (__access_ok(ea, nb)) return 1; - if (access_ok((void __user *)ea, 1)) + if (__access_ok(ea, 1)) /* Access overlaps the end of the user region */ regs->dar = TASK_SIZE_MAX - 1; else @@ -949,10 +949,7 @@ NOKPROBE_SYMBOL(emulate_dcbz); #define __put_user_asmx(x, addr, err, op, cr) \ __asm__ __volatile__( \ - ".machine push\n" \ - ".machine power8\n" \ "1: " op " %2,0,%3\n" \ - ".machine pop\n" \ " mfcr %1\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ @@ -965,10 +962,7 @@ NOKPROBE_SYMBOL(emulate_dcbz); #define __get_user_asmx(x, addr, err, op) \ __asm__ __volatile__( \ - ".machine push\n" \ - ".machine power8\n" \ "1: "op" %1,0,%2\n" \ - ".machine pop\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ @@ -3193,7 +3187,7 @@ int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) __put_user_asmx(op->val, ea, err, "stbcx.", cr); break; case 2: - __put_user_asmx(op->val, ea, err, "sthcx.", cr); + __put_user_asmx(op->val, ea, err, "stbcx.", cr); break; #endif case 4: diff --git a/arch/powerpc/mm/kasan/kasan_init_32.c b/arch/powerpc/mm/kasan/kasan_init_32.c index f3e4d069e0ba7b822cee880ecf4e016addf4b2b0..cf8770b1a692ec4a2349fc0645ca1375252df7bb 100644 --- a/arch/powerpc/mm/kasan/kasan_init_32.c +++ b/arch/powerpc/mm/kasan/kasan_init_32.c @@ -83,12 +83,13 @@ void __init kasan_update_early_region(unsigned long k_start, unsigned long k_end, pte_t pte) { unsigned long k_cur; + phys_addr_t pa = __pa(kasan_early_shadow_page); for (k_cur = k_start; k_cur != k_end; k_cur += PAGE_SIZE) { pmd_t *pmd = pmd_off_k(k_cur); pte_t *ptep = pte_offset_kernel(pmd, k_cur); - if (pte_page(*ptep) != virt_to_page(lm_alias(kasan_early_shadow_page))) + if ((pte_val(*ptep) & PTE_RPN_MASK) != pa) continue; __set_pte_at(&init_mm, k_cur, ptep, pte, 0); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 275c60f92a7ce21d86d176e49b365da339ece665..094a1076fd1fe3601f445048c669d836de6e4ec1 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -742,9 +742,7 @@ static int __init parse_numa_properties(void) of_node_put(cpu); } - /* node_set_online() is an UB if 'nid' is negative */ - if (likely(nid >= 0)) - node_set_online(nid); + node_set_online(nid); } get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index e8074d7f2401b7eef06c27dd1124bc092b0274eb..7b25548ec42b0db3ae872adce803de2a75ef9e03 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -1457,11 +1457,7 @@ static int trace_imc_event_init(struct perf_event *event) event->hw.idx = -1; - /* - * There can only be a single PMU for perf_hw_context events which is assigned to - * core PMU. Hence use "perf_sw_context" for trace_imc. - */ - event->pmu->task_ctx_nr = perf_sw_context; + event->pmu->task_ctx_nr = perf_hw_context; event->destroy = reset_global_refc; return 0; } diff --git a/arch/powerpc/platforms/8xx/pic.c b/arch/powerpc/platforms/8xx/pic.c index 04a6abf14c2958ca5f3f98a3bba203152be5104c..f2ba837249d694ab47a843ecff366191b64ea4cb 100644 --- a/arch/powerpc/platforms/8xx/pic.c +++ b/arch/powerpc/platforms/8xx/pic.c @@ -153,7 +153,6 @@ int __init mpc8xx_pic_init(void) if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret = -ENOMEM; - goto out; } ret = 0; diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c index 69c344c8884f36b120075ecf2c9123481299756a..72c25295c1c2b4e9bd89824dbf99d5646a1d5624 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c @@ -43,11 +43,7 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) unsigned long parity; /* Calculate the parity of the value */ - asm (".machine push; \ - .machine power7; \ - popcntd %0,%1; \ - .machine pop;" - : "=r" (parity) : "r" (val)); + asm ("popcntd %0,%1" : "=r" (parity) : "r" (val)); /* xor our value with the previous mask */ val ^= rng->mask; diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c index 39186ad6b3c3a96f7291ed77782b0f028350656a..8963eaffb1b7b54234cecaedea9f8fd42677470e 100644 --- a/arch/powerpc/sysdev/fsl_gtm.c +++ b/arch/powerpc/sysdev/fsl_gtm.c @@ -86,7 +86,7 @@ static LIST_HEAD(gtms); */ struct gtm_timer *gtm_get_timer16(void) { - struct gtm *gtm; + struct gtm *gtm = NULL; int i; list_for_each_entry(gtm, >ms, list_node) { @@ -103,7 +103,7 @@ struct gtm_timer *gtm_get_timer16(void) spin_unlock_irq(>m->lock); } - if (!list_empty(>ms)) + if (gtm) return ERR_PTR(-EBUSY); return ERR_PTR(-ENODEV); } diff --git a/arch/riscv/include/asm/module.lds.h b/arch/riscv/include/asm/module.lds.h index 1075beae1ac64521e4c98eadf9acc785deb93d3e..4254ff2ff04943f7df7053d6d8263edaba7a3f36 100644 --- a/arch/riscv/include/asm/module.lds.h +++ b/arch/riscv/include/asm/module.lds.h @@ -2,8 +2,8 @@ /* Copyright (C) 2017 Andes Technology Corporation */ #ifdef CONFIG_MODULE_SECTIONS SECTIONS { - .plt : { BYTE(0) } - .got : { BYTE(0) } - .got.plt : { BYTE(0) } + .plt (NOLOAD) : { BYTE(0) } + .got (NOLOAD) : { BYTE(0) } + .got.plt (NOLOAD) : { BYTE(0) } } #endif diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index d79ae9d98999f6b9dce68aaf00412fe08635e31b..a390711129de6471524141120419213e228a47e2 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -11,17 +11,11 @@ #include #include -#ifdef CONFIG_KASAN -#define KASAN_STACK_ORDER 1 -#else -#define KASAN_STACK_ORDER 0 -#endif - /* thread information allocation */ #ifdef CONFIG_64BIT -#define THREAD_SIZE_ORDER (2 + KASAN_STACK_ORDER) +#define THREAD_SIZE_ORDER (2) #else -#define THREAD_SIZE_ORDER (1 + KASAN_STACK_ORDER) +#define THREAD_SIZE_ORDER (1) #endif #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c index fb02811df71434ce30f2db7dbcf80a49f1bf9c64..ad3001cbdf6186778e09d33f285070c5d3f06ad9 100644 --- a/arch/riscv/kernel/perf_callchain.c +++ b/arch/riscv/kernel/perf_callchain.c @@ -19,8 +19,8 @@ static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry, { struct stackframe buftail; unsigned long ra = 0; - unsigned long __user *user_frame_tail = - (unsigned long __user *)(fp - sizeof(struct stackframe)); + unsigned long *user_frame_tail = + (unsigned long *)(fp - sizeof(struct stackframe)); /* Check accessibility of one struct frame_tail beyond */ if (!access_ok(user_frame_tail, sizeof(buftail))) @@ -77,7 +77,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, bool fill_callchain(unsigned long pc, void *entry) { - return perf_callchain_store(entry, pc) == 0; + return perf_callchain_store(entry, pc); } void notrace walk_stackframe(struct task_struct *task, diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 1da36dd34990b59b1d26ff18c01bbb046924802d..741d0701003af072bf2be08ac6ff8529da81dd6a 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -65,7 +65,7 @@ struct rt_signal_frame { */ static inline bool invalid_frame_pointer(void __user *fp, int fplen) { - if ((((unsigned long) fp) & 15) || !access_ok(fp, fplen)) + if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen)) return true; return false; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 2d20773b7d8ee237e90b49a1bc9c216b5b62f0c6..a2e680f7d39f25af3bcfc09bfaac464de7faec66 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -223,7 +223,7 @@ void mconsole_go(struct mc_request *req) void mconsole_stop(struct mc_request *req) { - block_signals(); + deactivate_fd(req->originating_fd, MCONSOLE_IRQ); os_set_fd_block(req->originating_fd, 1); mconsole_reply(req, "stopped", 0, 0); for (;;) { @@ -246,7 +246,6 @@ void mconsole_stop(struct mc_request *req) } os_set_fd_block(req->originating_fd, 0); mconsole_reply(req, "", 0, 0); - unblock_signals(); } static DEFINE_SPINLOCK(mc_devices_lock); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5e28d4a0dff5a71e326a10452ced75f28a51343d..f6fb0f6277b958cea9828f88848c83f132924e40 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -76,6 +76,7 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_DEVMAP if X86_64 select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_NONLEAF_PMD_YOUNG select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_COPY_MC if X86_64 select ARCH_HAS_SET_MEMORY diff --git a/arch/x86/configs/gki_defconfig b/arch/x86/configs/gki_defconfig index 76cb80cb70c3f3f3069ef78c923db2aca2943453..103720489453e3fe33cf6c05a70f94e24c147aad 100644 --- a/arch/x86/configs/gki_defconfig +++ b/arch/x86/configs/gki_defconfig @@ -99,6 +99,10 @@ CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=16 CONFIG_READ_ONLY_THP_FOR_FS=y CONFIG_ANON_VMA_NAME=y +CONFIG_LRU_GEN=y +CONFIG_DAMON=y +CONFIG_DAMON_PADDR=y +CONFIG_DAMON_RECLAIM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -302,6 +306,7 @@ CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_WIREGUARD=y CONFIG_IFB=y +CONFIG_MACSEC=y CONFIG_TUN=y CONFIG_VETH=y CONFIG_PPP=y @@ -313,7 +318,6 @@ CONFIG_PPPOL2TP=y CONFIG_USB_RTL8150=y CONFIG_USB_RTL8152=y CONFIG_USB_USBNET=y -# CONFIG_USB_NET_AX88179_178A is not set CONFIG_USB_NET_CDC_EEM=y # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set @@ -505,6 +509,7 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_F2FS_UNFAIR_RWSEM=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index cc3b79c06685303983984ef191973f12ebe7ca90..c084899e9582546d96cb49997e936ef1a8d89939 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -472,7 +472,7 @@ static u64 pt_config_filters(struct perf_event *event) pt->filters.filter[range].msr_b = filter->msr_b; } - rtit_ctl |= (u64)filter->config << pt_address_ranges[range].reg_off; + rtit_ctl |= filter->config << pt_address_ranges[range].reg_off; } return rtit_ctl; diff --git a/arch/x86/include/asm/kfence.h b/arch/x86/include/asm/kfence.h index 97bbb4a9083a76cce625d5255d2e25ce86aeb2a5..05b48b33baf0b811b2788750d4539f18c9bd2255 100644 --- a/arch/x86/include/asm/kfence.h +++ b/arch/x86/include/asm/kfence.h @@ -56,8 +56,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) else set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); - /* Flush this CPU's TLB. */ + /* + * Flush this CPU's TLB, assuming whoever did the allocation/free is + * likely to continue running on this CPU. + */ + preempt_disable(); flush_tlb_one_kernel(addr); + preempt_enable(); return true; } diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 87de9f2d71cf29d649924ea9784cece375283ef2..ed09aca6203ad27de6d887b385119c07c8436e99 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -846,7 +846,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) static inline int pmd_bad(pmd_t pmd) { - return (pmd_flags(pmd) & ~_PAGE_USER) != _KERNPG_TABLE; + return (pmd_flags(pmd) & ~(_PAGE_USER | _PAGE_ACCESSED)) != + (_KERNPG_TABLE & ~_PAGE_ACCESSED); } static inline unsigned long pages_to_mb(unsigned long npg) @@ -1452,10 +1453,10 @@ static inline bool arch_has_pfn_modify_check(void) return boot_cpu_has_bug(X86_BUG_L1TF); } -#define arch_faults_on_old_pte arch_faults_on_old_pte -static inline bool arch_faults_on_old_pte(void) +#define arch_has_hw_pte_young arch_has_hw_pte_young +static inline bool arch_has_hw_pte_young(void) { - return false; + return true; } #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 55562a9b7f92e9d6bc5f5db958dee01753f8321c..14cd3186dc77dc7a929a47026bfa8c3152f89308 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1340,17 +1340,6 @@ static int __init disable_acpi_pci(const struct dmi_system_id *d) return 0; } -static int __init disable_acpi_xsdt(const struct dmi_system_id *d) -{ - if (!acpi_force) { - pr_notice("%s detected: force use of acpi=rsdt\n", d->ident); - acpi_gbl_do_not_use_xsdt = TRUE; - } else { - pr_notice("Warning: DMI blacklist says broken, but acpi XSDT forced\n"); - } - return 0; -} - static int __init dmi_disable_acpi(const struct dmi_system_id *d) { if (!acpi_force) { @@ -1475,19 +1464,6 @@ static const struct dmi_system_id acpi_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), }, }, - /* - * Boxes that need ACPI XSDT use disabled due to corrupted tables - */ - { - .callback = disable_acpi_xsdt, - .ident = "Advantech DAC-BJ01", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "NEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "Bearlake CRB Board"), - DMI_MATCH(DMI_BIOS_VERSION, "V1.12"), - DMI_MATCH(DMI_BIOS_DATE, "02/01/2011"), - }, - }, {} }; diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 18e952fed021bdaa185dcfe3824b7bf4a7f9639b..7462b79c39de6a7e42f4b537862d7bc21a39768d 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -532,7 +532,7 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector) } else if (apic_id < min && max - apic_id < KVM_IPI_CLUSTER_SIZE) { ipi_bitmap <<= min - apic_id; min = apic_id; - } else if (apic_id > min && apic_id < min + KVM_IPI_CLUSTER_SIZE) { + } else if (apic_id < min + KVM_IPI_CLUSTER_SIZE) { max = apic_id < max ? max : apic_id; } else { ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index a63df19ef4dad2d1d75d022b86e4559a107fa131..e82151ba95c091ffce968e3422536a5484ba500c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1718,6 +1718,11 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, goto exception; } + if (!seg_desc.p) { + err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; + goto exception; + } + dpl = seg_desc.dpl; switch (seg) { @@ -1757,10 +1762,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, case VCPU_SREG_TR: if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9)) goto exception; - if (!seg_desc.p) { - err_vec = NP_VECTOR; - goto exception; - } old_desc = seg_desc; seg_desc.type |= 2; /* busy */ ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, @@ -1785,11 +1786,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, break; } - if (!seg_desc.p) { - err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; - goto exception; - } - if (seg_desc.s) { /* mark segment as accessed */ if (!(seg_desc.type & 1)) { diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index d806139377bc684aca5fef4593c34ec86f8151fc..328f37e4fd3a723a48b198d56141aa2d99be1dbc 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -207,7 +207,7 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, struct kvm_vcpu *vcpu = synic_to_vcpu(synic); int ret; - if (!synic->active && (!host || data)) + if (!synic->active && !host) return 1; trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host); @@ -253,9 +253,6 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, case HV_X64_MSR_EOM: { int i; - if (!synic->active) - break; - for (i = 0; i < ARRAY_SIZE(synic->sint); i++) kvm_hv_notify_acked_sint(vcpu, i); break; @@ -639,7 +636,7 @@ static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config, struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - if (!synic->active && (!host || config)) + if (!synic->active && !host) return 1; trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id, @@ -663,7 +660,7 @@ static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count, struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - if (!synic->active && (!host || count)) + if (!synic->active && !host) return 1; trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id, diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index de11149e28e097ff24a78b1d524a6cb37389b902..677d21082454f637e4a9e092da78826c9bd28200 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2227,7 +2227,10 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data) void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) { - apic_set_tpr(vcpu->arch.apic, (cr8 & 0x0f) << 4); + struct kvm_lapic *apic = vcpu->arch.apic; + + apic_set_tpr(apic, ((cr8 & 0x0f) << 4) + | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4)); } u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index c6daeeff1d9c9d958e08375c8baaedc295f7069f..f8829134bf3413c8141e1c74cabb888853a90a15 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -34,8 +34,9 @@ #define PT_HAVE_ACCESSED_DIRTY(mmu) true #ifdef CONFIG_X86_64 #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL - #define CMPXCHG "cmpxchgq" + #define CMPXCHG cmpxchg #else + #define CMPXCHG cmpxchg64 #define PT_MAX_FULL_LEVELS 2 #endif #elif PTTYPE == 32 @@ -51,7 +52,7 @@ #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT #define PT_HAVE_ACCESSED_DIRTY(mmu) true - #define CMPXCHG "cmpxchgl" + #define CMPXCHG cmpxchg #elif PTTYPE == PTTYPE_EPT #define pt_element_t u64 #define guest_walker guest_walkerEPT @@ -64,9 +65,7 @@ #define PT_GUEST_DIRTY_SHIFT 9 #define PT_GUEST_ACCESSED_SHIFT 8 #define PT_HAVE_ACCESSED_DIRTY(mmu) ((mmu)->ept_ad) - #ifdef CONFIG_X86_64 - #define CMPXCHG "cmpxchgq" - #endif + #define CMPXCHG cmpxchg64 #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL #else #error Invalid PTTYPE value @@ -148,39 +147,43 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, pt_element_t __user *ptep_user, unsigned index, pt_element_t orig_pte, pt_element_t new_pte) { - int r = -EFAULT; - - if (!user_access_begin(ptep_user, sizeof(pt_element_t))) - return -EFAULT; - -#ifdef CMPXCHG - asm volatile("1:" LOCK_PREFIX CMPXCHG " %[new], %[ptr]\n" - "mov $0, %[r]\n" - "setnz %b[r]\n" - "2:" - _ASM_EXTABLE_UA(1b, 2b) - : [ptr] "+m" (*ptep_user), - [old] "+a" (orig_pte), - [r] "+q" (r) - : [new] "r" (new_pte) - : "memory"); -#else - asm volatile("1:" LOCK_PREFIX "cmpxchg8b %[ptr]\n" - "movl $0, %[r]\n" - "jz 2f\n" - "incl %[r]\n" - "2:" - _ASM_EXTABLE_UA(1b, 2b) - : [ptr] "+m" (*ptep_user), - [old] "+A" (orig_pte), - [r] "+rm" (r) - : [new_lo] "b" ((u32)new_pte), - [new_hi] "c" ((u32)(new_pte >> 32)) - : "memory"); -#endif + int npages; + pt_element_t ret; + pt_element_t *table; + struct page *page; + + npages = get_user_pages_fast((unsigned long)ptep_user, 1, FOLL_WRITE, &page); + if (likely(npages == 1)) { + table = kmap_atomic(page); + ret = CMPXCHG(&table[index], orig_pte, new_pte); + kunmap_atomic(table); + + kvm_release_page_dirty(page); + } else { + struct vm_area_struct *vma; + unsigned long vaddr = (unsigned long)ptep_user & PAGE_MASK; + unsigned long pfn; + unsigned long paddr; + + mmap_read_lock(current->mm); + vma = find_vma_intersection(current->mm, vaddr, vaddr + PAGE_SIZE); + if (!vma || !(vma->vm_flags & VM_PFNMAP)) { + mmap_read_unlock(current->mm); + return -EFAULT; + } + pfn = ((vaddr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + paddr = pfn << PAGE_SHIFT; + table = memremap(paddr, PAGE_SIZE, MEMREMAP_WB); + if (!table) { + mmap_read_unlock(current->mm); + return -EFAULT; + } + ret = CMPXCHG(&table[index], orig_pte, new_pte); + memunmap(table); + mmap_read_unlock(current->mm); + } - user_access_end(); - return r; + return (ret != orig_pte); } static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 073514bbb5f715684d8ef584583d6dc27a732c9c..7e08efb06839379328323af53ad7b887dbbbc284 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -902,9 +902,6 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, if (tdp_mmu_iter_cond_resched(kvm, &iter, false)) continue; - if (!is_shadow_present_pte(iter.old_spte)) - continue; - if (spte_ad_need_write_protect(iter.old_spte)) { if (is_writable_pte(iter.old_spte)) new_spte = iter.old_spte & ~PT_WRITABLE_MASK; diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 3e5cb74c0b5386f4b81a3e7845d1353d1e92dbbc..a8b5533cf601d686b21bd8e11dd874ae70f8c1a6 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -806,7 +806,7 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, { struct kvm_kernel_irq_routing_entry *e; struct kvm_irq_routing_table *irq_rt; - int idx, ret = 0; + int idx, ret = -EINVAL; if (!kvm_arch_has_assigned_device(kvm) || !irq_remapping_cap(IRQ_POSTING_CAP)) @@ -817,13 +817,7 @@ int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq, idx = srcu_read_lock(&kvm->irq_srcu); irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu); - - if (guest_irq >= irq_rt->nr_rt_entries || - hlist_empty(&irq_rt->map[guest_irq])) { - pr_warn_once("no route for guest_irq %u/%u (broken user space?)\n", - guest_irq, irq_rt->nr_rt_entries); - goto out; - } + WARN_ON(guest_irq >= irq_rt->nr_rt_entries); hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) { struct vcpu_data vcpu_info; diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index f6a9e2e3664259e56844c54385e3f97409900b07..fd0f1cb6fc6c974a11675fd6c6d87ff764641859 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma, return ret; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp) { @@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, return ret; } +#endif + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE int pudp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pud_t *pudp) { diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index d7249f4c90f1b9c48d68f70f51e6d7d03d6a65ca..e13b0b49fcdfc181c19f76de1c968b9a344e8a70 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -512,7 +512,10 @@ irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id) return ret; } -bool is_xen_pmu; +bool is_xen_pmu(int cpu) +{ + return (get_xenpmu_data() != NULL); +} void xen_pmu_init(int cpu) { @@ -523,7 +526,7 @@ void xen_pmu_init(int cpu) BUILD_BUG_ON(sizeof(struct xen_pmu_data) > PAGE_SIZE); - if (xen_hvm_domain() || (cpu != 0 && !is_xen_pmu)) + if (xen_hvm_domain()) return; xenpmu_data = (struct xen_pmu_data *)get_zeroed_page(GFP_KERNEL); @@ -544,8 +547,7 @@ void xen_pmu_init(int cpu) per_cpu(xenpmu_shared, cpu).xenpmu_data = xenpmu_data; per_cpu(xenpmu_shared, cpu).flags = 0; - if (!is_xen_pmu) { - is_xen_pmu = true; + if (cpu == 0) { perf_register_guest_info_callbacks(&xen_guest_cbs); xen_pmu_arch_init(); } diff --git a/arch/x86/xen/pmu.h b/arch/x86/xen/pmu.h index 65c58894fc79f6d94a1ce860112ded726e0801f2..0e83a160589bc2e6c9149bbbae7e049c08e0e8c0 100644 --- a/arch/x86/xen/pmu.h +++ b/arch/x86/xen/pmu.h @@ -4,8 +4,6 @@ #include -extern bool is_xen_pmu; - irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id); #ifdef CONFIG_XEN_HAVE_VPMU void xen_pmu_init(int cpu); @@ -14,6 +12,7 @@ void xen_pmu_finish(int cpu); static inline void xen_pmu_init(int cpu) {} static inline void xen_pmu_finish(int cpu) {} #endif +bool is_xen_pmu(int cpu); bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err); bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err); int pmu_apic_update(uint32_t reg); diff --git a/arch/x86/xen/smp_pv.c b/arch/x86/xen/smp_pv.c index 35b6d15d874d046cc9c0a4a73aad541dbfcfa963..8f9e7e2407c873621f50c6954e6cff712437c6bf 100644 --- a/arch/x86/xen/smp_pv.c +++ b/arch/x86/xen/smp_pv.c @@ -130,7 +130,7 @@ int xen_smp_intr_init_pv(unsigned int cpu) per_cpu(xen_irq_work, cpu).irq = rc; per_cpu(xen_irq_work, cpu).name = callfunc_name; - if (is_xen_pmu) { + if (is_xen_pmu(cpu)) { pmu_name = kasprintf(GFP_KERNEL, "pmu%d", cpu); rc = bind_virq_to_irqhandler(VIRQ_XENPMU, cpu, xen_pmu_irq_handler, diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 9dd4efe1bf0bd0108f1c809636aa78776858876e..7f63aca6a0d340632646ccceb9f31ae63b878402 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -226,8 +226,8 @@ extern unsigned long get_wchan(struct task_struct *p); #define xtensa_set_sr(x, sr) \ ({ \ - __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: \ - "a"((unsigned int)(x))); \ + unsigned int v = (unsigned int)(x); \ + __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: "a"(v)); \ }) #define xtensa_get_sr(sr) \ diff --git a/arch/xtensa/kernel/jump_label.c b/arch/xtensa/kernel/jump_label.c index 0dde21e0d3de4c2836bbce5c7fee361811863ec8..61cf6497a646b7ec0273f0c8e823df64cffd9824 100644 --- a/arch/xtensa/kernel/jump_label.c +++ b/arch/xtensa/kernel/jump_label.c @@ -61,7 +61,7 @@ static void patch_text(unsigned long addr, const void *data, size_t sz) .data = data, }; stop_machine_cpuslocked(patch_text_stop_machine, - &patch, cpu_online_mask); + &patch, NULL); } else { unsigned long flags; diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index c2fdd6fcdaee664039c530efe04bf08743b3b0ba..b791e2041e49b3bbdf1c3e41fc8ea1fb589e647a 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -642,12 +642,6 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq, { struct bfq_entity *entity = &bfqq->entity; - /* - * oom_bfqq is not allowed to move, oom_bfqq will hold ref to root_group - * until elevator exit. - */ - if (bfqq == &bfqd->oom_bfqq) - return; /* * Get extra reference to prevent bfqq from being freed in * next possible expire or deactivate. diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 4edec39ba1ba9741addf5c19d418ded36e2d5b2c..481b80a609942fc13b02551e987a010d3e7e8660 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -2526,15 +2526,6 @@ bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) * are likely to increase the throughput. */ bfqq->new_bfqq = new_bfqq; - /* - * The above assignment schedules the following redirections: - * each time some I/O for bfqq arrives, the process that - * generated that I/O is disassociated from bfqq and - * associated with new_bfqq. Here we increases new_bfqq->ref - * in advance, adding the number of processes that are - * expected to be associated with new_bfqq as they happen to - * issue I/O. - */ new_bfqq->ref += process_refs; return new_bfqq; } @@ -2594,10 +2585,6 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, { struct bfq_queue *in_service_bfqq, *new_bfqq; - /* if a merge has already been setup, then proceed with that first */ - if (bfqq->new_bfqq) - return bfqq->new_bfqq; - /* * Do not perform queue merging if the device is non * rotational and performs internal queueing. In fact, such a @@ -2652,6 +2639,9 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, if (bfq_too_late_for_merging(bfqq)) return NULL; + if (bfqq->new_bfqq) + return bfqq->new_bfqq; + if (!io_struct || unlikely(bfqq == &bfqd->oom_bfqq)) return NULL; @@ -4806,7 +4796,7 @@ static struct request *bfq_dispatch_request(struct blk_mq_hw_ctx *hctx) struct bfq_data *bfqd = hctx->queue->elevator->elevator_data; struct request *rq; struct bfq_queue *in_serv_queue; - bool waiting_rq, idle_timer_disabled = false; + bool waiting_rq, idle_timer_disabled; spin_lock_irq(&bfqd->lock); @@ -4814,15 +4804,14 @@ static struct request *bfq_dispatch_request(struct blk_mq_hw_ctx *hctx) waiting_rq = in_serv_queue && bfq_bfqq_wait_request(in_serv_queue); rq = __bfq_dispatch_request(hctx); - if (in_serv_queue == bfqd->in_service_queue) { - idle_timer_disabled = - waiting_rq && !bfq_bfqq_wait_request(in_serv_queue); - } + + idle_timer_disabled = + waiting_rq && !bfq_bfqq_wait_request(in_serv_queue); spin_unlock_irq(&bfqd->lock); - bfq_update_dispatch_stats(hctx->queue, rq, - idle_timer_disabled ? in_serv_queue : NULL, - idle_timer_disabled); + + bfq_update_dispatch_stats(hctx->queue, rq, in_serv_queue, + idle_timer_disabled); return rq; } diff --git a/block/blk-merge.c b/block/blk-merge.c index 006b1f0a59bc54e227340f709de7169024c69393..26f4bcc10de9d7d550d78ef765b50fad80bd5276 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -7,7 +7,6 @@ #include #include #include -#include #include @@ -555,9 +554,6 @@ static inline unsigned int blk_rq_get_max_segments(struct request *rq) static inline int ll_new_hw_segment(struct request *req, struct bio *bio, unsigned int nr_phys_segs) { - if (!blk_cgroup_mergeable(req, bio)) - goto no_merge; - if (blk_integrity_merge_bio(req->q, req, bio) == false) goto no_merge; @@ -654,9 +650,6 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req, if (total_phys_segments > blk_rq_get_max_segments(req)) return 0; - if (!blk_cgroup_mergeable(req, next->bio)) - return 0; - if (blk_integrity_merge_rq(q, req, next) == false) return 0; @@ -868,10 +861,6 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (rq->rq_disk != bio->bi_disk) return false; - /* don't merge across cgroup boundaries */ - if (!blk_cgroup_mergeable(rq, bio)) - return false; - /* only merge integrity protected bio into ditto rq */ if (blk_integrity_merge_bio(rq->q, rq, bio) == false) return false; diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index e0117f5f969de56ecc44a700cdf6ba85eec643b7..24c08963890e97e2089feaf015b111f3f7baf44d 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -194,18 +194,11 @@ static int __blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx) static int blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx) { - unsigned long end = jiffies + HZ; int ret; do { ret = __blk_mq_do_dispatch_sched(hctx); - if (ret != 1) - break; - if (need_resched() || time_is_before_jiffies(end)) { - blk_mq_delay_run_hw_queue(hctx, 0); - break; - } - } while (1); + } while (ret == 1); return ret; } diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 8c5816364dd179f1e582dc70b5a51a131f7f81c3..b513f1683af06f8cb8d43361a13620cb14c6d20c 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -958,17 +958,15 @@ void blk_unregister_queue(struct gendisk *disk) */ if (queue_is_mq(q)) blk_mq_unregister_dev(disk_to_dev(disk), q); + + kobject_uevent(&q->kobj, KOBJ_REMOVE); + kobject_del(&q->kobj); blk_trace_remove_sysfs(disk_to_dev(disk)); mutex_lock(&q->sysfs_lock); if (q->elevator) elv_unregister_queue(q); mutex_unlock(&q->sysfs_lock); - - /* Now that we've deleted all child objects, we can delete the queue. */ - kobject_uevent(&q->kobj, KOBJ_REMOVE); - kobject_del(&q->kobj); - mutex_unlock(&q->sysfs_dir_lock); kobject_put(&disk_to_dev(disk)->kobj); diff --git a/block/mq-deadline.c b/block/mq-deadline.c index 0c6e2b3cf98ebf32eb1789d9daf1da4b3526462a..6556aa2182a53ea1703d6f45412419435bb4bbcf 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -860,7 +860,7 @@ SHOW_JIFFIES(deadline_write_expire_show, dd->fifo_expire[DD_WRITE]); SHOW_JIFFIES(deadline_prio_aging_expire_show, dd->prio_aging_expire); SHOW_INT(deadline_writes_starved_show, dd->writes_starved); SHOW_INT(deadline_front_merges_show, dd->front_merges); -SHOW_INT(deadline_async_depth_show, dd->front_merges); +SHOW_INT(deadline_async_depth_show, dd->async_depth); SHOW_INT(deadline_fifo_batch_show, dd->fifo_batch); #undef SHOW_INT #undef SHOW_JIFFIES @@ -890,7 +890,7 @@ STORE_JIFFIES(deadline_write_expire_store, &dd->fifo_expire[DD_WRITE], 0, INT_MA STORE_JIFFIES(deadline_prio_aging_expire_store, &dd->prio_aging_expire, 0, INT_MAX); STORE_INT(deadline_writes_starved_store, &dd->writes_starved, INT_MIN, INT_MAX); STORE_INT(deadline_front_merges_store, &dd->front_merges, 0, 1); -STORE_INT(deadline_async_depth_store, &dd->front_merges, 1, INT_MAX); +STORE_INT(deadline_async_depth_store, &dd->async_depth, 1, INT_MAX); STORE_INT(deadline_fifo_batch_store, &dd->fifo_batch, 0, INT_MAX); #undef STORE_FUNCTION #undef STORE_INT diff --git a/build.config.common b/build.config.common index 3885d4604ab2e99e192744a881ff81c99f2e4de3..a07fb7f8c01202db2a915038f656388358a0dbc9 100644 --- a/build.config.common +++ b/build.config.common @@ -1,6 +1,6 @@ . ${ROOT_DIR}/${KERNEL_DIR}/build.config.constants -KMI_GENERATION=1 +KMI_GENERATION=4 LLVM=1 DEPMOD=depmod @@ -8,6 +8,7 @@ CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-${CLANG_VERSION}/bin BUILDTOOLS_PREBUILT_BIN=build/kernel/build-tools/path/linux-x86 DTC=${ROOT_DIR}/${BUILDTOOLS_PREBUILT_BIN}/dtc +KCFLAGS="${KCFLAGS} -D__ANDROID_COMMON_KERNEL__" EXTRA_CMDS='' STOP_SHIP_TRACEPRINTK=1 IN_KERNEL_MODULES=1 diff --git a/build.config.constants b/build.config.constants index 5094eea3655f55b407f6a1261cad9ebdbf5e5e4c..028ad6a8474972ffddf191e4d1d3fe85f59018af 100644 --- a/build.config.constants +++ b/build.config.constants @@ -1,2 +1,2 @@ BRANCH=android13-5.10 -CLANG_VERSION=r445002 +CLANG_VERSION=r450784e diff --git a/build.config.gki.aarch64 b/build.config.gki.aarch64 index ad0078a7fee7f3b7d9f313780c94a1d72e3ab953..2e7f202446bf37e21809875acc0b1ccea39d9a4e 100644 --- a/build.config.gki.aarch64 +++ b/build.config.gki.aarch64 @@ -35,3 +35,5 @@ MODULES_ORDER=android/gki_aarch64_modules if [ -n "${GKI_DEFCONFIG_FRAGMENT}" ]; then source ${GKI_DEFCONFIG_FRAGMENT} fi + +BUILD_GKI_CERTIFICATION_TOOLS=1 diff --git a/build.config.gki.x86_64 b/build.config.gki.x86_64 index b8f7773108e40cf9b0a80a7e6c750536271a9577..739ae0b86e0d2cd6cfa32dd30288116fac8b99fb 100644 --- a/build.config.gki.x86_64 +++ b/build.config.gki.x86_64 @@ -4,3 +4,5 @@ BUILD_SYSTEM_DLKM=1 MODULES_LIST=${ROOT_DIR}/${KERNEL_DIR}/android/gki_system_dlkm_modules + +BUILD_GKI_CERTIFICATION_TOOLS=1 diff --git a/crypto/authenc.c b/crypto/authenc.c index 17f674a7cdff5434a213f66f66ca5c6976b565de..670bf1a01d00e4c3fd1cda495973a78da9ae6db2 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -253,7 +253,7 @@ static int crypto_authenc_decrypt_tail(struct aead_request *req, dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); skcipher_request_set_tfm(skreq, ctx->enc); - skcipher_request_set_callback(skreq, flags, + skcipher_request_set_callback(skreq, aead_request_flags(req), req->base.complete, req->base.data); skcipher_request_set_crypt(skreq, src, dst, req->cryptlen - authsize, req->iv); diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index 9d804831c8b3f9d1dba390cd6f92aab574af7967..8ac3e73e8ea65121a9ccfbe9e598d757f426e933 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -476,8 +476,6 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) pos++; if (digest_info) { - if (digest_info->size > dst_len - pos) - goto done; if (crypto_memneq(out_buf + pos, digest_info->data, digest_info->size)) goto done; @@ -497,7 +495,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) sg_nents_for_len(req->src, req->src_len + req->dst_len), req_ctx->out_buf + ctx->key_size, - req->dst_len, req->src_len); + req->dst_len, ctx->key_size); /* Do the actual verification step. */ if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos, req->dst_len) != 0) @@ -540,7 +538,7 @@ static int pkcs1pad_verify(struct akcipher_request *req) if (WARN_ON(req->dst) || WARN_ON(!req->dst_len) || - !ctx->key_size || req->src_len != ctx->key_size) + !ctx->key_size || req->src_len < ctx->key_size) return -EINVAL; req_ctx->out_buf = kmalloc(ctx->key_size + req->dst_len, GFP_KERNEL); @@ -623,11 +621,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) rsa_alg = crypto_spawn_akcipher_alg(&ctx->spawn); - if (strcmp(rsa_alg->base.cra_name, "rsa") != 0) { - err = -EINVAL; - goto err_free_inst; - } - err = -ENAMETOOLONG; hash_name = crypto_attr_alg_name(tb[2]); if (IS_ERR(hash_name)) { diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 901fa5ca284d2f54f973a25b9529e88090d69193..b7f3e8603ad841f8af776d88415a960087a5ca1d 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -169,9 +169,6 @@ acpi_ns_walk_namespace(acpi_object_type type, if (start_node == ACPI_ROOT_OBJECT) { start_node = acpi_gbl_root_node; - if (!start_node) { - return_ACPI_STATUS(AE_NO_NAMESPACE); - } } /* Null child means "get first node" */ diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c index 598fd19b65fa489d1cc4d44da8db7ee072612e1a..19e50fcbf4d6f52771f573094f4fa635bcfd5ff6 100644 --- a/drivers/acpi/apei/bert.c +++ b/drivers/acpi/apei/bert.c @@ -29,7 +29,6 @@ #undef pr_fmt #define pr_fmt(fmt) "BERT: " fmt -#define ACPI_BERT_PRINT_MAX_LEN 1024 static int bert_disable; @@ -59,11 +58,8 @@ static void __init bert_print_all(struct acpi_bert_region *region, } pr_info_once("Error records from previous boot:\n"); - if (region_len < ACPI_BERT_PRINT_MAX_LEN) - cper_estatus_print(KERN_INFO HW_ERR, estatus); - else - pr_info_once("Max print length exceeded, table data is available at:\n" - "/sys/firmware/acpi/tables/data/BERT"); + + cper_estatus_print(KERN_INFO HW_ERR, estatus); /* * Because the boot error source is "one-time polled" type, @@ -81,7 +77,7 @@ static int __init setup_bert_disable(char *str) { bert_disable = 1; - return 1; + return 0; } __setup("bert_disable", setup_bert_disable); diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 83efb52a3f31d070cfde3fe9e34166ba3bed64de..2e0b0fcad9607c3803c6db616be62967e725d512 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -891,7 +891,7 @@ EXPORT_SYMBOL_GPL(erst_clear); static int __init setup_erst_disable(char *str) { erst_disable = 1; - return 1; + return 0; } __setup("erst_disable", setup_erst_disable); diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 7bf48c2776fbf5e417ccbb795fc59ffa9e3a2f4b..6e980fe16772cc194e8c8daa0589c31102d31b52 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -219,7 +219,7 @@ err: static int __init setup_hest_disable(char *str) { hest_disable = HEST_DISABLED; - return 1; + return 0; } __setup("hest_disable", setup_hest_disable); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index be743d177bcbf8ddc5089d6079c651550fb40179..2376f57b3617aa2f4ff47d4100a85d8ba792effa 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -66,10 +66,6 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, - - /* Microsoft Surface Go 3 */ - {"MSHW0146", 0}, - {"", 0}, }; @@ -1175,14 +1171,6 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad"), }, }, - { - /* Microsoft Surface Go 3 */ - .callback = battery_notification_delay_quirk, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"), - }, - }, {}, }; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 2ac0773326e9ab46c8523e0bd064e69fcbedd91e..0a2da06e9d8bf67de5a02146da59bd399ed44c0b 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -719,11 +719,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_obj = &out_obj->package.elements[0]; if (cpc_obj->type == ACPI_TYPE_INTEGER) { num_ent = cpc_obj->integer.value; - if (num_ent <= 1) { - pr_debug("Unexpected _CPC NumEntries value (%d) for CPU:%d\n", - num_ent, pr->id); - goto out_free; - } } else { pr_debug("Unexpected entry type(%d) for NumEntries\n", cpc_obj->type); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 35ecb57514caca0495e824e53b1224430c009aed..592e1ee9b338dae4c94bf28fe21728222e1bf51f 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -685,7 +685,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, */ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) { if (index) - return -ENOENT; + return -EINVAL; ret = acpi_bus_get_device(obj->reference.handle, &device); if (ret) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 7b9793cb55c504c6b027d031d7e435677a61cf66..33474fd969913c513d1acfd1577a0135f1c8a8d9 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -409,81 +409,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), }, }, - /* - * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a - * working native and video interface. However the default detection - * mechanism first registers the video interface before unregistering - * it again and switching to the native interface during boot. This - * results in a dangling SBIOS request for backlight change for some - * reason, causing the backlight to switch to ~2% once per boot on the - * first power cord connect or disconnect event. Setting the native - * interface explicitly circumvents this buggy behaviour, by avoiding - * the unregistering process. - */ - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "AURA1501"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xRU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), - }, - }, - { - .callback = video_detect_force_native, - .ident = "Clevo NL5xNU", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), - DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"), - }, - }, /* * Desktops which falsely report a backlight and which our heuristics diff --git a/drivers/android/binder.c b/drivers/android/binder.c index bcf0ae355bc643c74e7c1c11e89b72ff084db793..f13562617e638966b5ed536078b45d48cb7305a0 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2723,6 +2723,12 @@ static void binder_transaction(struct binder_proc *proc, goto err_dead_binder; } e->to_node = target_node->debug_id; + if (WARN_ON(proc == target_proc)) { + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; + } trace_android_vh_binder_trans(target_proc, proc, thread, tr); if (security_binder_transaction(proc->cred, target_proc->cred) < 0) { @@ -2892,7 +2898,7 @@ static void binder_transaction(struct binder_proc *proc, if (extra_buffers_size < added_size) { /* integer overflow of extra_buffers_size */ return_error = BR_FAILED_REPLY; - return_error_param = EINVAL; + return_error_param = -EINVAL; return_error_line = __LINE__; goto err_bad_extra_size; } @@ -3420,10 +3426,17 @@ static int binder_thread_write(struct binder_proc *proc, struct binder_node *ctx_mgr_node; mutex_lock(&context->context_mgr_node_lock); ctx_mgr_node = context->binder_context_mgr_node; - if (ctx_mgr_node) + if (ctx_mgr_node) { + if (ctx_mgr_node->proc == proc) { + binder_user_error("%d:%d context manager tried to acquire desc 0\n", + proc->pid, thread->pid); + mutex_unlock(&context->context_mgr_node_lock); + return -EINVAL; + } ret = binder_inc_ref_for_node( proc, ctx_mgr_node, strong, NULL, &rdata); + } mutex_unlock(&context->context_mgr_node_lock); } if (ret) diff --git a/drivers/android/vendor_hooks.c b/drivers/android/vendor_hooks.c index a72414c52a5a18d99ef734f3e4b23e8c6f898a7a..e8773213ed4c5853bf24cf0654ca3dfba0c29b40 100644 --- a/drivers/android/vendor_hooks.c +++ b/drivers/android/vendor_hooks.c @@ -8,6 +8,7 @@ #define CREATE_TRACE_POINTS #include +#include #include #include #include @@ -72,6 +73,8 @@ #include #include #include +#include +#include /* * Export tracepoints that act as a bare tracehook (ie: have no trace event @@ -382,3 +385,15 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_enable_thermal_power_throttle); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_thermal_power_cap); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_thermal_zone_device); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpm_modify_src_caps); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_grab_compound_head); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh___get_user_pages_remote); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_user_pages); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_internal_get_user_pages_fast); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_pin_user_pages); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_attach_entity_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_detach_entity_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_update_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_remove_entity_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_update_blocked_fair); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_update_rt_rq_load_avg); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 9fcc49be499f18a3cdfcf607f79891a345e36111..b574cce98dc3686ce473b1f2cc132b4de8616ed2 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1112,8 +1112,6 @@ DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); skb_data3 = skb->data[3]; paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr)) - return enq_next; ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b1b8f480a752a35cf5180480ba0810f226647642..d3b33edc40ece242a8942452810b49009f03d8b5 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -771,7 +771,7 @@ static int __init save_async_options(char *buf) pr_warn("Too long list of driver names for 'driver_async_probe'!\n"); strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN); - return 1; + return 0; } __setup("driver_async_probe=", save_async_options); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a1ae1c43f3c0d940171c6bd51152bfe5dd2f10db..1ec4520d77a93dc185e21dd8fe6caf0dcb57ab18 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -2005,9 +2005,7 @@ static bool pm_ops_is_empty(const struct dev_pm_ops *ops) void device_pm_check_callbacks(struct device *dev) { - unsigned long flags; - - spin_lock_irqsave(&dev->power.lock, flags); + spin_lock_irq(&dev->power.lock); dev->power.no_pm_callbacks = (!dev->bus || (pm_ops_is_empty(dev->bus->pm) && !dev->bus->suspend && !dev->bus->resume)) && @@ -2016,7 +2014,7 @@ void device_pm_check_callbacks(struct device *dev) (!dev->pm_domain || pm_ops_is_empty(&dev->pm_domain->ops)) && (!dev->driver || (pm_ops_is_empty(dev->driver->pm) && !dev->driver->suspend && !dev->driver->resume)); - spin_unlock_irqrestore(&dev->power.lock, flags); + spin_unlock_irq(&dev->power.lock); } bool dev_pm_skip_suspend(struct device *dev) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 69638146f949cfa339e6c428de6d8af1b0dd1a12..330f851cb8f0b0acccb15160f7a8f9cc64f723b8 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -177,8 +177,7 @@ void start_new_tl_epoch(struct drbd_connection *connection) void complete_master_bio(struct drbd_device *device, struct bio_and_error *m) { - if (unlikely(m->error)) - m->bio->bi_status = errno_to_blk_status(m->error); + m->bio->bi_status = errno_to_blk_status(m->error); bio_endio(m->bio); dec_ap_bio(device); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 64994c39a11740550de8bf5baa325e7229be87f0..dea24990d270ba0894a500a3287550e924206190 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -797,33 +797,33 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) { - return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_offset); + return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset); } static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf) { - return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); + return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); } static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) { int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR); - return sysfs_emit(buf, "%s\n", autoclear ? "1" : "0"); + return sprintf(buf, "%s\n", autoclear ? "1" : "0"); } static ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf) { int partscan = (lo->lo_flags & LO_FLAGS_PARTSCAN); - return sysfs_emit(buf, "%s\n", partscan ? "1" : "0"); + return sprintf(buf, "%s\n", partscan ? "1" : "0"); } static ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf) { int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO); - return sysfs_emit(buf, "%s\n", dio ? "1" : "0"); + return sprintf(buf, "%s\n", dio ? "1" : "0"); } LOOP_ATTR_RO(backing_file); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 263c0cd1aa1672157149cd7146ccc0c27694e332..73f30b5c2f5232ffba3f2cae9e9ebe1bc09a4acb 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -843,7 +843,7 @@ static int virtblk_probe(struct virtio_device *vdev) dev_err(&vdev->dev, "virtio_blk: invalid block size: 0x%x\n", blk_size); - goto out_free_tags; + goto out_cleanup_disk; } blk_queue_logical_block_size(q, blk_size); @@ -914,6 +914,8 @@ static int virtblk_probe(struct virtio_device *vdev) device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); return 0; +out_cleanup_disk: + blk_cleanup_queue(vblk->disk->queue); out_free_tags: blk_mq_free_tag_set(&vblk->tag_set); out_put_disk: diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index c41560be39fb6bcacb6a58a8a7b7e789b90c40d6..74856a58621622dae4582f05a4914dd7bdfe3f05 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -981,8 +981,6 @@ static int btmtksdio_probe(struct sdio_func *func, hdev->manufacturer = 70; set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); - sdio_set_drvdata(func, bdev); - err = hci_register_dev(hdev); if (err < 0) { dev_err(&func->dev, "Can't register HCI device\n"); @@ -990,6 +988,8 @@ static int btmtksdio_probe(struct sdio_func *func, return err; } + sdio_set_drvdata(func, bdev); + /* pm_runtime_enable would be done after the firmware is being * downloaded because the core layer probably already enables * runtime PM for this func such as the case host->caps & diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index e9a44ab3812df06e1714cb237eb15d4b72f3b5bd..9e03402ef1b378c2f613df7697f1708beba1f9b9 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -305,8 +305,6 @@ int hci_uart_register_device(struct hci_uart *hu, if (err) return err; - percpu_init_rwsem(&hu->proto_lock); - err = p->open(hu); if (err) goto err_open; @@ -329,6 +327,7 @@ int hci_uart_register_device(struct hci_uart *hu, INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); + percpu_init_rwsem(&hu->proto_lock); /* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index fca0d0669aa97e78168b20aa503a60fa9cdf72d1..626dedd110cbc2463b67cf48599242740a037e21 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -351,7 +351,6 @@ phys_addr_t __weak mips_cdmm_phys_base(void) np = of_find_compatible_node(NULL, NULL, "mti,mips-cdmm"); if (np) { err = of_address_to_resource(np, 0, &res); - of_node_put(np); if (!err) return res.start; } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index a7d9e4600d40e31eaf6d28b3844191023339179e..5952210526aaacff895cd6362ff2ca6e0f1d2135 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -427,7 +427,7 @@ config HW_RANDOM_MESON config HW_RANDOM_CAVIUM tristate "Cavium ThunderX Random Number Generator support" - depends on HW_RANDOM && PCI && ARCH_THUNDER + depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT)) default HW_RANDOM help This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 8cf0ef501341eafbdeb6ae31d95bc2327f7a0532..ecb71c4317a503a8772fb078cfec2950ce3a39d8 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -114,7 +114,6 @@ static int atmel_trng_probe(struct platform_device *pdev) err_register: clk_disable_unprepare(trng->clk); - atmel_trng_disable(trng); return ret; } diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c index 6f66919652bf571b25a8c2762de0fe12398aab67..3de4a6a443ef98ac3369228593147afd7cd1b862 100644 --- a/drivers/char/hw_random/cavium-rng-vf.c +++ b/drivers/char/hw_random/cavium-rng-vf.c @@ -1,7 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support. - * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. + * Hardware Random Number Generator support for Cavium, Inc. + * Thunder processor family. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * * Copyright (C) 2016 Cavium, Inc. */ @@ -12,146 +15,16 @@ #include #include -#include - -/* PCI device IDs */ -#define PCI_DEVID_CAVIUM_RNG_PF 0xA018 -#define PCI_DEVID_CAVIUM_RNG_VF 0xA033 - -#define HEALTH_STATUS_REG 0x38 - -/* RST device info */ -#define PCI_DEVICE_ID_RST_OTX2 0xA085 -#define RST_BOOT_REG 0x1600ULL -#define CLOCK_BASE_RATE 50000000ULL -#define MSEC_TO_NSEC(x) (x * 1000000) - struct cavium_rng { struct hwrng ops; void __iomem *result; - void __iomem *pf_regbase; - struct pci_dev *pdev; - u64 clock_rate; - u64 prev_error; - u64 prev_time; }; -static inline bool is_octeontx(struct pci_dev *pdev) -{ - if (midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_83XX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(3, 0)) || - midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_81XX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(3, 0)) || - midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(3, 0))) - return true; - - return false; -} - -static u64 rng_get_coprocessor_clkrate(void) -{ - u64 ret = CLOCK_BASE_RATE * 16; /* Assume 800Mhz as default */ - struct pci_dev *pdev; - void __iomem *base; - - pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVICE_ID_RST_OTX2, NULL); - if (!pdev) - goto error; - - base = pci_ioremap_bar(pdev, 0); - if (!base) - goto error_put_pdev; - - /* RST: PNR_MUL * 50Mhz gives clockrate */ - ret = CLOCK_BASE_RATE * ((readq(base + RST_BOOT_REG) >> 33) & 0x3F); - - iounmap(base); - -error_put_pdev: - pci_dev_put(pdev); - -error: - return ret; -} - -static int check_rng_health(struct cavium_rng *rng) -{ - u64 cur_err, cur_time; - u64 status, cycles; - u64 time_elapsed; - - - /* Skip checking health for OcteonTx */ - if (!rng->pf_regbase) - return 0; - - status = readq(rng->pf_regbase + HEALTH_STATUS_REG); - if (status & BIT_ULL(0)) { - dev_err(&rng->pdev->dev, "HWRNG: Startup health test failed\n"); - return -EIO; - } - - cycles = status >> 1; - if (!cycles) - return 0; - - cur_time = arch_timer_read_counter(); - - /* RNM_HEALTH_STATUS[CYCLES_SINCE_HEALTH_FAILURE] - * Number of coprocessor cycles times 2 since the last failure. - * This field doesn't get cleared/updated until another failure. - */ - cycles = cycles / 2; - cur_err = (cycles * 1000000000) / rng->clock_rate; /* In nanosec */ - - /* Ignore errors that happenned a long time ago, these - * are most likely false positive errors. - */ - if (cur_err > MSEC_TO_NSEC(10)) { - rng->prev_error = 0; - rng->prev_time = 0; - return 0; - } - - if (rng->prev_error) { - /* Calculate time elapsed since last error - * '1' tick of CNTVCT is 10ns, since it runs at 100Mhz. - */ - time_elapsed = (cur_time - rng->prev_time) * 10; - time_elapsed += rng->prev_error; - - /* Check if current error is a new one or the old one itself. - * If error is a new one then consider there is a persistent - * issue with entropy, declare hardware failure. - */ - if (cur_err < time_elapsed) { - dev_err(&rng->pdev->dev, "HWRNG failure detected\n"); - rng->prev_error = cur_err; - rng->prev_time = cur_time; - return -EIO; - } - } - - rng->prev_error = cur_err; - rng->prev_time = cur_time; - return 0; -} - /* Read data from the RNG unit */ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait) { struct cavium_rng *p = container_of(rng, struct cavium_rng, ops); unsigned int size = max; - int err = 0; - - err = check_rng_health(p); - if (err) - return err; while (size >= 8) { *((u64 *)dat) = readq(p->result); @@ -166,39 +39,6 @@ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait) return max; } -static int cavium_map_pf_regs(struct cavium_rng *rng) -{ - struct pci_dev *pdev; - - /* Health status is not supported on 83xx, skip mapping PF CSRs */ - if (is_octeontx(rng->pdev)) { - rng->pf_regbase = NULL; - return 0; - } - - pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVID_CAVIUM_RNG_PF, NULL); - if (!pdev) { - dev_err(&pdev->dev, "Cannot find RNG PF device\n"); - return -EIO; - } - - rng->pf_regbase = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!rng->pf_regbase) { - dev_err(&pdev->dev, "Failed to map PF CSR region\n"); - pci_dev_put(pdev); - return -ENOMEM; - } - - pci_dev_put(pdev); - - /* Get co-processor clock rate */ - rng->clock_rate = rng_get_coprocessor_clkrate(); - - return 0; -} - /* Map Cavium RNG to an HWRNG object */ static int cavium_rng_probe_vf(struct pci_dev *pdev, const struct pci_device_id *id) @@ -210,8 +50,6 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, if (!rng) return -ENOMEM; - rng->pdev = pdev; - /* Map the RNG result */ rng->result = pcim_iomap(pdev, 0, 0); if (!rng->result) { @@ -229,11 +67,6 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, pci_set_drvdata(pdev, rng); - /* Health status is available only at PF, hence map PF registers. */ - ret = cavium_map_pf_regs(rng); - if (ret) - return ret; - ret = devm_hwrng_register(&pdev->dev, &rng->ops); if (ret) { dev_err(&pdev->dev, "Error registering device as HWRNG.\n"); @@ -243,18 +76,10 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, return 0; } -/* Remove the VF */ -static void cavium_rng_remove_vf(struct pci_dev *pdev) -{ - struct cavium_rng *rng; - - rng = pci_get_drvdata(pdev); - iounmap(rng->pf_regbase); -} static const struct pci_device_id cavium_rng_vf_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CAVIUM_RNG_VF) }, - { 0, } + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0}, + {0,}, }; MODULE_DEVICE_TABLE(pci, cavium_rng_vf_id_table); @@ -262,9 +87,8 @@ static struct pci_driver cavium_rng_vf_driver = { .name = "cavium_rng_vf", .id_table = cavium_rng_vf_id_table, .probe = cavium_rng_probe_vf, - .remove = cavium_rng_remove_vf, }; module_pci_driver(cavium_rng_vf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/cavium-rng.c index b96579222408ba0bd24c4cdf2f063aa1bedf7514..63d6e68c24d2fc979f54345c2f71ad2e58b36236 100644 --- a/drivers/char/hw_random/cavium-rng.c +++ b/drivers/char/hw_random/cavium-rng.c @@ -1,7 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support. - * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. + * Hardware Random Number Generator support for Cavium Inc. + * Thunder processor family. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * * Copyright (C) 2016 Cavium, Inc. */ @@ -88,4 +91,4 @@ static struct pci_driver cavium_rng_pf_driver = { module_pci_driver(cavium_rng_pf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c index e8f9621e795410a21fdc6760e8c7b949c67172e7..67947a19aa225e8cd7b05622479452e8b5651bce 100644 --- a/drivers/char/hw_random/nomadik-rng.c +++ b/drivers/char/hw_random/nomadik-rng.c @@ -65,14 +65,14 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id) out_release: amba_release_regions(dev); out_clk: - clk_disable_unprepare(rng_clk); + clk_disable(rng_clk); return ret; } static void nmk_rng_remove(struct amba_device *dev) { amba_release_regions(dev); - clk_disable_unprepare(rng_clk); + clk_disable(rng_clk); } static const struct amba_id nmk_rng_ids[] = { diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index ed600473ad7e3e63d4d27a7e634bb96dc59320fa..ddaeceb7e109105297f6baf53d74138911246fed 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -274,6 +274,14 @@ static void tpm_dev_release(struct device *dev) kfree(chip); } +static void tpm_devs_release(struct device *dev) +{ + struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); + + /* release the master device reference */ + put_device(&chip->dev); +} + /** * tpm_class_shutdown() - prepare the TPM device for loss of power. * @dev: device to which the chip is associated. @@ -336,6 +344,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->dev_num = rc; device_initialize(&chip->dev); + device_initialize(&chip->devs); chip->dev.class = tpm_class; chip->dev.class->shutdown_pre = tpm_class_shutdown; @@ -343,12 +352,29 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->dev.parent = pdev; chip->dev.groups = chip->groups; + chip->devs.parent = pdev; + chip->devs.class = tpmrm_class; + chip->devs.release = tpm_devs_release; + /* get extra reference on main device to hold on + * behalf of devs. This holds the chip structure + * while cdevs is in use. The corresponding put + * is in the tpm_devs_release (TPM2 only) + */ + if (chip->flags & TPM_CHIP_FLAG_TPM2) + get_device(&chip->dev); + if (chip->dev_num == 0) chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); else chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); + chip->devs.devt = + MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); + rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num); + if (rc) + goto out; + rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); if (rc) goto out; @@ -356,7 +382,9 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, chip->flags |= TPM_CHIP_FLAG_VIRTUAL; cdev_init(&chip->cdev, &tpm_fops); + cdev_init(&chip->cdevs, &tpmrm_fops); chip->cdev.owner = THIS_MODULE; + chip->cdevs.owner = THIS_MODULE; rc = tpm2_init_space(&chip->work_space, TPM2_SPACE_BUFFER_SIZE); if (rc) { @@ -368,6 +396,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, return chip; out: + put_device(&chip->devs); put_device(&chip->dev); return ERR_PTR(rc); } @@ -416,9 +445,14 @@ static int tpm_add_char_device(struct tpm_chip *chip) } if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm_devs_add(chip); - if (rc) - goto err_del_cdev; + rc = cdev_device_add(&chip->cdevs, &chip->devs); + if (rc) { + dev_err(&chip->devs, + "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", + dev_name(&chip->devs), MAJOR(chip->devs.devt), + MINOR(chip->devs.devt), rc); + return rc; + } } /* Make the chip available. */ @@ -426,10 +460,6 @@ static int tpm_add_char_device(struct tpm_chip *chip) idr_replace(&dev_nums_idr, chip, chip->dev_num); mutex_unlock(&idr_lock); - return 0; - -err_del_cdev: - cdev_device_del(&chip->cdev, &chip->dev); return rc; } @@ -611,7 +641,7 @@ void tpm_chip_unregister(struct tpm_chip *chip) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2) - tpm_devs_remove(chip); + cdev_device_del(&chip->cdevs, &chip->devs); tpm_del_char_device(chip); } EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index b99e1941c52c98359863ed1bfb9c785ed22ceabe..1784530b8387bb46bec8694a49ddb5385833be80 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -70,13 +70,7 @@ static void tpm_dev_async_work(struct work_struct *work) ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); - - /* - * If ret is > 0 then tpm_dev_transmit returned the size of the - * response. If ret is < 0 then tpm_dev_transmit failed and - * returned an error code. - */ - if (ret != 0) { + if (ret > 0) { priv->response_length = ret; mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2163c6ee0d364f3f8ee935e5abae8f547b4a886f..283f78211c3a7bc09092085d12834c48571f93f3 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -234,8 +234,6 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd, size_t cmdsiz); int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf, size_t *bufsiz); -int tpm_devs_add(struct tpm_chip *chip); -void tpm_devs_remove(struct tpm_chip *chip); void tpm_bios_log_setup(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index ffb35f0154c16c463082962426dcc7bdaa4c3a38..97e916856cf3e25445c94256dbe94569f5e84524 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -58,12 +58,12 @@ int tpm2_init_space(struct tpm_space *space, unsigned int buf_size) void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) { - - if (tpm_try_get_ops(chip) == 0) { + mutex_lock(&chip->tpm_mutex); + if (!tpm_chip_start(chip)) { tpm2_flush_sessions(chip, space); - tpm_put_ops(chip); + tpm_chip_stop(chip); } - + mutex_unlock(&chip->tpm_mutex); kfree(space->context_buf); kfree(space->session_buf); } @@ -574,68 +574,3 @@ out: dev_err(&chip->dev, "%s: error %d\n", __func__, rc); return rc; } - -/* - * Put the reference to the main device. - */ -static void tpm_devs_release(struct device *dev) -{ - struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); - - /* release the master device reference */ - put_device(&chip->dev); -} - -/* - * Remove the device file for exposed TPM spaces and release the device - * reference. This may also release the reference to the master device. - */ -void tpm_devs_remove(struct tpm_chip *chip) -{ - cdev_device_del(&chip->cdevs, &chip->devs); - put_device(&chip->devs); -} - -/* - * Add a device file to expose TPM spaces. Also take a reference to the - * main device. - */ -int tpm_devs_add(struct tpm_chip *chip) -{ - int rc; - - device_initialize(&chip->devs); - chip->devs.parent = chip->dev.parent; - chip->devs.class = tpmrm_class; - - /* - * Get extra reference on main device to hold on behalf of devs. - * This holds the chip structure while cdevs is in use. The - * corresponding put is in the tpm_devs_release. - */ - get_device(&chip->dev); - chip->devs.release = tpm_devs_release; - chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); - cdev_init(&chip->cdevs, &tpmrm_fops); - chip->cdevs.owner = THIS_MODULE; - - rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); - if (rc) - goto err_put_devs; - - rc = cdev_device_add(&chip->cdevs, &chip->devs); - if (rc) { - dev_err(&chip->devs, - "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", - dev_name(&chip->devs), MAJOR(chip->devs.devt), - MINOR(chip->devs.devt), rc); - goto err_put_devs; - } - - return 0; - -err_put_devs: - put_device(&chip->devs); - - return rc; -} diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index c90db9fb5d8d77097d315d3e21de0c0b8982497a..a5e9d1a8a53c2122f33193e6c101bd76677ceacb 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1960,13 +1960,6 @@ static void virtcons_remove(struct virtio_device *vdev) list_del(&portdev->list); spin_unlock_irq(&pdrvdata_lock); - /* Device is going away, exit any polling for buffers */ - virtio_break_device(vdev); - if (use_multiport(portdev)) - flush_work(&portdev->control_work); - else - flush_work(&portdev->config_work); - /* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ diff --git a/drivers/clk/actions/owl-s700.c b/drivers/clk/actions/owl-s700.c index 6ea7da1d6d755e25c191fc91d5e2780343c08680..a2f34d13fb54304357eed076ceb11e31863e76d2 100644 --- a/drivers/clk/actions/owl-s700.c +++ b/drivers/clk/actions/owl-s700.c @@ -162,7 +162,6 @@ static struct clk_div_table hdmia_div_table[] = { static struct clk_div_table rmii_div_table[] = { {0, 4}, {1, 10}, - {0, 0} }; /* divider clocks */ diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c index 5144ada2c7e1a46ac2617e0cd1af7f9dcc1c37c7..790890978424a241c8229c7592c2843b1fdb694d 100644 --- a/drivers/clk/actions/owl-s900.c +++ b/drivers/clk/actions/owl-s900.c @@ -140,7 +140,7 @@ static struct clk_div_table rmii_ref_div_table[] = { static struct clk_div_table usb3_mac_div_table[] = { { 1, 2 }, { 2, 3 }, { 3, 4 }, - { 0, 0 } + { 0, 8 }, }; static struct clk_div_table i2s_div_table[] = { diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index 9d25b23fb99d7f8c706aa4d36e9b18afca2bb3d1..a092a940baa40bc857ff5f26d3bd1d07c4f06ec8 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -606,16 +606,16 @@ static const struct { { .n = "pdmc0_gclk", .id = 68, .r = { .max = 50000000 }, - .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, - .pp_mux_table = { 5, 9, }, + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, + .pp_mux_table = { 5, 8, }, .pp_count = 2, .pp_chg_id = INT_MIN, }, { .n = "pdmc1_gclk", .id = 69, .r = { .max = 50000000, }, - .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, - .pp_mux_table = { 5, 9, }, + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, + .pp_mux_table = { 5, 8, }, .pp_count = 2, .pp_chg_id = INT_MIN, }, diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index f8417ee2961aaabc9c46e9007716d83b25a3c7bc..a2c6486ef1708bb387fd88b33e8bbd1fd04c730d 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -28,13 +28,11 @@ static const struct clk_div_table spi_div_table[] = { { .val = 1, .div = 8, }, { .val = 2, .div = 2, }, { .val = 3, .div = 1, }, - { /* sentinel */ } }; static const struct clk_div_table timer_div_table[] = { { .val = 0, .div = 256, }, { .val = 1, .div = 1, }, - { /* sentinel */ } }; struct clps711x_clk { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 67ff7d9b74e96854699df09ad4b5487389bc0400..411ca7a1c0882da8982284b64109de3dcca9677c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3446,19 +3446,6 @@ static void clk_core_reparent_orphans_nolock(void) __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); __clk_core_update_orphan_hold_state(orphan); - - /* - * __clk_init_parent() will set the initial req_rate to - * 0 if the clock doesn't have clk_ops::recalc_rate and - * is an orphan when it's registered. - * - * 'req_rate' is used by clk_set_rate_range() and - * clk_put() to trigger a clk_set_rate() call whenever - * the boundaries are modified. Let's make sure - * 'req_rate' is set to something non-zero so that - * clk_set_rate_range() doesn't drop the frequency. - */ - orphan->req_rate = orphan->rate; } } } diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 3f6fd7ef2a68fcca4c38de27afcbfaafa61af218..c4e0f1c07192f2d8ccd9c059940c104fe6205291 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -849,6 +849,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) hws[IMX7D_WDOG4_ROOT_CLK] = imx_clk_hw_gate4("wdog4_root_clk", "wdog_post_div", base + 0x49f0, 0); hws[IMX7D_KPP_ROOT_CLK] = imx_clk_hw_gate4("kpp_root_clk", "ipg_root_clk", base + 0x4aa0, 0); hws[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_hw_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0); + hws[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_hw_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0); hws[IMX7D_WRCLK_ROOT_CLK] = imx_clk_hw_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0); hws[IMX7D_USB_CTRL_CLK] = imx_clk_hw_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0); hws[IMX7D_USB_PHY1_CLK] = imx_clk_hw_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0); diff --git a/drivers/clk/loongson1/clk-loongson1c.c b/drivers/clk/loongson1/clk-loongson1c.c index 1ebf740380efbd38f6a912e59e3488c4fc76a2e9..703f87622cf5f7042c216a27b5842ec83e146a99 100644 --- a/drivers/clk/loongson1/clk-loongson1c.c +++ b/drivers/clk/loongson1/clk-loongson1c.c @@ -37,7 +37,6 @@ static const struct clk_div_table ahb_div_table[] = { [1] = { .val = 1, .div = 4 }, [2] = { .val = 2, .div = 3 }, [3] = { .val = 3, .div = 3 }, - [4] = { /* sentinel */ } }; void __init ls1x_clk_init(void) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 71a0d30cf44dffc7c44708b32c869197360335ee..59a5a0f261f336098748b02453a4b59a9910e7f1 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -264,7 +264,7 @@ static int clk_rcg2_determine_floor_rate(struct clk_hw *hw, static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) { - u32 cfg, mask, d_val, not2d_val, n_minus_m; + u32 cfg, mask; struct clk_hw *hw = &rcg->clkr.hw; int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src); @@ -283,17 +283,8 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) if (ret) return ret; - /* Calculate 2d value */ - d_val = f->n; - - n_minus_m = f->n - f->m; - n_minus_m *= 2; - - d_val = clamp_t(u32, d_val, f->m, n_minus_m); - not2d_val = ~d_val & mask; - ret = regmap_update_bits(rcg->clkr.regmap, - RCG_D_OFFSET(rcg), mask, not2d_val); + RCG_D_OFFSET(rcg), mask, ~f->n); if (ret) return ret; } @@ -648,7 +639,6 @@ static const struct frac_entry frac_table_pixel[] = { { 2, 9 }, { 4, 9 }, { 1, 1 }, - { 2, 3 }, { } }; diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 541016db3c4bbae76a6374eebe383bd39f95bb6d..108fe27bee10f611f7417f01ffd52aec2c3fd4aa 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -60,6 +60,11 @@ static const struct parent_map gcc_xo_gpll0_gpll0_out_main_div2_map[] = { { P_GPLL0_DIV2, 4 }, }; +static const char * const gcc_xo_gpll0[] = { + "xo", + "gpll0", +}; + static const struct parent_map gcc_xo_gpll0_map[] = { { P_XO, 0 }, { P_GPLL0, 1 }, @@ -951,11 +956,6 @@ static struct clk_rcg2 blsp1_uart6_apps_clk_src = { }, }; -static const struct clk_parent_data gcc_xo_gpll0[] = { - { .fw_name = "xo" }, - { .hw = &gpll0.clkr.hw }, -}; - static const struct freq_tbl ftbl_pcie_axi_clk_src[] = { F(19200000, P_XO, 1, 0, 0), F(200000000, P_GPLL0, 4, 0, 0), @@ -969,7 +969,7 @@ static struct clk_rcg2 pcie0_axi_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "pcie0_axi_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_names = gcc_xo_gpll0, .num_parents = 2, .ops = &clk_rcg2_ops, }, @@ -1016,7 +1016,7 @@ static struct clk_rcg2 pcie1_axi_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "pcie1_axi_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_names = gcc_xo_gpll0, .num_parents = 2, .ops = &clk_rcg2_ops, }, @@ -1074,7 +1074,7 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { .name = "sdcc1_apps_clk_src", .parent_names = gcc_xo_gpll0_gpll2_gpll0_out_main_div2, .num_parents = 4, - .ops = &clk_rcg2_floor_ops, + .ops = &clk_rcg2_ops, }, }; @@ -1330,7 +1330,7 @@ static struct clk_rcg2 nss_ce_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "nss_ce_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_names = gcc_xo_gpll0, .num_parents = 2, .ops = &clk_rcg2_ops, }, @@ -4329,7 +4329,8 @@ static struct clk_rcg2 pcie0_rchng_clk_src = { .parent_map = gcc_xo_gpll0_map, .clkr.hw.init = &(struct clk_init_data){ .name = "pcie0_rchng_clk_src", - .parent_data = gcc_xo_gpll0, + .parent_hws = (const struct clk_hw *[]) { + &gpll0.clkr.hw }, .num_parents = 2, .ops = &clk_rcg2_ops, }, diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c index 463a444c8a7e4dad1e349a9c658dafd07b947c73..144d2ba7a9bef10660884cf4185dc551694260f8 100644 --- a/drivers/clk/qcom/gcc-msm8994.c +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -108,7 +108,6 @@ static struct clk_alpha_pll gpll4_early = { static struct clk_alpha_pll_postdiv gpll4 = { .offset = 0x1dc0, - .width = 4, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], .clkr.hw.init = &(struct clk_init_data) { diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c index 733a962ff521ac53d5f1310abd740955c90d4872..745f9faa98d8ef00e7bcc3483bfdf4584ba525d8 100644 --- a/drivers/clk/tegra/clk-tegra124-emc.c +++ b/drivers/clk/tegra/clk-tegra124-emc.c @@ -191,7 +191,6 @@ static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra) tegra->emc = platform_get_drvdata(pdev); if (!tegra->emc) { - put_device(&pdev->dev); pr_err("%s: cannot find EMC driver\n", __func__); return NULL; } diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c index 3bc55ab75314bf8d87e05490d95ae0c1c0c4c174..5319cd3804801f03bf181e0807b965ab4ee0c1fd 100644 --- a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c +++ b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c @@ -24,7 +24,6 @@ struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, init.name = name; init.ops = &clk_fixed_rate_ops; - init.flags = 0; init.parent_names = NULL; init.num_parents = 0; diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 279ddff81ab4955a7106dd3504433fa41f546a4e..eb596ff9e7bb30908e82f80c04e8046893ce2b8c 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -229,10 +229,8 @@ static int __init parse_pmtmr(char *arg) int ret; ret = kstrtouint(arg, 16, &base); - if (ret) { - pr_warn("PMTMR: invalid 'pmtmr=' value: '%s'\n", arg); - return 1; - } + if (ret) + return ret; pr_info("PMTMR IOPort override: 0x%04x -> 0x%04x\n", pmtmr_ioport, base); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index df194b05e944c631415207f19aa166f36fddf691..fabad79baafce28ea848a1b42538bed66b3d6893 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -494,14 +494,11 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) return 0; } -static int __init exynos4_timer_resources(struct device_node *np) +static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { + int err, cpu; struct clk *mct_clk, *tick_clk; - reg_base = of_iomap(np, 0); - if (!reg_base) - panic("%s: unable to ioremap mct address space\n", __func__); - tick_clk = of_clk_get_by_name(np, "fin_pll"); if (IS_ERR(tick_clk)) panic("%s: unable to determine tick clock rate\n", __func__); @@ -512,32 +509,9 @@ static int __init exynos4_timer_resources(struct device_node *np) panic("%s: unable to retrieve mct clock instance\n", __func__); clk_prepare_enable(mct_clk); - return 0; -} - -static int __init exynos4_timer_interrupts(struct device_node *np, - unsigned int int_type) -{ - int nr_irqs, i, err, cpu; - - mct_int_type = int_type; - - /* This driver uses only one global timer interrupt */ - mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); - - /* - * Find out the number of local irqs specified. The local - * timer irqs are specified after the four global timer - * irqs are specified. - */ - nr_irqs = of_irq_count(np); - if (nr_irqs > ARRAY_SIZE(mct_irqs)) { - pr_err("exynos-mct: too many (%d) interrupts configured in DT\n", - nr_irqs); - nr_irqs = ARRAY_SIZE(mct_irqs); - } - for (i = MCT_L0_IRQ; i < nr_irqs; i++) - mct_irqs[i] = irq_of_parse_and_map(np, i); + reg_base = base; + if (!reg_base) + panic("%s: unable to ioremap mct address space\n", __func__); if (mct_int_type == MCT_INT_PPI) { @@ -548,14 +522,11 @@ static int __init exynos4_timer_interrupts(struct device_node *np, mct_irqs[MCT_L0_IRQ], err); } else { for_each_possible_cpu(cpu) { - int mct_irq; + int mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; struct mct_clock_event_device *pcpu_mevt = per_cpu_ptr(&percpu_mct_tick, cpu); pcpu_mevt->evt.irq = -1; - if (MCT_L0_IRQ + cpu >= ARRAY_SIZE(mct_irqs)) - break; - mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; irq_set_status_flags(mct_irq, IRQ_NOAUTOEN); if (request_irq(mct_irq, @@ -600,13 +571,24 @@ out_irq: static int __init mct_init_dt(struct device_node *np, unsigned int int_type) { + u32 nr_irqs, i; int ret; - ret = exynos4_timer_resources(np); - if (ret) - return ret; + mct_int_type = int_type; + + /* This driver uses only one global timer interrupt */ + mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); + + /* + * Find out the number of local irqs specified. The local + * timer irqs are specified after the four global timer + * irqs are specified. + */ + nr_irqs = of_irq_count(np); + for (i = MCT_L0_IRQ; i < nr_irqs; i++) + mct_irqs[i] = irq_of_parse_and_map(np, i); - ret = exynos4_timer_interrupts(np, int_type); + ret = exynos4_timer_resources(np, of_iomap(np, 0)); if (ret) return ret; diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c index 5c9485cb4e0590bfde56ba72d4c20afdc288fc76..59e11ca8ee73e02186335c9707f02b2030b511bc 100644 --- a/drivers/clocksource/timer-microchip-pit64b.c +++ b/drivers/clocksource/timer-microchip-pit64b.c @@ -121,7 +121,7 @@ static u64 mchp_pit64b_clksrc_read(struct clocksource *cs) return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); } -static u64 notrace mchp_pit64b_sched_read_clk(void) +static u64 mchp_pit64b_sched_read_clk(void) { return mchp_pit64b_cnt_read(mchp_pit64b_cs_base); } diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index c5c84c7895f055c98bae48078520261eea8aaf3f..fd3b8686cba3820e1973938f4b930c8d0cefdbf9 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -157,9 +157,9 @@ static int timer_of_base_init(struct device_node *np, of_base->base = of_base->name ? of_io_request_and_map(np, of_base->index, of_base->name) : of_iomap(np, of_base->index); - if (IS_ERR_OR_NULL(of_base->base)) { - pr_err("Failed to iomap (%s:%s)\n", np->name, of_base->name); - return of_base->base ? PTR_ERR(of_base->base) : -ENOMEM; + if (IS_ERR(of_base->base)) { + pr_err("Failed to iomap (%s)\n", of_base->name); + return PTR_ERR(of_base->base); } return 0; diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c index 2737407ff0698033daa955a41abd65cba914af6f..1fccb457fcc54233507a654813c3eeb220fb90c6 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -694,9 +694,9 @@ static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) return 0; } - if (pa == 0x4882c000) /* dra7 dmtimer15 */ + if (pa == 0x48034000) /* dra7 dmtimer3 */ return dmtimer_percpu_timer_init(np, 0); - else if (pa == 0x4882e000) /* dra7 dmtimer16 */ + else if (pa == 0x48036000) /* dra7 dmtimer4 */ return dmtimer_percpu_timer_init(np, 1); return 0; diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index 7fdd30e92e42973bfb549500f77a06a4638fe9b4..fba9937a406b387164a3836c69af2b1ebf2aa0c1 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -130,7 +130,7 @@ static void get_krait_bin_format_b(struct device *cpu_dev, } /* Check PVS_BLOW_STATUS */ - pte_efuse = *(((u32 *)buf) + 1); + pte_efuse = *(((u32 *)buf) + 4); pte_efuse &= BIT(21); if (pte_efuse) { dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 64133d4da3d566b88fdb905e5ecc3c39cbe74a98..33707a2e55ff0c2dd0e2f16c1487c708038db867 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -11,7 +11,6 @@ * You could find a link for the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -281,9 +280,7 @@ static int sun8i_ce_cipher_run(struct crypto_engine *engine, void *areq) flow = rctx->flow; err = sun8i_ce_run_task(ce, flow, crypto_tfm_alg_name(breq->base.tfm)); - local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c index 62c07a724d40e6b2f130f116a1009e8a21f04f3d..4c5a2c11d7141d95b38d0a0bd0d41f7c34d85a69 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-hash.c @@ -9,7 +9,6 @@ * * You could find the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -413,8 +412,6 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *breq) theend: kfree(buf); kfree(result); - local_bh_disable(); crypto_finalize_hash_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c index f783748462f94781f5553dff988afd2b0f51d877..7c355bc2fb0664172bd3c1f499bafd55a82234d1 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c @@ -11,7 +11,6 @@ * You could find a link for the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -272,9 +271,7 @@ static int sun8i_ss_handle_cipher_request(struct crypto_engine *engine, void *ar struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); err = sun8i_ss_cipher(breq); - local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c index 319fe3279a7162e5bc5811822878fe87a9543129..80e89066dbd1ae60f3a646a8a69481267b1d5074 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c @@ -30,8 +30,6 @@ static const struct ss_variant ss_a80_variant = { .alg_cipher = { SS_ALG_AES, SS_ALG_DES, SS_ALG_3DES, }, - .alg_hash = { SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, SS_ID_NOTSUPP, - }, .op_mode = { SS_OP_ECB, SS_OP_CBC, }, .ss_clks = { diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c index c9edecd43ef96cdc66c37338e6afc8856a0df1d7..756d5a783548227b0ebf7c29a09e538e1706b917 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c @@ -9,7 +9,6 @@ * * You could find the datasheet in Documentation/arm/sunxi.rst */ -#include #include #include #include @@ -441,8 +440,6 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq) theend: kfree(pad); kfree(result); - local_bh_disable(); crypto_finalize_hash_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/amlogic/amlogic-gxl-cipher.c index 652e72d030bb09a51f2d772e6817283b489b2ad8..8b5e07316352c3df6ac52ea27bebd11c0897fe72 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c +++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c @@ -265,9 +265,7 @@ static int meson_handle_cipher_request(struct crypto_engine *engine, struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); err = meson_cipher(breq); - local_bh_disable(); crypto_finalize_skcipher_request(engine, breq, err); - local_bh_enable(); return 0; } diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c index b3eea329f840fbc974aed0b93c2412c11efd9895..0770a83bf1a570c1b0392ab82f76e323ea4636b5 100644 --- a/drivers/crypto/ccp/ccp-dmaengine.c +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -633,20 +633,6 @@ static int ccp_terminate_all(struct dma_chan *dma_chan) return 0; } -static void ccp_dma_release(struct ccp_device *ccp) -{ - struct ccp_dma_chan *chan; - struct dma_chan *dma_chan; - unsigned int i; - - for (i = 0; i < ccp->cmd_q_count; i++) { - chan = ccp->ccp_dma_chan + i; - dma_chan = &chan->dma_chan; - tasklet_kill(&chan->cleanup_tasklet); - list_del_rcu(&dma_chan->device_node); - } -} - int ccp_dmaengine_register(struct ccp_device *ccp) { struct ccp_dma_chan *chan; @@ -751,7 +737,6 @@ int ccp_dmaengine_register(struct ccp_device *ccp) return 0; err_reg: - ccp_dma_release(ccp); kmem_cache_destroy(ccp->dma_desc_cache); err_cache: @@ -768,7 +753,6 @@ void ccp_dmaengine_unregister(struct ccp_device *ccp) return; dma_async_device_unregister(dma_dev); - ccp_dma_release(ccp); kmem_cache_destroy(ccp->dma_desc_cache); kmem_cache_destroy(ccp->dma_cmd_cache); diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c index 11e0278c8631d2e0b2ea5f0e406b02074218a658..a5e041d9d2cf132516aa43db7bb3d13ec04f703a 100644 --- a/drivers/crypto/ccree/cc_buffer_mgr.c +++ b/drivers/crypto/ccree/cc_buffer_mgr.c @@ -258,13 +258,6 @@ static int cc_map_sg(struct device *dev, struct scatterlist *sg, { int ret = 0; - if (!nbytes) { - *mapped_nents = 0; - *lbytes = 0; - *nents = 0; - return 0; - } - *nents = cc_get_sgl_nents(dev, sg, nbytes, lbytes); if (*nents > max_sg_nents) { *nents = 0; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index c289e4d5cbdc0517a9fba64ca05c0015400cefae..dafa6577a8451f2c175f44070a10be4760b34b92 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -254,8 +254,8 @@ static void cc_cipher_exit(struct crypto_tfm *tfm) &ctx_p->user.key_dma_addr); /* Free key buffer in context */ - dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); kfree_sensitive(ctx_p->user.key); + dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); } struct tdes_keys { diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index a9d3e675f7ff44ddaeef525c7ac8a0f1be1d8103..5edc91cdb4e65da310ba2e0247c5e272c79366a1 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -330,7 +330,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128); } - for_each_sg(req->src, src, sg_nents(req->src), i) { + for_each_sg(req->src, src, sg_nents(src), i) { src_buf = sg_virt(src); len = sg_dma_len(src); tlen += len; diff --git a/drivers/crypto/qat/qat_common/qat_crypto.c b/drivers/crypto/qat/qat_common/qat_crypto.c index 9210af8a1f58ccda41fca0f0983750abc5e03aef..ab621b7dbd203e700b1f252ac3c33a9d7b69318b 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.c +++ b/drivers/crypto/qat/qat_common/qat_crypto.c @@ -126,14 +126,6 @@ int qat_crypto_dev_config(struct adf_accel_dev *accel_dev) goto err; if (adf_cfg_section_add(accel_dev, "Accelerator0")) goto err; - - /* Temporarily set the number of crypto instances to zero to avoid - * registering the crypto algorithms. - * This will be removed when the algorithms will support the - * CRYPTO_TFM_REQ_MAY_BACKLOG flag - */ - instances = 0; - for (i = 0; i < instances; i++) { val = i; snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_BANK_NUM, i); diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c index 11f30fd48c1414780006ec57b7fca020ce1e891d..99ba8d51d10209de2d99c666bb790c181d800c64 100644 --- a/drivers/crypto/qcom-rng.c +++ b/drivers/crypto/qcom-rng.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -44,19 +43,16 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max) { unsigned int currsize = 0; u32 val; - int ret; /* read random data from hardware */ do { - ret = readl_poll_timeout(rng->base + PRNG_STATUS, val, - val & PRNG_STATUS_DATA_AVAIL, - 200, 10000); - if (ret) - return ret; + val = readl_relaxed(rng->base + PRNG_STATUS); + if (!(val & PRNG_STATUS_DATA_AVAIL)) + break; val = readl_relaxed(rng->base + PRNG_DATA_OUT); if (!val) - return -EINVAL; + break; if ((max - currsize) >= WORD_SZ) { memcpy(data, &val, WORD_SZ); @@ -65,10 +61,11 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max) } else { /* copy only remaining bytes */ memcpy(data, &val, max - currsize); + break; } } while (currsize < max); - return 0; + return currsize; } static int qcom_rng_generate(struct crypto_rng *tfm, @@ -90,7 +87,7 @@ static int qcom_rng_generate(struct crypto_rng *tfm, mutex_unlock(&rng->lock); clk_disable_unprepare(rng->clk); - return ret; + return 0; } static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed, diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c index 5bbf0d2722e11cffef500ad42a27cb7d5e65980a..1cece1a7d3f008fb60a2d2ecedfffc5ec8757e36 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c @@ -506,6 +506,7 @@ struct rk_crypto_tmp rk_ecb_des3_ede_alg = { .exit = rk_ablk_exit_tfm, .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, .setkey = rk_tdes_setkey, .encrypt = rk_des3_ede_ecb_encrypt, .decrypt = rk_des3_ede_ecb_decrypt, diff --git a/drivers/crypto/vmx/Kconfig b/drivers/crypto/vmx/Kconfig index b2c28b87f14b3d1566cbca862441f80bcc3e1ad9..c85fab7ef0bdd21754ad1a30ad833778b92832f6 100644 --- a/drivers/crypto/vmx/Kconfig +++ b/drivers/crypto/vmx/Kconfig @@ -2,11 +2,7 @@ config CRYPTO_DEV_VMX_ENCRYPT tristate "Encryption acceleration support on P8 CPU" depends on CRYPTO_DEV_VMX - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_CTR select CRYPTO_GHASH - select CRYPTO_XTS default m help Support for VMX cryptographic acceleration instructions on Power8 CPU. diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 260a247c60d2da5c56c93144cdaac1340fd2750a..cadbd0a1a1ef0220296faa93736f53b1b359783c 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -723,7 +723,6 @@ static int dax_fs_init(void) static void dax_fs_exit(void) { kern_unmount(dax_mnt); - rcu_barrier(); kmem_cache_destroy(dax_cache); } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a44db03329391395278c889d0ac6476ebc6baf1f..d3451a41d1ecb9f1d89b68fdb8a6fc19efc53c5e 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -606,10 +606,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) file->f_mode |= FMODE_LSEEK; dmabuf->file = file; - ret = dma_buf_stats_setup(dmabuf); - if (ret) - goto err_sysfs; - mutex_init(&dmabuf->lock); INIT_LIST_HEAD(&dmabuf->attachments); @@ -617,6 +613,10 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) list_add(&dmabuf->list_node, &db_list.head); mutex_unlock(&db_list.lock); + ret = dma_buf_stats_setup(dmabuf); + if (ret) + goto err_sysfs; + return dmabuf; err_sysfs: diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index cfbf10128aaedbc04ec6be9d6b6ab164c6e5ea79..db732f71e59aded339b3b0199579864436aa5510 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -181,10 +181,6 @@ static long udmabuf_create(struct miscdevice *device, if (ubuf->pagecount > pglimit) goto err; } - - if (!ubuf->pagecount) - goto err; - ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), GFP_KERNEL); if (!ubuf->pages) { diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c index 3e83769615d1cb71d335093aa2b8aeae276b5e0e..e1a958ae7925477b1d7c2ba310721ac046e094cd 100644 --- a/drivers/dma/hisi_dma.c +++ b/drivers/dma/hisi_dma.c @@ -30,7 +30,7 @@ #define HISI_DMA_MODE 0x217c #define HISI_DMA_OFFSET 0x100 -#define HISI_DMA_MSI_NUM 32 +#define HISI_DMA_MSI_NUM 30 #define HISI_DMA_CHAN_NUM 30 #define HISI_DMA_Q_DEPTH_VAL 1024 diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index e51838d749e2e415f4fc891b9ab0fc8f36831e4f..e1926483ae2fdc910a1cc785ac390c11c2ebd408 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -24,7 +24,7 @@ static bool dump_properties __initdata; static int __init dump_properties_enable(char *arg) { dump_properties = true; - return 1; + return 0; } __setup("dump_apple_properties", dump_properties_enable); diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 7e771c56c13c6194cbda0ac31a1359dd9d2d8d8f..0ef086e43090bb14f3789466bedf0af049e3d18d 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -266,7 +266,7 @@ static int efi_pstore_write(struct pstore_record *record) efi_name[i] = name[i]; ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, - false, record->size, record->psi->buf); + preemptible(), record->size, record->psi->buf); if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE)) if (!schedule_work(&efivar_work)) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index e3df82d5d37a83f2fe6958ab5ecfabe8581e286a..9fa86288b78a987490a9826ccac9727d580dba10 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -209,7 +209,7 @@ static int __init efivar_ssdt_setup(char *str) memcpy(efivar_ssdt, str, strlen(str)); else pr_warn("efivar_ssdt: name too long: %s\n", str); - return 1; + return 0; } __setup("efivar_ssdt=", efivar_ssdt_setup); diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 983e07dc022ede84376add92c25bc651b0b16bb2..931544c9f63d4b8e0ed169e491b51c15df2259b3 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -21,7 +21,7 @@ config GOOGLE_SMI config GOOGLE_COREBOOT_TABLE tristate "Coreboot Table Access" - depends on HAS_IOMEM && (ACPI || OF) + depends on ACPI || OF help This option enables the coreboot_table module, which provides other firmware modules access to the coreboot table. The coreboot table diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d3a1d4ce66c7a2e2882477aa56fedcee56f64110..0de70a6f8b2a5a839ffad057471f064d1d4b651f 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -749,6 +749,12 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) }; int ret; + desc.args[0] = addr; + desc.args[1] = size; + desc.args[2] = spare; + desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL, + QCOM_SCM_VAL); + ret = qcom_scm_call(__scm->dev, &desc, NULL); /* the pg table has been initialized already, ignore the error */ diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index 53c7e3f8cfde2925fba08d52c3292450ad79db74..2a7687911c097c964bed2444d45262441f2872e3 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -477,7 +477,7 @@ static int svc_normal_to_secure_thread(void *data) case INTEL_SIP_SMC_RSU_ERROR: pr_err("%s: STATUS_ERROR\n", __func__); cbdata->status = BIT(SVC_STATUS_ERROR); - cbdata->kaddr1 = &res.a1; + cbdata->kaddr1 = NULL; cbdata->kaddr2 = NULL; cbdata->kaddr3 = NULL; pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata); diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 87edc77260d20598ac5851c7e6098db674654db7..dbad73162c8333bf5161b688d9a53a4eb4ae71b4 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -525,6 +525,7 @@ static int tacoma_cabled_fsi_fixup(struct device *dev) static int fsi_master_aspeed_probe(struct platform_device *pdev) { struct fsi_master_aspeed *aspeed; + struct resource *res; int rc, links, reg; __be32 raw; @@ -534,28 +535,26 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) return rc; } - aspeed = kzalloc(sizeof(*aspeed), GFP_KERNEL); + aspeed = devm_kzalloc(&pdev->dev, sizeof(*aspeed), GFP_KERNEL); if (!aspeed) return -ENOMEM; aspeed->dev = &pdev->dev; - aspeed->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(aspeed->base)) { - rc = PTR_ERR(aspeed->base); - goto err_free_aspeed; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + aspeed->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(aspeed->base)) + return PTR_ERR(aspeed->base); aspeed->clk = devm_clk_get(aspeed->dev, NULL); if (IS_ERR(aspeed->clk)) { dev_err(aspeed->dev, "couldn't get clock\n"); - rc = PTR_ERR(aspeed->clk); - goto err_free_aspeed; + return PTR_ERR(aspeed->clk); } rc = clk_prepare_enable(aspeed->clk); if (rc) { dev_err(aspeed->dev, "couldn't enable clock\n"); - goto err_free_aspeed; + return rc; } rc = setup_cfam_reset(aspeed); @@ -590,7 +589,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw); if (rc) { dev_err(&pdev->dev, "failed to read hub version\n"); - goto err_release; + return rc; } reg = be32_to_cpu(raw); @@ -629,8 +628,6 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) err_release: clk_disable_unprepare(aspeed->clk); -err_free_aspeed: - kfree(aspeed); return rc; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index e828f9414ba2cfd9dc30dd2176534b818ba76e21..6c8f141103da47b0b581067c6a2e06363fbc05c0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6396,9 +6396,6 @@ static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder, mode = amdgpu_dm_create_common_mode(encoder, common_modes[i].name, common_modes[i].w, common_modes[i].h); - if (!mode) - continue; - drm_mode_probed_add(connector, mode); amdgpu_dm_connector->num_modes++; } @@ -8615,13 +8612,10 @@ static int dm_update_plane_state(struct dc *dc, static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc) { struct drm_connector *connector; - struct drm_connector_state *conn_state, *old_conn_state; + struct drm_connector_state *conn_state; struct amdgpu_dm_connector *aconnector = NULL; int i; - for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn_state, i) { - if (!conn_state->crtc) - conn_state = old_conn_state; - + for_each_new_connector_in_state(state, connector, conn_state, i) { if (conn_state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c index b037fd57fd366ce2237592ebf2e0b03928f53bf4..0e0f494fbb5e138b1f739cd664252d2899c2fc12 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c @@ -227,6 +227,14 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { .funcs = &pflip_irq_info_funcs\ } +#define vupdate_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\ + .funcs = &vblank_irq_info_funcs\ + } + /* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic * of DCE's DC_IRQ_SOURCE_VUPDATEx. */ @@ -340,6 +348,12 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = { dc_underflow_int_entry(6), [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), + vupdate_int_entry(0), + vupdate_int_entry(1), + vupdate_int_entry(2), + vupdate_int_entry(3), + vupdate_int_entry(4), + vupdate_int_entry(5), vupdate_no_lock_int_entry(0), vupdate_no_lock_int_entry(1), vupdate_no_lock_int_entry(2), diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 5abb68017f6ed6df2165114a36881264be9c4437..49109614510b8c8ef38ab94e2f4cac1db0867ac0 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2098,8 +2098,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ } } - /* setting should not be allowed from VF if not in one VF mode */ - if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) { + /* setting should not be allowed from VF */ + if (amdgpu_sriov_vf(adev)) { dev_attr->attr.mode &= ~S_IWUGO; dev_attr->store = NULL; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index ee27970cfff952d38b5d02cd8e368f8851d8ae57..e5893218fa4bb5c62fcd7b76a9336b5645527565 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -115,7 +115,7 @@ int smu_get_dpm_freq_range(struct smu_context *smu, uint32_t *min, uint32_t *max) { - int ret = -ENOTSUPP; + int ret = 0; if (!min && !max) return -EINVAL; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index a0f6ee15c24859a48f39c7120ad36a48ca28eec0..a9bb734366ae6ffa1172b394b851047170ff7e2c 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -169,7 +169,6 @@ #define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) #define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) -#define ADV7535_REG_POWER2_HPD_OVERRIDE BIT(6) #define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 #define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 #define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 338c6a2ad322b4ac2e898222788f53b330364410..940448fce41cd6219dc02e1221501a9d73da5340 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -351,17 +351,11 @@ static void __adv7511_power_on(struct adv7511 *adv7511) * from standby or are enabled. When the HPD goes low the adv7511 is * reset and the outputs are disabled which might cause the monitor to * go to standby again. To avoid this we ignore the HPD pin for the - * first few seconds after enabling the output. On the other hand - * adv7535 require to enable HPD Override bit for proper HPD. + * first few seconds after enabling the output. */ - if (adv7511->type == ADV7535) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7535_REG_POWER2_HPD_OVERRIDE, - ADV7535_REG_POWER2_HPD_OVERRIDE); - else - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_NONE); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HPD_SRC_MASK, + ADV7511_REG_POWER2_HPD_SRC_NONE); /* HACK: If we don't delay here edid probing doesn't work properly */ msleep(200); @@ -384,10 +378,6 @@ static void adv7511_power_on(struct adv7511 *adv7511) static void __adv7511_power_off(struct adv7511 *adv7511) { /* TODO: setup additional power down modes */ - if (adv7511->type == ADV7535) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7535_REG_POWER2_HPD_OVERRIDE, 0); - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); @@ -685,14 +675,9 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) status = connector_status_disconnected; } else { /* Renable HPD sensing */ - if (adv7511->type == ADV7535) - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7535_REG_POWER2_HPD_OVERRIDE, - ADV7535_REG_POWER2_HPD_OVERRIDE); - else - regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, - ADV7511_REG_POWER2_HPD_SRC_MASK, - ADV7511_REG_POWER2_HPD_SRC_BOTH); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HPD_SRC_MASK, + ADV7511_REG_POWER2_HPD_SRC_BOTH); } adv7511->status = status; diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 0ced08d81d7a262dc3c36af5b1f81ca460be2864..b31281f76117c02335393fc9b447a6e166b2570b 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -1286,7 +1286,6 @@ static const struct of_device_id cdns_dsi_of_match[] = { { .compatible = "cdns,dsi" }, { }, }; -MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); static struct platform_driver cdns_dsi_platform_driver = { .probe = cdns_dsi_drm_probe, diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index b68d335981588e42d884959a2e5fc4c1d0b1af10..6cac2e58cd15fb15e51b7026aca23ac9200c8421 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -1188,7 +1188,6 @@ static int nwl_dsi_probe(struct platform_device *pdev) ret = nwl_dsi_select_input(dsi); if (ret < 0) { - pm_runtime_disable(dev); mipi_dsi_host_unregister(&dsi->dsi_host); return ret; } diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index ec7745c31da07aaccdbde0a90cd220b6dd441e19..843265d7f1b123b3dee5c07cc4830314b8168c4e 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) if (ret) { dev_err(ctx->dev, "Failed to register RC device\n"); ctx->error = ret; - rc_free_device(rc_dev); + rc_free_device(ctx->rc_dev); return; } ctx->rc_dev = rc_dev; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index b10228b9e3a93bf4144ce6d6d3d818907edf9b92..29c0eb4bd7546d3452533607ffafff65c618cebe 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2566,9 +2566,8 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, if (!output_fmts) return NULL; - /* If dw-hdmi is the first or only bridge, avoid negociating with ourselves */ - if (list_is_singular(&bridge->encoder->bridge_chain) || - list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) { + /* If dw-hdmi is the only bridge, avoid negociating with ourselves */ + if (list_is_singular(&bridge->encoder->bridge_chain)) { *num_output_fmts = 1; output_fmts[0] = MEDIA_BUS_FMT_FIXED; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 376fa6eb46f6978afff4fd4d4b63c37c4818a8ad..6b268f9445b36aea903d13fdd8c76822d50c66dc 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -1172,7 +1172,6 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, ret = mipi_dsi_host_register(&dsi->dsi_host); if (ret) { dev_err(dev, "Failed to register MIPI host: %d\n", ret); - pm_runtime_disable(dev); dw_mipi_dsi_debugfs_remove(dsi); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 862e173d34315e7d3ccadaa2b7d604ce07d34fc2..3d7593ea79f14b6270154878f909679c401c0b5a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4806,8 +4806,7 @@ bool drm_detect_monitor_audio(struct edid *edid) if (!edid_ext) goto end; - has_audio = (edid_ext[0] == CEA_EXT && - (edid_ext[3] & EDID_BASIC_AUDIO) != 0); + has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0); if (has_audio) { DRM_DEBUG_KMS("Monitor has basic audio support\n"); @@ -4960,8 +4959,16 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, connector->name, dc_bpc); info->bpc = dc_bpc; + /* + * Deep color support mandates RGB444 support for all video + * modes and forbids YCRCB422 support for all video modes per + * HDMI 1.3 spec. + */ + info->color_formats = DRM_COLOR_FORMAT_RGB444; + /* YCRCB444 is optional according to spec. */ if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { + info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", connector->name); } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 6d083b98f6ae6242e34cf288872340c5cf0ff0d5..abff2d6cedd12ca99ecb9004635d5d20026d1240 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -376,21 +376,6 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, return -EINVAL; } - /* - * The port numbering and mapping here is bizarre. The now-obsolete - * swsci spec supports ports numbered [0..4]. Port E is handled as a - * special case, but port F and beyond are not. The functionality is - * supposed to be obsolete for new platforms. Just bail out if the port - * number is out of bounds after mapping. - */ - if (port > 4) { - drm_dbg_kms(&dev_priv->drm, - "[ENCODER:%d:%s] port %c (index %u) out of bounds for display power state notification\n", - intel_encoder->base.base.id, intel_encoder->base.name, - port_name(intel_encoder->port), port); - return -EINVAL; - } - if (!enable) parm |= 4 << 8; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 92dd65befbcb833244edfe0b88f3a1082e54ae68..5754bccff4d15030dd1a81d10a222e0b29c1fc2b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -423,7 +423,7 @@ vm_access(struct vm_area_struct *area, unsigned long addr, return -EACCES; addr -= area->vm_start; - if (range_overflows_t(u64, addr, len, obj->base.size)) + if (addr >= obj->base.size) return -EINVAL; /* As this is primarily for debugging, let's focus on simplicity */ diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 605ac8825a5911278e4e8c9e002aa1e087d7f728..2eb8df4697dfac6c0bd1e6a2098a62a296e0498c 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -212,6 +212,14 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, if (!imx_pd_format_supported(bus_fmt)) return -EINVAL; + if (bus_flags & + ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | + DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) { + dev_warn(imxpd->dev, "invalid bus_flags (%x)\n", bus_flags); + return -EINVAL; + } + bridge_state->output_bus_cfg.flags = bus_flags; bridge_state->input_bus_cfg.flags = bus_flags; imx_crtc_state->bus_flags = bus_flags; diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 728fea50941243f15c377f4bc40fd6ca99bf3952..2753067c08e68bfe22e483fae825fbfed9af5934 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -396,8 +396,10 @@ static void meson_drv_unbind(struct device *dev) drm_irq_uninstall(drm); drm_dev_put(drm); - if (priv->afbcd.ops) - priv->afbcd.ops->exit(priv); + if (priv->afbcd.ops) { + priv->afbcd.ops->reset(priv); + meson_rdma_free(priv); + } } static const struct component_master_ops meson_drv_master_ops = { diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.c b/drivers/gpu/drm/meson/meson_osd_afbcd.c index 0cdbe899402f84571e508f09f7c4a978d9d77d31..ffc6b584dbf85d82b778b37ebc3b0a069063ea08 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.c +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.c @@ -79,6 +79,11 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format) return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; } +static int meson_gxm_afbcd_init(struct meson_drm *priv) +{ + return 0; +} + static int meson_gxm_afbcd_reset(struct meson_drm *priv) { writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, @@ -88,16 +93,6 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv) return 0; } -static int meson_gxm_afbcd_init(struct meson_drm *priv) -{ - return 0; -} - -static void meson_gxm_afbcd_exit(struct meson_drm *priv) -{ - meson_gxm_afbcd_reset(priv); -} - static int meson_gxm_afbcd_enable(struct meson_drm *priv) { writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | @@ -177,7 +172,6 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv) struct meson_afbcd_ops meson_afbcd_gxm_ops = { .init = meson_gxm_afbcd_init, - .exit = meson_gxm_afbcd_exit, .reset = meson_gxm_afbcd_reset, .enable = meson_gxm_afbcd_enable, .disable = meson_gxm_afbcd_disable, @@ -275,18 +269,6 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format) return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; } -static int meson_g12a_afbcd_reset(struct meson_drm *priv) -{ - meson_rdma_reset(priv); - - meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | - VIU_SW_RESET_G12A_OSD1_AFBCD, - VIU_SW_RESET); - meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); - - return 0; -} - static int meson_g12a_afbcd_init(struct meson_drm *priv) { int ret; @@ -304,10 +286,16 @@ static int meson_g12a_afbcd_init(struct meson_drm *priv) return 0; } -static void meson_g12a_afbcd_exit(struct meson_drm *priv) +static int meson_g12a_afbcd_reset(struct meson_drm *priv) { - meson_g12a_afbcd_reset(priv); - meson_rdma_free(priv); + meson_rdma_reset(priv); + + meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | + VIU_SW_RESET_G12A_OSD1_AFBCD, + VIU_SW_RESET); + meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); + + return 0; } static int meson_g12a_afbcd_enable(struct meson_drm *priv) @@ -392,7 +380,6 @@ static int meson_g12a_afbcd_setup(struct meson_drm *priv) struct meson_afbcd_ops meson_afbcd_g12a_ops = { .init = meson_g12a_afbcd_init, - .exit = meson_g12a_afbcd_exit, .reset = meson_g12a_afbcd_reset, .enable = meson_g12a_afbcd_enable, .disable = meson_g12a_afbcd_disable, diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.h b/drivers/gpu/drm/meson/meson_osd_afbcd.h index e77ddeb6416f3c2998c45131e14dd9f3fb503f6d..5e5523304f42f95c305a850bcde238fc57988ca5 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.h +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.h @@ -14,7 +14,6 @@ struct meson_afbcd_ops { int (*init)(struct meson_drm *priv); - void (*exit)(struct meson_drm *priv); int (*reset)(struct meson_drm *priv); int (*enable)(struct meson_drm *priv); int (*disable)(struct meson_drm *priv); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 2a13e297e16df5a529e9a52ec6cbe283c4285ea7..509968c0d16bc7ad8874b33baf362078c3e29db9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1243,10 +1243,7 @@ static void mgag200_set_format_regs(struct mga_device *mdev, WREG_GFX(3, 0x00); WREG_GFX(4, 0x00); WREG_GFX(5, 0x40); - /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode), - * so that it doesn't hang when running kexec/kdump on G200_SE rev42. - */ - WREG_GFX(6, 0x0d); + WREG_GFX(6, 0x05); WREG_GFX(7, 0x0f); WREG_GFX(8, 0x0f); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index a0274fcfe9c9d58e92f2c8118e6ad3bfae004efb..f7f5c258b5537b38946e29150b99c4710abcd28c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1113,7 +1113,7 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) } - if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS && + if (dpu_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort && dpu_enc->cur_master->hw_mdptop && dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select) dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select( diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 74a13ccad34c0bb942983385ec46db5b5554241f..9b2b5044e8e05490003f534a6d34f10204304d22 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -34,14 +34,6 @@ int dpu_rm_destroy(struct dpu_rm *rm) { int i; - for (i = 0; i < ARRAY_SIZE(rm->dspp_blks); i++) { - struct dpu_hw_dspp *hw; - - if (rm->dspp_blks[i]) { - hw = to_dpu_hw_dspp(rm->dspp_blks[i]); - dpu_hw_dspp_destroy(hw); - } - } for (i = 0; i < ARRAY_SIZE(rm->pingpong_blks); i++) { struct dpu_hw_pingpong *hw; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 6cd6934c8c9f10760a2b89b2393a43ba721d7cf2..66f2ea3d42fc2074f430d598a6887a79b6105a7a 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1336,7 +1336,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv; - struct dp_display_private *dp_priv; int ret; if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) @@ -1345,8 +1344,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, priv = dev->dev_private; dp_display->drm_dev = dev; - dp_priv = container_of(dp_display, struct dp_display_private, dp_display); - ret = dp_display_request_irq(dp_display); if (ret) { DRM_ERROR("request_irq failed, ret=%d\n", ret); @@ -1364,8 +1361,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, return ret; } - dp_priv->panel->connector = dp_display->connector; - priv->connectors[priv->num_connectors++] = dp_display->connector; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c index a6ea89a5d51ab90806de88908bb7e7d961412c3b..667fa016496eeb11e61b774f8db98bb9565829b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/hsfw.c @@ -142,12 +142,11 @@ nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const char *name, int ver, hsfw->imem_size = desc->code_size; hsfw->imem_tag = desc->start_tag; - hsfw->imem = kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL); + hsfw->imem = kmalloc(desc->code_size, GFP_KERNEL); + memcpy(hsfw->imem, data + desc->code_off, desc->code_size); + nvkm_firmware_put(fw); - if (!hsfw->imem) - return -ENOMEM; - else - return 0; + return 0; } int diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 959dcbd8a29c175b3b697e23b784779a365f04ef..7ffd2a04ab23ad4758d0952be357e89d6e32c420 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2132,7 +2132,7 @@ static const struct display_timing innolux_g070y2_l01_timing = { static const struct panel_desc innolux_g070y2_l01 = { .timings = &innolux_g070y2_l01_timing, .num_timings = 1, - .bpc = 8, + .bpc = 6, .size = { .width = 152, .height = 91, diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 107ad2d764ec0de1fef6911ec691f9d457eb5f1b..2aae636f1cf5cbe10f0f51724a1062c19c6ab29b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -359,11 +359,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) panfrost_gpu_init_features(pfdev); - err = dma_set_mask_and_coherent(pfdev->dev, + dma_set_mask_and_coherent(pfdev->dev, DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); - if (err) - return err; - dma_set_max_seg_size(pfdev->dev, UINT_MAX); irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index de1333dc0d8670aa30dc9867d5c13a41691ea4a3..f46d377f0c3046309c2bf1d12415f593f6aed467 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1538,10 +1538,8 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) dsi->slave = platform_get_drvdata(gangster); of_node_put(np); - if (!dsi->slave) { - put_device(&gangster->dev); + if (!dsi->slave) return -EPROBE_DEFER; - } dsi->slave->master = dsi; } diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 8659558b518d6afc3100c19631363c42e6fe1b43..a2c09dca4eef945e76a2bf68da9f0db52bb39263 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -520,7 +520,6 @@ static int host1x_remove(struct platform_device *pdev) host1x_syncpt_deinit(host); reset_control_assert(host->rst); clk_disable_unprepare(host->clk); - host1x_channel_list_free(&host->channel_list); host1x_iommu_exit(host); return 0; diff --git a/drivers/greybus/svc.c b/drivers/greybus/svc.c index 51d0875a34800aec4ea11347060e4d1956443aba..ce7740ef449babaf0f7bfd1afd2021cb6c7a7aec 100644 --- a/drivers/greybus/svc.c +++ b/drivers/greybus/svc.c @@ -866,14 +866,8 @@ static int gb_svc_hello(struct gb_operation *op) gb_svc_debugfs_init(svc); - ret = gb_svc_queue_deferred_request(op); - if (ret) - goto err_remove_debugfs; - - return 0; + return gb_svc_queue_deferred_request(op); -err_remove_debugfs: - gb_svc_debugfs_exit(svc); err_unregister_device: gb_svc_watchdog_destroy(svc); device_del(&svc->dev); diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 587259b3db97c5c547b049ea81ba5017252e4771..a311b0a33eba7ff45501c396281daba4919a79b8 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1000,7 +1000,6 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, workitem.reports_supported |= STD_KEYBOARD; break; case 0x0f: - case 0x11: device_type = "eQUAD Lightspeed 1.2"; logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem); workitem.reports_supported |= STD_KEYBOARD; diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 14811d42a5a918bfdd2ba09c7dedaaf50317917a..998aad8a9e60893d5b5b5830245ea311fc6068c4 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -620,17 +620,6 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, if (report_type == HID_OUTPUT_REPORT) return -EINVAL; - /* - * In case of unnumbered reports the response from the device will - * not have the report ID that the upper layers expect, so we need - * to stash it the buffer ourselves and adjust the data size. - */ - if (!report_number) { - buf[0] = 0; - buf++; - count--; - } - /* +2 bytes to include the size of the reply in the query buffer */ ask_count = min(count + 2, (size_t)ihid->bufsize); @@ -652,9 +641,6 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, count = min(count, ret_count - 2); memcpy(buf, ihid->rawbuf + 2, count); - if (!report_number) - count++; - return count; } @@ -671,19 +657,17 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, mutex_lock(&ihid->reset_lock); - /* - * Note that both numbered and unnumbered reports passed here - * are supposed to have report ID stored in the 1st byte of the - * buffer, so we strip it off unconditionally before passing payload - * to i2c_hid_set_or_send_report which takes care of encoding - * everything properly. - */ + if (report_id) { + buf++; + count--; + } + ret = i2c_hid_set_or_send_report(client, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, - report_id, buf + 1, count - 1, use_data); + report_id, buf, count, use_data); - if (ret >= 0) - ret++; /* add report_id to the number of transferred bytes */ + if (report_id && ret >= 0) + ret++; /* add report_id to the number of transfered bytes */ mutex_unlock(&ihid->reset_lock); diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index b6d6d119035ca0405a46c3b94d64f35ea5159be0..6cf59fd26ad784356923115c3c28054a344990b0 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -656,12 +656,21 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, */ payload_max_size &= ~(L1_CACHE_BYTES - 1); - dma_buf = dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_KERNEL); + dma_buf = kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32); if (!dma_buf) { client_data->flag_retry = true; return -ENOMEM; } + dma_buf_phy = dma_map_single(devc, dma_buf, payload_max_size, + DMA_TO_DEVICE); + if (dma_mapping_error(devc, dma_buf_phy)) { + dev_err(cl_data_to_dev(client_data), "DMA map failed\n"); + client_data->flag_retry = true; + rv = -ENOMEM; + goto end_err_dma_buf_release; + } + ldr_xfer_dma_frag.fragment.hdr.command = LOADER_CMD_XFER_FRAGMENT; ldr_xfer_dma_frag.fragment.xfer_mode = LOADER_XFER_MODE_DIRECT_DMA; ldr_xfer_dma_frag.ddr_phys_addr = (u64)dma_buf_phy; @@ -681,7 +690,14 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, ldr_xfer_dma_frag.fragment.size = fragment_size; memcpy(dma_buf, &fw->data[fragment_offset], fragment_size); - /* Flush cache to be sure the data is in main memory. */ + dma_sync_single_for_device(devc, dma_buf_phy, + payload_max_size, + DMA_TO_DEVICE); + + /* + * Flush cache here because the dma_sync_single_for_device() + * does not do for x86. + */ clflush_cache_range(dma_buf, payload_max_size); dev_dbg(cl_data_to_dev(client_data), @@ -704,8 +720,15 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, fragment_offset += fragment_size; } + dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); + kfree(dma_buf); + return 0; + end_err_resp_buf_release: - dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy); + /* Free ISH buffer if not done already, in error case */ + dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); +end_err_dma_buf_release: + kfree(dma_buf); return rv; } diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 210e532ac277fe3057ffdd75e6ab89b08b22adb9..79e5356a737a2ad6b9fb19a498613eba20aa9761 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -17,7 +17,6 @@ config HYPERV_TIMER config HYPERV_UTILS tristate "Microsoft Hyper-V Utilities driver" depends on HYPERV && CONNECTOR && NLS - depends on PTP_1588_CLOCK_OPTIONAL help Select this option to enable the Hyper-V Utilities. diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 6a716996a6250b30ac458a8a95714b44c9f04d8e..eb56e09ae15f3999478b0e75f601836c92ad175a 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1558,7 +1558,7 @@ static void balloon_onchannelcallback(void *context) break; default: - pr_warn_ratelimited("Unhandled message: type: %d\n", dm_hdr->type); + pr_warn("Unhandled message: type: %d\n", dm_hdr->type); } } diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index de27837e852717a42e98b902295bf2c8c79b628f..88a5df2633fb254cbbf6474eae59899eb7ec0081 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -319,7 +319,6 @@ enum pmbus_fan_mode { percent = 0, rpm }; /* * STATUS_VOUT, STATUS_INPUT */ -#define PB_VOLTAGE_VIN_OFF BIT(3) #define PB_VOLTAGE_UV_FAULT BIT(4) #define PB_VOLTAGE_UV_WARNING BIT(5) #define PB_VOLTAGE_OV_WARNING BIT(6) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 117e3ce9c76ad8a775b4b6f75c0285f98cf1133b..71798fde2ef0c93280698c355f190273b429f05b 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1360,7 +1360,7 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { .reg = PMBUS_VIN_UV_FAULT_LIMIT, .attr = "lcrit", .alarm = "lcrit_alarm", - .sbit = PB_VOLTAGE_UV_FAULT | PB_VOLTAGE_VIN_OFF, + .sbit = PB_VOLTAGE_UV_FAULT, }, { .reg = PMBUS_VIN_OV_WARN_LIMIT, .attr = "max", @@ -2255,14 +2255,10 @@ static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) { struct device *dev = rdev_get_dev(rdev); struct i2c_client *client = to_i2c_client(dev->parent); - struct pmbus_data *data = i2c_get_clientdata(client); u8 page = rdev_get_id(rdev); int ret; - mutex_lock(&data->update_lock); ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION); - mutex_unlock(&data->update_lock); - if (ret < 0) return ret; @@ -2273,17 +2269,11 @@ static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) { struct device *dev = rdev_get_dev(rdev); struct i2c_client *client = to_i2c_client(dev->parent); - struct pmbus_data *data = i2c_get_clientdata(client); u8 page = rdev_get_id(rdev); - int ret; - mutex_lock(&data->update_lock); - ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION, - PB_OPERATION_CONTROL_ON, - enable ? PB_OPERATION_CONTROL_ON : 0); - mutex_unlock(&data->update_lock); - - return ret; + return pmbus_update_byte_data(client, page, PMBUS_OPERATION, + PB_OPERATION_CONTROL_ON, + enable ? PB_OPERATION_CONTROL_ON : 0); } static int pmbus_regulator_enable(struct regulator_dev *rdev) diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index 066b12990fbfb6f97ee7f16beb174ab388595013..6c84780e358e8d12cc21a73deaa4644ae637ec0c 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -424,7 +424,7 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent, if (nowayout) set_bit(WDOG_NO_WAY_OUT, &data->wddev.status); if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) - set_bit(WDOG_HW_RUNNING, &data->wddev.status); + set_bit(WDOG_ACTIVE, &data->wddev.status); /* Since the watchdog uses a downcounter there is no register to read the BIOS set timeout from (if any was set at all) -> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 19dbb794f7c8abd33fc4eb50d851526d33d8b9da..bfcf9e0415c267f8046a4e45e7f63e315e77f12a 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2056,7 +2056,7 @@ static void clear_etmdrvdata(void *info) etmdrvdata[cpu] = NULL; } -static void __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) +static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) { etm_perf_symlink(drvdata->csdev, false); /* @@ -2076,6 +2076,8 @@ static void __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) cpus_read_unlock(); coresight_unregister(drvdata->csdev); + + return 0; } static void __exit etm4_remove_amba(struct amba_device *adev) @@ -2092,7 +2094,7 @@ static int __exit etm4_remove_platform_dev(struct platform_device *pdev) struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev); if (drvdata) - etm4_remove_dev(drvdata); + ret = etm4_remove_dev(drvdata); pm_runtime_disable(&pdev->dev); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index b8dd7ea111c1ebd2082b21cb4d416e45895aabf2..007bad9e7ad81dd729a62fa45afcca967b257b48 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -364,12 +364,8 @@ static ssize_t mode_store(struct device *dev, mode = ETM_MODE_QELEM(config->mode); /* start by clearing QE bits */ config->cfg &= ~(BIT(13) | BIT(14)); - /* - * if supported, Q elements with instruction counts are enabled. - * Always set the low bit for any requested mode. Valid combos are - * 0b00, 0b01 and 0b11. - */ - if (mode && drvdata->q_support) + /* if supported, Q elements with instruction counts are enabled */ + if ((mode & BIT(0)) && (drvdata->q_support & BIT(0))) config->cfg |= BIT(13); /* * if supported, Q elements with and without instruction diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 07eb819072c4fdf44a2a570b08aded0ae83c02e4..ef73a42577cc7b3cedff721df31b6c94f707f31c 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -465,18 +465,18 @@ static int meson_i2c_probe(struct platform_device *pdev) */ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); - /* Disable filtering */ - meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, - REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); - - meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); - ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { clk_disable_unprepare(i2c->clk); return ret; } + /* Disable filtering */ + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, + REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); + + meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); + return 0; } diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 8dabb6ffb1a4f088adc2b507c2ea89ad411cdbbe..2a8568b97c14d5452a532c6aede85b4734611b1d 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -756,6 +756,7 @@ static const struct i2c_adapter_quirks xiic_quirks = { static const struct i2c_adapter xiic_adapter = { .owner = THIS_MODULE, + .name = DRIVER_NAME, .class = I2C_CLASS_DEPRECATED, .algo = &xiic_algorithm, .quirks = &xiic_quirks, @@ -792,8 +793,6 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = pdev->dev.of_node; - snprintf(i2c->adap.name, sizeof(i2c->adap.name), - DRIVER_NAME " %s", pdev->name); mutex_init(&i2c->lock); init_waitqueue_head(&i2c->wait); diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index f7a7405d4350a10718b7948d546ca31fc11dabdb..5365199a31f419b9db442ba3fa555e3a3ed044fc 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -261,7 +261,7 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) err = device_create_file(&pdev->dev, &dev_attr_available_masters); if (err) - goto err_rollback_activation; + goto err_rollback; err = device_create_file(&pdev->dev, &dev_attr_current_master); if (err) @@ -271,9 +271,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) err_rollback_available: device_remove_file(&pdev->dev, &dev_attr_available_masters); -err_rollback_activation: - i2c_demux_deactivate_master(priv); err_rollback: + i2c_demux_deactivate_master(priv); for (j = 0; j < i; j++) { of_node_put(priv->chan[j].parent_np); of_changeset_destroy(&priv->chan[j].chgset); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index e7e280282774089830e0f922d781f8ba3f31d7d1..a7208704d31c90d15b7e40bff45e43ab7dd783ec 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -176,7 +176,6 @@ static const struct mma8452_event_regs trans_ev_regs = { * @enabled_events: event flags enabled and handled by this driver */ struct mma_chip_info { - const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -1304,7 +1303,6 @@ enum { static const struct mma_chip_info mma_chip_info_table[] = { [mma8451] = { - .name = "mma8451", .chip_id = MMA8451_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1329,7 +1327,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8452] = { - .name = "mma8452", .chip_id = MMA8452_DEVICE_ID, .channels = mma8452_channels, .num_channels = ARRAY_SIZE(mma8452_channels), @@ -1346,7 +1343,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8453] = { - .name = "mma8453", .chip_id = MMA8453_DEVICE_ID, .channels = mma8453_channels, .num_channels = ARRAY_SIZE(mma8453_channels), @@ -1363,7 +1359,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8652] = { - .name = "mma8652", .chip_id = MMA8652_DEVICE_ID, .channels = mma8652_channels, .num_channels = ARRAY_SIZE(mma8652_channels), @@ -1373,7 +1368,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [mma8653] = { - .name = "mma8653", .chip_id = MMA8653_DEVICE_ID, .channels = mma8653_channels, .num_channels = ARRAY_SIZE(mma8653_channels), @@ -1388,7 +1382,6 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [fxls8471] = { - .name = "fxls8471", .chip_id = FXLS8471_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1532,6 +1525,13 @@ static int mma8452_probe(struct i2c_client *client, struct mma8452_data *data; struct iio_dev *indio_dev; int ret; + const struct of_device_id *match; + + match = of_match_device(mma8452_dt_ids, &client->dev); + if (!match) { + dev_err(&client->dev, "unknown device model\n"); + return -ENODEV; + } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1540,14 +1540,7 @@ static int mma8452_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); - - data->chip_info = device_get_match_data(&client->dev); - if (!data->chip_info && id) { - data->chip_info = &mma_chip_info_table[id->driver_data]; - } else { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } + data->chip_info = match->data; data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) @@ -1591,11 +1584,11 @@ static int mma8452_probe(struct i2c_client *client, } dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", - data->chip_info->name, data->chip_info->chip_id); + match->compatible, data->chip_info->chip_id); i2c_set_clientdata(client, indio_dev); indio_dev->info = &mma8452_info; - indio_dev->name = data->chip_info->name; + indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; @@ -1821,7 +1814,7 @@ MODULE_DEVICE_TABLE(i2c, mma8452_id); static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", - .of_match_table = mma8452_dt_ids, + .of_match_table = of_match_ptr(mma8452_dt_ids), .pm = &mma8452_pm_ops, }, .probe = mma8452_probe, diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 256177b15c511de57c9e93b31a9e690d09bb7780..c6416ad795ca48ae2a24cd02c8ecd5e8d4fb74e3 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -911,8 +911,6 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, irq, NULL, twl6030_gpadc_irq_handler, IRQF_ONESHOT, "twl6030_gpadc", indio_dev); - if (ret) - return ret; ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); if (ret < 0) { diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 3809f98894a515fd100167dc5c865bd7928a8bd5..e42ea2b1707db9eb4628387a1db3a2b6fbbdebc7 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -38,7 +38,7 @@ static int rescale_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct rescale *rescale = iio_priv(indio_dev); - s64 tmp; + unsigned long long tmp; int ret; switch (mask) { @@ -59,10 +59,10 @@ static int rescale_read_raw(struct iio_dev *indio_dev, *val2 = rescale->denominator; return IIO_VAL_FRACTIONAL; case IIO_VAL_FRACTIONAL_LOG2: - tmp = (s64)*val * 1000000000LL; - tmp = div_s64(tmp, rescale->denominator); + tmp = *val * 1000000000LL; + do_div(tmp, rescale->denominator); tmp *= rescale->numerator; - tmp = div_s64(tmp, 1000000000LL); + do_div(tmp, 1000000000LL); *val = tmp; return ret; default: diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 8c3faa7972842db38a55531c18cf626bfb4119fa..ede99e0d53714d4d7d9dce825c8551598d3d7f5a 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -561,50 +561,28 @@ EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) { - int scale_type, scale_val, scale_val2; - int offset_type, offset_val, offset_val2; + int scale_type, scale_val, scale_val2, offset; s64 raw64 = raw; + int ret; - offset_type = iio_channel_read(chan, &offset_val, &offset_val2, - IIO_CHAN_INFO_OFFSET); - if (offset_type >= 0) { - switch (offset_type) { - case IIO_VAL_INT: - break; - case IIO_VAL_INT_PLUS_MICRO: - case IIO_VAL_INT_PLUS_NANO: - /* - * Both IIO_VAL_INT_PLUS_MICRO and IIO_VAL_INT_PLUS_NANO - * implicitely truncate the offset to it's integer form. - */ - break; - case IIO_VAL_FRACTIONAL: - offset_val /= offset_val2; - break; - case IIO_VAL_FRACTIONAL_LOG2: - offset_val >>= offset_val2; - break; - default: - return -EINVAL; - } - - raw64 += offset_val; - } + ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); + if (ret >= 0) + raw64 += offset; scale_type = iio_channel_read(chan, &scale_val, &scale_val2, IIO_CHAN_INFO_SCALE); if (scale_type < 0) { /* - * If no channel scaling is available apply consumer scale to - * raw value and return. + * Just pass raw values as processed if no scaling is + * available. */ - *processed = raw * scale; + *processed = raw; return 0; } switch (scale_type) { case IIO_VAL_INT: - *processed = raw64 * scale_val * scale; + *processed = raw64 * scale_val; break; case IIO_VAL_INT_PLUS_MICRO: if (scale_val2 < 0) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 3c40aa50cd60c17064c4187b1a92fe307c0ebd1c..fbb0efbe25f84fee2f3e6defcb727fd48201c43e 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2635,7 +2635,7 @@ int rdma_set_ack_timeout(struct rdma_cm_id *id, u8 timeout) { struct rdma_id_private *id_priv; - if (id->qp_type != IB_QPT_RC && id->qp_type != IB_QPT_XRC_INI) + if (id->qp_type != IB_QPT_RC) return -EINVAL; id_priv = container_of(id, struct rdma_id_private, id); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 597e889ba83126ff337125782aeac8ea038ac8a4..3d895cc41c3ad93cf2df789035e01304d2039e47 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2078,7 +2078,6 @@ struct ib_mr *ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return mr; mr->device = pd->device; - mr->type = IB_MR_TYPE_USER; mr->pd = pd; mr->dm = NULL; atomic_inc(&pd->usecnt); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 5f3edd255ca3cab845b8cc0019b86132c37a0b29..3591923abebb9b172396136f186d3b053711ccbb 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1439,7 +1439,8 @@ static int query_port(struct rvt_dev_info *rdi, u8 port_num, 4096 : hfi1_max_mtu), IB_MTU_4096); props->active_mtu = !valid_ib_mtu(ppd->ibmtu) ? props->max_mtu : mtu_to_enum(ppd->ibmtu, IB_MTU_4096); - props->phys_mtu = hfi1_max_mtu; + props->phys_mtu = HFI1_CAP_IS_KSET(AIP) ? hfi1_max_mtu : + ib_mtu_enum_to_int(props->max_mtu); return 0; } diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 2f053f48f1bebcb0dba263e5a5df20501cc83cd8..343e6709d9fc3878e994b2a4962c619b821a78e5 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -1792,10 +1792,8 @@ subscribe_event_xa_alloc(struct mlx5_devx_event_table *devx_event_table, key_level2, obj_event, GFP_KERNEL); - if (err) { - kfree(obj_event); + if (err) return err; - } INIT_LIST_HEAD(&obj_event->obj_sub_list); } diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 6cd0cbd4fc9f6169e65f7d3dad69a6e35f860954..19346693c1da4a3b6068b6aeb3de2feda3227e89 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -575,8 +575,6 @@ struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, ent = &cache->ent[entry]; spin_lock_irq(&ent->lock); if (list_empty(&ent->head)) { - queue_adjust_cache_locked(ent); - ent->miss++; spin_unlock_irq(&ent->lock); mr = create_cache_mr(ent); if (IS_ERR(mr)) diff --git a/drivers/input/input.c b/drivers/input/input.c index 3cfd2c18eebd9d6a546c0d259204dc559c8460a1..ff9dc37eff3454662d1fdede756fe74cf06444e0 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2179,6 +2179,12 @@ int input_register_device(struct input_dev *dev) /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); + /* Buttonpads should not map BTN_RIGHT and/or BTN_MIDDLE. */ + if (test_bit(INPUT_PROP_BUTTONPAD, dev->propbit)) { + __clear_bit(BTN_RIGHT, dev->keybit); + __clear_bit(BTN_MIDDLE, dev->keybit); + } + /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 8afeefcea67bb1ad498569a2c8b8a3b78f5285e5..e08b0ef078e8198474120972a656b09a0150ee09 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1801,13 +1801,15 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); - err = usb_find_common_endpoints(intf->cur_altsetting, - NULL, NULL, &endpoint, NULL); - if (err) { + /* Verify that a device really has an endpoint */ + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, - "interface has no int in endpoints, but must have minimum 1\n"); + "interface has %d endpoints, but must have minimum 1\n", + intf->cur_altsetting->desc.bNumEndpoints); + err = -EINVAL; goto fail3; } + endpoint = &intf->cur_altsetting->endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives * input. diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index 17b10b81c71319947ff95542cbdc794fb68a1112..6df6f07f1ac66a036737e1957a5ed8007cd7f2bd 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -135,7 +135,7 @@ struct point_coord { struct touch_event { __le16 status; - u8 finger_mask; + u8 finger_cnt; u8 time_stamp; struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM]; }; @@ -311,32 +311,11 @@ static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541) static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot, const struct point_coord *p) { - u16 x, y; - - if (unlikely(!(p->sub_status & - (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) { - dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n", - p->sub_status); - return; - } - - x = le16_to_cpu(p->x); - y = le16_to_cpu(p->y); - input_mt_slot(bt541->input_dev, slot); - if (input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, - !(p->sub_status & SUB_BIT_UP))) { - touchscreen_report_pos(bt541->input_dev, - &bt541->prop, x, y, true); - input_report_abs(bt541->input_dev, - ABS_MT_TOUCH_MAJOR, p->width); - dev_dbg(&bt541->client->dev, "finger %d %s (%u, %u)\n", - slot, p->sub_status & SUB_BIT_DOWN ? "down" : "move", - x, y); - } else { - dev_dbg(&bt541->client->dev, "finger %d up (%u, %u)\n", - slot, x, y); - } + input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true); + touchscreen_report_pos(bt541->input_dev, &bt541->prop, + le16_to_cpu(p->x), le16_to_cpu(p->y), true); + input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width); } static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) @@ -344,7 +323,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) struct bt541_ts_data *bt541 = bt541_handler; struct i2c_client *client = bt541->client; struct touch_event touch_event; - unsigned long finger_mask; int error; int i; @@ -357,14 +335,10 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) goto out; } - finger_mask = touch_event.finger_mask; - for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) { - const struct point_coord *p = &touch_event.point_coord[i]; - - /* Only process contacts that are actually reported */ - if (p->sub_status & SUB_BIT_EXIST) - zinitix_report_finger(bt541, i, p); - } + for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) + if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST) + zinitix_report_finger(bt541, i, + &touch_event.point_coord[i]); input_mt_sync_frame(bt541->input_dev); input_sync(bt541->input_dev); diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index d9068e8f2db4fcc7484ed6fe8d4b56589b6f7159..d71f10257f15929f6337b9cc13cc147998c59df5 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -1012,9 +1012,7 @@ static int ipmmu_probe(struct platform_device *pdev) bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(&pdev->dev); memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs); - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); - if (ret) - return ret; + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); /* Map I/O memory and request IRQ. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index e903c44edb64ab474d35097daed4ebcbd44ba913..21cb31ff2bbf25777d34c6b12ed86c6458724461 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -94,7 +94,6 @@ static int __init nvic_of_init(struct device_node *node, if (!nvic_irq_domain) { pr_warn("Failed to allocate irq domain\n"); - iounmap(nvic_base); return -ENOMEM; } @@ -104,7 +103,6 @@ static int __init nvic_of_init(struct device_node *node, if (ret) { pr_warn("Failed to allocate irq chips\n"); irq_domain_remove(nvic_irq_domain); - iounmap(nvic_base); return ret; } diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index 1530cce617a4142e9f7aa1a94bdeb71dba168603..afdf0d6600ba33c90e5a9a6d356c4f7c7ebc1820 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -88,18 +88,17 @@ static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d, static void pdc_enable_intr(struct irq_data *d, bool on) { int pin_out = d->hwirq; - unsigned long flags; u32 index, mask; u32 enable; index = pin_out / 32; mask = pin_out % 32; - raw_spin_lock_irqsave(&pdc_lock, flags); + raw_spin_lock(&pdc_lock); enable = pdc_reg_read(IRQ_ENABLE_BANK, index); enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); pdc_reg_write(IRQ_ENABLE_BANK, index, enable); - raw_spin_unlock_irqrestore(&pdc_lock, flags); + raw_spin_unlock(&pdc_lock); } static void qcom_pdc_gic_disable(struct irq_data *d) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index c5663398c6b7d7ec49b0314d2f564e23d62dd900..2543c7b6948b6d9ce701eccdd0e6430ef629a869 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #define IMX_MU_xSR_GIPn(x) BIT(28 + (3 - (x))) @@ -67,7 +66,6 @@ struct imx_mu_priv { const struct imx_mu_dcfg *dcfg; struct clk *clk; int irq; - bool suspend; u32 xcr; @@ -279,9 +277,6 @@ static irqreturn_t imx_mu_isr(int irq, void *p) return IRQ_NONE; } - if (priv->suspend) - pm_system_wakeup(); - return IRQ_HANDLED; } @@ -331,8 +326,6 @@ static int imx_mu_startup(struct mbox_chan *chan) break; } - priv->suspend = true; - return 0; } @@ -550,8 +543,6 @@ static int imx_mu_probe(struct platform_device *pdev) clk_disable_unprepare(priv->clk); - priv->suspend = false; - return 0; disable_runtime_pm: diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 4895d8074002220ef7baa5dc1c0e6bd628cdf6db..e07091d71986a5f1ca30dfdfd38c785356e6647b 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -410,11 +410,6 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, value = tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX); if ((value & HSP_SM_SHRD_MBOX_FULL) == 0) { mbox_chan_txdone(chan, 0); - - /* Wait until channel is empty */ - if (chan->active_req != NULL) - continue; - return 0; } diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 418914373a51319364ffd26a988b3f3d492ab9d1..fe6dce125aba226e5f7c05cad39c78b38829389d 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -2060,11 +2060,9 @@ int bch_btree_check(struct cache_set *c) } } - /* - * Must wait for all threads to stop. - */ wait_event_interruptible(check_state->wait, - atomic_read(&check_state->started) == 0); + atomic_read(&check_state->started) == 0 || + test_bit(CACHE_SET_IO_DISABLE, &c->flags)); for (i = 0; i < check_state->total_threads; i++) { if (check_state->infos[i].result) { diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 952253f24175a80cdcfc83e68f883474504a2660..3c74996978dadef2642c3ac716abb4c46abda3c9 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -952,11 +952,9 @@ void bch_sectors_dirty_init(struct bcache_device *d) } } - /* - * Must wait for all threads to stop. - */ wait_event_interruptible(state->wait, - atomic_read(&state->started) == 0); + atomic_read(&state->started) == 0 || + test_bit(CACHE_SET_IO_DISABLE, &c->flags)); out: kfree(state); diff --git a/drivers/md/dm-bow.c b/drivers/md/dm-bow.c index e666ca01d2200df5e2dbf7494ab56909ff355bf1..2e95d614969202038dbca09fccbc1f8be4e70cbb 100644 --- a/drivers/md/dm-bow.c +++ b/drivers/md/dm-bow.c @@ -236,7 +236,6 @@ static void set_type(struct bow_context *bc, struct bow_range **br, int type) (*br)->type = type; - mutex_lock(&bc->ranges_lock); if (next->type == type) { if (type == TRIMMED) list_del(&next->trimmed_list); @@ -250,7 +249,6 @@ static void set_type(struct bow_context *bc, struct bow_range **br, int type) rb_erase(&(*br)->node, &bc->ranges); kfree(*br); } - mutex_unlock(&bc->ranges_lock); *br = NULL; } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index b9677f701b6a11a0011683dc01f0721aa8f07285..2aa4acd33af3903506824331181179f856502b97 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2561,7 +2561,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string static int get_key_size(char **key_string) { - return (*key_string[0] == ':') ? -EINVAL : (int)(strlen(*key_string) >> 1); + return (*key_string[0] == ':') ? -EINVAL : strlen(*key_string) >> 1; } #endif /* CONFIG_KEYS */ diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index f7471a2642dd4162b2c29e4f416166b45eb000f5..4c7da1c4e6cb9e50c2b828e41a0716c3ad12a4c1 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -2354,11 +2354,9 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start, dm_integrity_io_error(ic, "invalid sector in journal", -EIO); sec &= ~(sector_t)(ic->sectors_per_block - 1); } - if (unlikely(sec >= ic->provided_data_sectors)) { - journal_entry_set_unused(je); - continue; - } } + if (unlikely(sec >= ic->provided_data_sectors)) + continue; get_area_and_offset(ic, sec, &area, &offset); restore_last_bytes(ic, access_journal_data(ic, i, j), je); for (k = j + 1; k < ic->journal_section_entries; k++) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 10eb0544f1cba17d8fb674e4a305587ef245119c..9fd176e225aff4f192e3b4d5d8323b324ce21fa2 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -608,18 +608,17 @@ static void start_io_acct(struct dm_io *io) false, 0, &io->stats_aux); } -static void end_io_acct(struct dm_io *io) +static void end_io_acct(struct mapped_device *md, struct bio *bio, + unsigned long start_time, struct dm_stats_aux *stats_aux) { - struct mapped_device *md = io->md; - struct bio *bio = io->orig_bio; - unsigned long duration = jiffies - io->start_time; + unsigned long duration = jiffies - start_time; - bio_end_io_acct(bio, io->start_time); + bio_end_io_acct(bio, start_time); if (unlikely(dm_stats_used(&md->stats))) dm_stats_account_io(&md->stats, bio_data_dir(bio), bio->bi_iter.bi_sector, bio_sectors(bio), - true, duration, &io->stats_aux); + true, duration, stats_aux); /* nudge anyone waiting on suspend queue */ if (unlikely(wq_has_sleeper(&md->wait))) @@ -904,6 +903,8 @@ static void dec_pending(struct dm_io *io, blk_status_t error) blk_status_t io_error; struct bio *bio; struct mapped_device *md = io->md; + unsigned long start_time = 0; + struct dm_stats_aux stats_aux; /* Push-back supersedes any I/O errors */ if (unlikely(error)) { @@ -930,8 +931,10 @@ static void dec_pending(struct dm_io *io, blk_status_t error) io_error = io->status; bio = io->orig_bio; - end_io_acct(io); + start_time = io->start_time; + stats_aux = io->stats_aux; free_io(md, io); + end_io_acct(md, bio, start_time, &stats_aux); if (io_error == BLK_STS_DM_REQUEUE) return; diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 9f5713b76794d686c17bff3b7d0a3dedc7d10505..ab7883cff8b2236064f6d8870d398f8eabc1407f 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -555,7 +555,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_ buffer[3] = 0; buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); - if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) { + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); return; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 8cf1704308bf5aaef736debb1a45dad5d930445a..d1f58795794fd0a2c2278c1692cdfc7ed01e5f81 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2454,7 +2454,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, buffer[i + 3] = infoframe_read(sd, adv76xx_cri[index].payload_addr + i); - if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) { + if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, adv76xx_cri[index].desc); return -ENOENT; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index a870117feb44c550b65c02c8b7b4b1d8e5afeb2b..f7d2b6cd3008b3e4e9bf0e46de05b581cd779aea 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2574,7 +2574,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_ for (i = 0; i < len; i++) buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i); - if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) { + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); return; } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 1f0e4b913a053485493a90bef6b049fbefc46a42..35a51e9b539da194c766e72b7156225db043f9a2 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3898,7 +3898,7 @@ static int bttv_register_video(struct bttv *btv) /* video */ vdev_init(btv, &btv->video_dev, &bttv_video_template, "video"); - btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (btv->tuner_type != TUNER_ABSENT) btv->video_dev.device_caps |= V4L2_CAP_TUNER; @@ -3919,7 +3919,7 @@ static int bttv_register_video(struct bttv *btv) /* vbi */ vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi"); btv->vbi_dev.device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + V4L2_CAP_STREAMING | V4L2_CAP_TUNER; if (btv->tuner_type != TUNER_ABSENT) btv->vbi_dev.device_caps |= V4L2_CAP_TUNER; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 10d2971ef0624ff2b87119567d7a099565245b81..a57c991b165b1ab84ddcd4edf79cd68dd62c8ac0 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -162,9 +162,6 @@ int cx8802_start_dma(struct cx8802_dev *dev, cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); q->count = 0; - /* clear interrupt status register */ - cx_write(MO_TS_INTSTAT, 0x1f1111); - /* enable irqs */ dprintk(1, "setting the interrupt mask\n"); cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index 00caf60ff98903f4fcf9c0209768225ee883d565..e5efe525ad7bf91dc726c78581d91a5ddce9a75e 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -332,6 +332,7 @@ struct ivtv_stream { struct ivtv *itv; /* for ease of use */ const char *name; /* name of the stream */ int type; /* stream type */ + u32 caps; /* V4L2 capabilities */ struct v4l2_fh *fh; /* pointer to the streaming filehandle */ spinlock_t qlock; /* locks access to the queues */ diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index a9d69b253516b610d9b772b7dd56d67ba79478b2..35dccb31174c1e82d77ba72d6a58b7b9af7b34e8 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -443,7 +443,7 @@ static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; struct v4l2_window *winfmt = &fmt->fmt.win; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; if (!itv->osd_video_pbase) return -EINVAL; @@ -554,7 +554,7 @@ static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2 u32 chromakey = fmt->fmt.win.chromakey; u8 global_alpha = fmt->fmt.win.global_alpha; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; if (!itv->osd_video_pbase) return -EINVAL; @@ -1388,7 +1388,7 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) 0, }; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; @@ -1455,7 +1455,7 @@ static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffe struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; struct yuv_playback_info *yi = &itv->yuv_info; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; @@ -1475,7 +1475,7 @@ static int ivtv_overlay(struct file *file, void *fh, unsigned int on) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; - if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; if (!itv->osd_video_pbase) return -ENOTTY; diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index f9de5d1605fe37aea734d0e1f24963ea099cab11..f04ee84bab5fd38690914860ea6c7db7b51ae318 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -176,7 +176,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->itv = itv; s->type = type; s->name = ivtv_stream_info[type].name; - s->vdev.device_caps = ivtv_stream_info[type].v4l2_caps; + s->caps = ivtv_stream_info[type].v4l2_caps; if (ivtv_stream_info[type].pio) s->dma = PCI_DMA_NONE; @@ -299,9 +299,12 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) if (s_mpg->vdev.v4l2_dev) num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset; } - if (itv->osd_video_pbase && (type == IVTV_DEC_STREAM_TYPE_YUV || - type == IVTV_DEC_STREAM_TYPE_MPG)) { - s->vdev.device_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + s->vdev.device_caps = s->caps; + if (itv->osd_video_pbase) { + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; } video_set_drvdata(&s->vdev, s); diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index d3cde05a6ebab80027cb5722c9d3eccb836022a6..7a1fb067b0e09b81e6453abd006edcc623e05978 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1214,14 +1214,16 @@ static int alsa_device_exit(struct saa7134_dev *dev) static int saa7134_alsa_init(void) { - struct saa7134_dev *dev; + struct saa7134_dev *dev = NULL; + struct list_head *list; saa7134_dmasound_init = alsa_device_init; saa7134_dmasound_exit = alsa_device_exit; pr_info("saa7134 ALSA driver for DMA sound loaded\n"); - list_for_each_entry(dev, &saa7134_devlist, devlist) { + list_for_each(list,&saa7134_devlist) { + dev = list_entry(list, struct saa7134_dev, devlist); if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) pr_info("%s/alsa: %s doesn't support digital audio\n", dev->name, saa7134_boards[dev->board].name); @@ -1229,7 +1231,7 @@ static int saa7134_alsa_init(void) alsa_device_init(dev); } - if (list_empty(&saa7134_devlist)) + if (dev == NULL) pr_info("saa7134 ALSA: no saa7134 cards found\n"); return 0; diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 757a58829a512a21602f7902ee997c631a5e19c5..debc7509c173c41e218bbebbebeeeb9f4fc7ca1e 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -151,7 +151,7 @@ #define VE_SRC_TB_EDGE_DET_BOT GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF) #define VE_MODE_DETECT_STATUS 0x098 -#define VE_MODE_DETECT_H_PERIOD GENMASK(11, 0) +#define VE_MODE_DETECT_H_PIXELS GENMASK(11, 0) #define VE_MODE_DETECT_V_LINES_SHF 16 #define VE_MODE_DETECT_V_LINES GENMASK(27, VE_MODE_DETECT_V_LINES_SHF) #define VE_MODE_DETECT_STATUS_VSYNC BIT(28) @@ -162,8 +162,6 @@ #define VE_SYNC_STATUS_VSYNC_SHF 16 #define VE_SYNC_STATUS_VSYNC GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF) -#define VE_H_TOTAL_PIXELS 0x0A0 - #define VE_INTERRUPT_CTRL 0x304 #define VE_INTERRUPT_STATUS 0x308 #define VE_INTERRUPT_MODE_DETECT_WD BIT(0) @@ -767,7 +765,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) u32 src_lr_edge; u32 src_tb_edge; u32 sync; - u32 htotal; struct v4l2_bt_timings *det = &video->detected_timings; det->width = MIN_WIDTH; @@ -812,7 +809,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) src_tb_edge = aspeed_video_read(video, VE_SRC_TB_EDGE_DET); mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS); sync = aspeed_video_read(video, VE_SYNC_STATUS); - htotal = aspeed_video_read(video, VE_H_TOTAL_PIXELS); video->frame_bottom = (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >> VE_SRC_TB_EDGE_DET_BOT_SHF; @@ -829,7 +825,8 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) VE_SRC_LR_EDGE_DET_RT_SHF; video->frame_left = src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT; det->hfrontporch = video->frame_left; - det->hbackporch = htotal - video->frame_right; + det->hbackporch = (mds & VE_MODE_DETECT_H_PIXELS) - + video->frame_right; det->hsync = sync & VE_SYNC_STATUS_HSYNC; if (video->frame_left > video->frame_right) continue; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 2333079a83c71330412f64e930e257a1f3132cc1..1eed69d29149f34c43fd155ff957c157623deac4 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -408,7 +408,6 @@ static struct vdoa_data *coda_get_vdoa_data(void) if (!vdoa_data) vdoa_data = ERR_PTR(-EPROBE_DEFER); - put_device(&vdoa_pdev->dev); out: of_node_put(vdoa_node); diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index ee610daf90a3c9a93805cd7be44d4996d87e6cdf..5e67994e62ccac50a0205f06d520e3be469174a6 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -428,7 +428,6 @@ static int vpif_probe(struct platform_device *pdev) static struct resource *res, *res_irq; struct platform_device *pdev_capture, *pdev_display; struct device_node *endpoint = NULL; - int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); vpif_base = devm_ioremap_resource(&pdev->dev, res); @@ -459,8 +458,8 @@ static int vpif_probe(struct platform_device *pdev) res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res_irq) { dev_warn(&pdev->dev, "Missing IRQ resource.\n"); - ret = -EINVAL; - goto err_put_rpm; + pm_runtime_put(&pdev->dev); + return -EINVAL; } pdev_capture = devm_kzalloc(&pdev->dev, sizeof(*pdev_capture), @@ -494,17 +493,10 @@ static int vpif_probe(struct platform_device *pdev) } return 0; - -err_put_rpm: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - return ret; } static int vpif_remove(struct platform_device *pdev) { - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c index cfc7ebed8fb7ab7a828ff1357b5cc5fa04afbe2a..cd27f637dbe7c8690baf3b7d0cd9790839118d61 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c @@ -102,8 +102,6 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev, vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id); fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); - if (!fw) - return ERR_PTR(-ENOMEM); fw->type = VPU; fw->ops = &mtk_vcodec_vpu_msg; fw->pdev = fw_pdev; diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index a50701cfbbd7b37c5462347c9e74926091f1fdee..c6cd2e6d8e654d8cb5182f1bb7fc3436d7cdecf5 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -48,29 +48,11 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier) return 0; } -static void delay_until(ktime_t until) -{ - /* - * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on - * m68k ndelay(s64) does not compile; so use s32 rather than s64. - */ - s32 delta; - - while (true) { - delta = ktime_us_delta(until, ktime_get()); - if (delta <= 0) - return; - - /* udelay more than 1ms may not work */ - delta = min(delta, 1000); - udelay(delta); - } -} - static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, uint count) { ktime_t edge; + s32 delta; int i; local_irq_disable(); @@ -81,7 +63,9 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, gpiod_set_value(gpio_ir->gpio, !(i % 2)); edge = ktime_add_us(edge, txbuf[i]); - delay_until(edge); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 0) + udelay(delta); } gpiod_set_value(gpio_ir->gpio, 0); @@ -113,7 +97,9 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf, if (i % 2) { // space edge = ktime_add_us(edge, txbuf[i]); - delay_until(edge); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 0) + udelay(delta); } else { // pulse ktime_t last = ktime_add_us(edge, txbuf[i]); diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 7f394277478b32ae0c461dfc3949249194775b90..1aa7989e756ccd967ca376ce0201911f3f5c4708 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -429,7 +429,7 @@ static int irtoy_probe(struct usb_interface *intf, err = usb_submit_urb(irtoy->urb_in, GFP_KERNEL); if (err != 0) { dev_err(irtoy->dev, "fail to submit in urb: %d\n", err); - goto free_rcdev; + return err; } err = irtoy_setup(irtoy); diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c b/drivers/media/test-drivers/vidtv/vidtv_s302m.c index 4676083cee3b8aa58f01845c9839d91505d24850..d79b65854627cc18c60c5172430c40369e687c68 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_s302m.c +++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c @@ -455,9 +455,6 @@ struct vidtv_encoder e->name = kstrdup(args.name, GFP_KERNEL); e->encoder_buf = vzalloc(VIDTV_S302M_BUF_SZ); - if (!e->encoder_buf) - goto out_kfree_e; - e->encoder_buf_sz = VIDTV_S302M_BUF_SZ; e->encoder_buf_offset = 0; @@ -470,8 +467,10 @@ struct vidtv_encoder e->is_video_encoder = false; ctx = kzalloc(priv_sz, GFP_KERNEL); - if (!ctx) - goto out_kfree_buf; + if (!ctx) { + kfree(e); + return NULL; + } e->ctx = ctx; ctx->last_duration = 0; @@ -499,14 +498,6 @@ struct vidtv_encoder e->next = NULL; return e; - -out_kfree_buf: - kfree(e->encoder_buf); - -out_kfree_e: - kfree(e->name); - kfree(e); - return NULL; } void vidtv_s302m_encoder_destroy(struct vidtv_encoder *e) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 26408a972b443e7d90751aa3ad8beb9362b51be1..87e375562dbb2b1df019c6ea305a222a298b01df 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3881,8 +3881,6 @@ static int em28xx_usb_probe(struct usb_interface *intf, goto err_free; } - kref_init(&dev->ref); - dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; @@ -3983,8 +3981,6 @@ static int em28xx_usb_probe(struct usb_interface *intf, } if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) { - kref_init(&dev->dev_next->ref); - dev->dev_next->ts = SECONDARY_TS; dev->dev_next->alt = -1; dev->dev_next->is_audio_only = has_vendor_audio && @@ -4039,8 +4035,12 @@ static int em28xx_usb_probe(struct usb_interface *intf, em28xx_write_reg(dev, 0x0b, 0x82); mdelay(100); } + + kref_init(&dev->dev_next->ref); } + kref_init(&dev->ref); + request_modules(dev); /* @@ -4095,8 +4095,11 @@ static void em28xx_usb_disconnect(struct usb_interface *intf) em28xx_close_extension(dev); - if (dev->dev_next) + if (dev->dev_next) { + em28xx_close_extension(dev->dev_next); em28xx_release_resources(dev->dev_next); + } + em28xx_release_resources(dev); if (dev->dev_next) { diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index 2e5913bccb38f696cadd93ea5bd1c7b17862a7b1..b9e45124673b6b72955ceb0003658e183e0ed5ee 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -504,7 +504,6 @@ static int s2250_probe(struct i2c_client *client, u8 *data; struct go7007 *go = i2c_get_adapdata(adapter); struct go7007_usb *usb = go->hpi_context; - int err = -EIO; audio = i2c_new_dummy_device(adapter, TLV320_ADDRESS >> 1); if (IS_ERR(audio)) @@ -533,8 +532,11 @@ static int s2250_probe(struct i2c_client *client, V4L2_CID_HUE, -512, 511, 1, 0); sd->ctrl_handler = &state->hdl; if (state->hdl.error) { - err = state->hdl.error; - goto fail; + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; } state->std = V4L2_STD_NTSC; @@ -598,7 +600,7 @@ fail: i2c_unregister_device(audio); v4l2_ctrl_handler_free(&state->hdl); kfree(state); - return err; + return -EIO; } static int s2250_remove(struct i2c_client *client) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 60e57e0f192725a8dae8500b911c8b2426dd94ae..563128d117317f40eef5661aed370616e1ed026d 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -308,6 +308,7 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev) dev->status = STATUS_STREAMING; + INIT_WORK(&dev->worker, hdpvr_transmit_buffers); schedule_work(&dev->worker); v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, @@ -1164,9 +1165,6 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; int res; - // initialize dev->worker - INIT_WORK(&dev->worker, hdpvr_transmit_buffers); - dev->cur_std = V4L2_STD_525_60; dev->width = 720; dev->height = 480; diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index ce717502ea4c393096646c92b25e380e86d9d4df..4e1698f7881876010ff05f18b39610d863fccaa6 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -403,7 +403,7 @@ static void stk1160_disconnect(struct usb_interface *interface) /* Here is the only place where isoc get released */ stk1160_uninit_isoc(dev); - stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR); + stk1160_clear_queue(dev); video_unregister_device(&dev->vdev); v4l2_device_disconnect(&dev->v4l2_dev); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 1aa953469402f50590a3b92590ed83871d88c140..6a4eb616d5160ec822acace9122bef200827792d 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -258,7 +258,7 @@ out_uninit: stk1160_uninit_isoc(dev); out_stop_hw: usb_set_interface(dev->udev, 0, 0); - stk1160_clear_queue(dev, VB2_BUF_STATE_QUEUED); + stk1160_clear_queue(dev); mutex_unlock(&dev->v4l_lock); @@ -306,7 +306,7 @@ static int stk1160_stop_streaming(struct stk1160 *dev) stk1160_stop_hw(dev); - stk1160_clear_queue(dev, VB2_BUF_STATE_ERROR); + stk1160_clear_queue(dev); stk1160_dbg("streaming stopped\n"); @@ -745,7 +745,7 @@ static const struct video_device v4l_template = { /********************************************************************/ /* Must be called with both v4l_lock and vb_queue_lock hold */ -void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state) +void stk1160_clear_queue(struct stk1160 *dev) { struct stk1160_buffer *buf; unsigned long flags; @@ -756,7 +756,7 @@ void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state) buf = list_first_entry(&dev->avail_bufs, struct stk1160_buffer, list); list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, vb2_state); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); stk1160_dbg("buffer [%p/%d] aborted\n", buf, buf->vb.vb2_buf.index); } @@ -766,7 +766,7 @@ void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state) buf = dev->isoc_ctl.buf; dev->isoc_ctl.buf = NULL; - vb2_buffer_done(&buf->vb.vb2_buf, vb2_state); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); stk1160_dbg("buffer [%p/%d] aborted\n", buf, buf->vb.vb2_buf.index); } diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index a70963ce875337f3929e45582f800dc1251d6848..a31ea1c80f25569a9312e228601c3ac58665bd36 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -166,7 +166,7 @@ struct regval { int stk1160_vb2_setup(struct stk1160 *dev); int stk1160_video_register(struct stk1160 *dev); void stk1160_video_unregister(struct stk1160 *dev); -void stk1160_clear_queue(struct stk1160 *dev, enum vb2_buffer_state vb2_state); +void stk1160_clear_queue(struct stk1160 *dev); /* Provided by stk1160-video.c */ int stk1160_alloc_isoc(struct stk1160 *dev); diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 5a059be3516c9f2c1082c05b5ebb7fef54204fe6..ddb1879f07d3f7a9b657307719ca6bd05c9bdd92 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -1403,7 +1403,7 @@ static struct emif_data *__init_or_module get_device_details( temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL); - if (!emif || !temp || !dev_info) { + if (!emif || !pd || !dev_info) { dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__); goto error; } @@ -1495,7 +1495,7 @@ static int __init_or_module emif_probe(struct platform_device *pdev) { struct emif_data *emif; struct resource *res; - int irq, ret; + int irq; if (pdev->dev.of_node) emif = of_get_memory_device_details(pdev->dev.of_node, &pdev->dev); @@ -1526,9 +1526,7 @@ static int __init_or_module emif_probe(struct platform_device *pdev) emif_onetime_settings(emif); emif_debugfs_init(emif); disable_and_clear_all_interrupts(emif); - ret = setup_interrupts(emif, irq); - if (ret) - goto error; + setup_interrupts(emif, irq); /* One-time actions taken on probing the first device */ if (!emif1) { diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 14e4bbe6a9da3d007bdf44ad65ea3f4b44e343ad..a6bd2134cea2ae8c8a2720347b8523965e8e8cd4 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -914,14 +914,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); if (ret < 0) - goto out_unmap; + goto out; } if (mem_sdio && (irq >= 0)) { ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_mmc, 1, mem_sdio, irq, NULL); if (ret < 0) - goto out_unmap; + goto out; } ret = 0; @@ -935,12 +935,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ret = mfd_add_devices(&pdev->dev, 0, asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); } - return ret; -out_unmap: - if (asic->tmio_cnf) - iounmap(asic->tmio_cnf); -out: + out: return ret; } diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index e281a9202f110f3c5b98ba3cbf304bb12115e56e..1abe7432aad82a308d6b3d8f4c977e9a91964edd 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -323,10 +323,8 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, adc1 |= MC13783_ADC1_ATOX; dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__); - ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, + mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, mc13xxx_handler_adcdone, __func__, &adcdone_data); - if (ret) - goto out; mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0); mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1); diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index 3f514d77a843f3c5bb13934343945dde101628c0..de6d44a158bbae69f22ed2deed3000928f7cb6fa 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -266,7 +266,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, if (!priv) return -ENOMEM; - ret = ida_alloc(&alcor_pci_idr, GFP_KERNEL); + ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL); if (ret < 0) return ret; priv->id = ret; @@ -280,8 +280,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI); if (ret) { dev_err(&pdev->dev, "Cannot request region\n"); - ret = -ENOMEM; - goto error_free_ida; + return -ENOMEM; } if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { @@ -325,8 +324,6 @@ static int alcor_pci_probe(struct pci_dev *pdev, error_release_regions: pci_release_regions(pdev); -error_free_ida: - ida_free(&alcor_pci_idr, priv->id); return ret; } @@ -340,7 +337,7 @@ static void alcor_pci_remove(struct pci_dev *pdev) mfd_remove_devices(&pdev->dev); - ida_free(&alcor_pci_idr, priv->id); + ida_simple_remove(&alcor_pci_idr, priv->id); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 9716b0728b306aeac90d9f50fb3e25ed28281a53..912ddfa360b1375e79d8b6d37e69bda169485ad5 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -859,8 +859,6 @@ static ssize_t hl_set_power_state(struct file *f, const char __user *buf, pci_set_power_state(hdev->pdev, PCI_D0); pci_restore_state(hdev->pdev); rc = pci_enable_device(hdev->pdev); - if (rc < 0) - return rc; } else if (value == 2) { pci_save_state(hdev->pdev); pci_disable_device(hdev->pdev); diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 3e4d894719380865d95c7c9abe963552a53afb02..49489153cd1624bad474bd38e521f743b7910a27 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1060,10 +1060,10 @@ static int kgdbts_option_setup(char *opt) { if (strlen(opt) >= MAX_CONFIG_LEN) { printk(KERN_ERR "kgdbts: config string too long\n"); - return 1; + return -ENOSPC; } strcpy(config, opt); - return 1; + return 0; } __setup("kgdbts=", kgdbts_option_setup); diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index d81d75a20b8f211f6fd312b4282d086a10cecc67..67bb6a25fd0a020c55c310fcd171b1fc566982f9 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -107,7 +107,6 @@ #define MEI_DEV_ID_ADP_S 0x7AE8 /* Alder Lake Point S */ #define MEI_DEV_ID_ADP_LP 0x7A60 /* Alder Lake Point LP */ #define MEI_DEV_ID_ADP_P 0x51E0 /* Alder Lake Point P */ -#define MEI_DEV_ID_ADP_N 0x54E0 /* Alder Lake Point N */ /* * MEI HW Section diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index ca3067fa6f0e07df9e2d8ce3fc11ab0a53ef550c..fee603039e872430736dedb51a934494d103d5b6 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -427,26 +427,31 @@ int mei_irq_read_handler(struct mei_device *dev, list_for_each_entry(cl, &dev->file_list, link) { if (mei_cl_hbm_equal(cl, mei_hdr)) { cl_dbg(dev, cl, "got a message\n"); - ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); - goto reset_slots; + break; } } /* if no recipient cl was found we assume corrupted header */ - /* A message for not connected fixed address clients - * should be silently discarded - * On power down client may be force cleaned, - * silently discard such messages - */ - if (hdr_is_fixed(mei_hdr) || - dev->dev_state == MEI_DEV_POWER_DOWN) { - mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); - ret = 0; - goto reset_slots; + if (&cl->link == &dev->file_list) { + /* A message for not connected fixed address clients + * should be silently discarded + * On power down client may be force cleaned, + * silently discard such messages + */ + if (hdr_is_fixed(mei_hdr) || + dev->dev_state == MEI_DEV_POWER_DOWN) { + mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); + ret = 0; + goto reset_slots; + } + dev_err(dev->dev, "no destination client found 0x%08X\n", + dev->rd_msg_hdr[0]); + ret = -EBADMSG; + goto end; } - dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]); - ret = -EBADMSG; - goto end; + + ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); + reset_slots: /* reset the number of slots and header */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index a738253dbd056171fc8db0e16b60cbb3407450df..3a45aaf002ac8523e3955e23e21603acfffeb280 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -113,7 +113,6 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_N, MEI_ME_PCH15_CFG)}, /* required last entry */ {0, } diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index b7717fd8cb2acd3f07821572d33c46638cf391d0..d0b71aecaee86d396a430488bd83929daf17401c 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -514,16 +514,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) EXPORT_SYMBOL(mmc_alloc_host); -static int mmc_validate_host_caps(struct mmc_host *host) -{ - if (host->caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) { - dev_warn(host->parent, "missing ->enable_sdio_irq() ops\n"); - return -EINVAL; - } - - return 0; -} - /** * mmc_add_host - initialise host hardware * @host: mmc host @@ -536,9 +526,8 @@ int mmc_add_host(struct mmc_host *host) { int err; - err = mmc_validate_host_caps(host); - if (err) - return err; + WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && + !host->ops->enable_sdio_irq); err = device_add(&host->class_dev); if (err) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 647928ab00a30db117ce9a65d52a765cf364999a..90cd179625fc27be597ab4e4bcc21f2b626a9ead 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1375,12 +1375,8 @@ static int davinci_mmcsd_suspend(struct device *dev) static int davinci_mmcsd_resume(struct device *dev) { struct mmc_davinci_host *host = dev_get_drvdata(dev); - int ret; - - ret = clk_enable(host->clk); - if (ret) - return ret; + clk_enable(host->clk); mmc_davinci_reset_ctrl(host, 0); return 0; diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c index a4b8b65fe15f50faeaa1225203c52cd50f6a9288..8b6f4da5d72011b878732242d0041dc6b6c0b2aa 100644 --- a/drivers/mtd/nand/onenand/generic.c +++ b/drivers/mtd/nand/onenand/generic.c @@ -53,12 +53,7 @@ static int generic_onenand_probe(struct platform_device *pdev) } info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL; - - err = platform_get_irq(pdev, 0); - if (err < 0) - goto out_iounmap; - - info->onenand.irq = err; + info->onenand.irq = platform_get_irq(pdev, 0); info->mtd.dev.parent = &pdev->dev; info->mtd.priv = &info->onenand; diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index c048e826746a9d92cd2a9d455bd417f91da62630..8aab1017b460037d1ba7d5036a89bad20dce0e99 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2057,15 +2057,13 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, nc->mck = of_clk_get(dev->parent->of_node, 0); if (IS_ERR(nc->mck)) { dev_err(dev, "Failed to retrieve MCK clk\n"); - ret = PTR_ERR(nc->mck); - goto out_release_dma; + return PTR_ERR(nc->mck); } np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0); if (!np) { dev_err(dev, "Missing or invalid atmel,smc property\n"); - ret = -EINVAL; - goto out_release_dma; + return -EINVAL; } nc->smc = syscon_node_to_regmap(np); @@ -2073,16 +2071,10 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, if (IS_ERR(nc->smc)) { ret = PTR_ERR(nc->smc); dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret); - goto out_release_dma; + return ret; } return 0; - -out_release_dma: - if (nc->dmac) - dma_release_channel(nc->dmac); - - return ret; } static int diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 92e8ca56f56653761a502b383fe8a8a86150a952..cb7631145700a56f700fa861d4ed42f88817fc50 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -646,7 +646,6 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, const struct nand_sdr_timings *sdr) { struct gpmi_nfc_hardware_timing *hw = &this->hw; - struct resources *r = &this->resources; unsigned int dll_threshold_ps = this->devdata->max_chain_delay; unsigned int period_ps, reference_period_ps; unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles; @@ -670,8 +669,6 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY; } - hw->clk_rate = clk_round_rate(r->clock[0], hw->clk_rate); - /* SDR core timings are given in picoseconds */ period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index c41c0ff611b1bf312310c5e66ed0c5b464d6cee6..1f0d542d59230c06d5277f5741d66831d23958fb 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -297,19 +297,16 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) * * Return: -EBUSY if the chip has been suspended, 0 otherwise */ -static void nand_get_device(struct nand_chip *chip) +static int nand_get_device(struct nand_chip *chip) { - /* Wait until the device is resumed. */ - while (1) { - mutex_lock(&chip->lock); - if (!chip->suspended) { - mutex_lock(&chip->controller->lock); - return; - } + mutex_lock(&chip->lock); + if (chip->suspended) { mutex_unlock(&chip->lock); - - wait_event(chip->resume_wq, !chip->suspended); + return -EBUSY; } + mutex_lock(&chip->controller->lock); + + return 0; } /** @@ -534,7 +531,9 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) nand_erase_nand(chip, &einfo, 0); /* Write bad block marker to OOB */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; ret = nand_markbad_bbm(chip, ofs); nand_release_device(chip); @@ -3535,7 +3534,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ops->mode != MTD_OPS_RAW) return -ENOTSUPP; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; if (!ops->datbuf) ret = nand_do_read_oob(chip, from, ops); @@ -4118,11 +4119,13 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct nand_chip *chip = mtd_to_nand(mtd); - int ret = 0; + int ret; ops->retlen = 0; - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -4178,7 +4181,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, return -EINVAL; /* Grab the lock and see if the device is available */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -4265,7 +4270,7 @@ static void nand_sync(struct mtd_info *mtd) pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ - nand_get_device(chip); + WARN_ON(nand_get_device(chip)); /* Release it and go back */ nand_release_device(chip); } @@ -4282,7 +4287,9 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) int ret; /* Select the NAND device */ - nand_get_device(chip); + ret = nand_get_device(chip); + if (ret) + return ret; nand_select_target(chip, chipnr); @@ -4353,8 +4360,6 @@ static void nand_resume(struct mtd_info *mtd) __func__); } mutex_unlock(&chip->lock); - - wake_up_all(&chip->resume_wq); } /** @@ -5063,7 +5068,6 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, chip->cur_cs = -1; mutex_init(&chip->lock); - init_waitqueue_head(&chip->resume_wq); /* Enforce the right timings for reset/detection */ chip->current_interface_config = nand_get_reset_interface_config(); diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 9a9f1c24d83219c34b1da8f1f2b45aceceeb47f7..9e7cf9f36057981f351db48d063dbe44ac883391 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2453,5 +2453,6 @@ static void __exit ns_cleanup_module(void) module_exit(ns_cleanup_module); MODULE_LICENSE ("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR ("Artem B. Bityuckiy"); MODULE_DESCRIPTION ("The NAND flash simulator"); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 4153e0d15c5f913711507fbaf35e50e2ae297173..0597478129ffe177c21ff489dac358af08ae6870 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -350,6 +350,9 @@ static ssize_t dev_attribute_show(struct device *dev, * we still can use 'ubi->ubi_num'. */ ubi = container_of(dev, struct ubi_device, dev); + ubi = ubi_get_device(ubi->ubi_num); + if (!ubi) + return -ENODEV; if (attr == &dev_eraseblock_size) ret = sprintf(buf, "%d\n", ubi->leb_size); @@ -378,6 +381,7 @@ static ssize_t dev_attribute_show(struct device *dev, else ret = -EINVAL; + ubi_put_device(ubi); return ret; } @@ -976,6 +980,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, goto out_detach; } + /* Make device "available" before it becomes accessible via sysfs */ + ubi_devices[ubi_num] = ubi; + err = uif_init(ubi); if (err) goto out_detach; @@ -1020,7 +1027,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, wake_up_process(ubi->bgt_thread); spin_unlock(&ubi->wl_lock); - ubi_devices[ubi_num] = ubi; ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL); return ubi_num; @@ -1029,6 +1035,7 @@ out_debugfs: out_uif: uif_close(ubi); out_detach: + ubi_devices[ubi_num] = NULL; ubi_wl_close(ubi); ubi_free_all_volumes(ubi); vfree(ubi->vtbl); @@ -1469,3 +1476,4 @@ MODULE_VERSION(__stringify(UBI_VERSION)); MODULE_DESCRIPTION("UBI - Unsorted Block Images"); MODULE_AUTHOR("Artem Bityutskiy"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 6b5f1ffd961b9430e553e2564f7163598f3a1b63..022af59906aa9a6d2b9bfd59e375964c21b3e884 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -468,9 +468,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, if (err == UBI_IO_FF_BITFLIPS) scrub = 1; - ret = add_aeb(ai, free, pnum, ec, scrub); - if (ret) - goto out; + add_aeb(ai, free, pnum, ec, scrub); continue; } else if (err == 0 || err == UBI_IO_BITFLIPS) { dbg_bld("Found non empty PEB:%i in pool", pnum); @@ -640,10 +638,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); - if (ret) - goto fail; + add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 0); } /* read EC values from used list */ @@ -653,10 +649,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); - if (ret) - goto fail; + add_aeb(ai, &used, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 0); } /* read EC values from scrub list */ @@ -666,10 +660,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); - if (ret) - goto fail; + add_aeb(ai, &used, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 1); } /* read EC values from erase list */ @@ -679,10 +671,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; - ret = add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); - if (ret) - goto fail; + add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), + be32_to_cpu(fmec->ec), 1); } ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 1bc7b3a05604628ebd3a334f8be766efa7ecf471..139ee132bfbcfa432bb8b75f3df93858900c07f9 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -56,11 +56,16 @@ static ssize_t vol_attribute_show(struct device *dev, { int ret; struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); - struct ubi_device *ubi = vol->ubi; + struct ubi_device *ubi; + + ubi = ubi_get_device(vol->ubi->ubi_num); + if (!ubi) + return -ENODEV; spin_lock(&ubi->volumes_lock); if (!ubi->volumes[vol->vol_id]) { spin_unlock(&ubi->volumes_lock); + ubi_put_device(ubi); return -ENODEV; } /* Take a reference to prevent volume removal */ @@ -98,6 +103,7 @@ static ssize_t vol_attribute_show(struct device *dev, vol->ref_count -= 1; ubi_assert(vol->ref_count >= 0); spin_unlock(&ubi->volumes_lock); + ubi_put_device(ubi); return ret; } diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index 53ef48588e59a1510ab5ac4d16a76f26d7728ca1..39b128205f2551b97fb4213fe6127ea4fd3d4b85 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -140,14 +140,14 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) oiph = skb_network_header(skb); skb_reset_network_header(skb); - if (!ipv6_mod_enabled() || family == AF_INET) + if (!IS_ENABLED(CONFIG_IPV6) || family == AF_INET) err = IP_ECN_decapsulate(oiph, skb); else err = IP6_ECN_decapsulate(oiph, skb); if (unlikely(err)) { if (log_ecn_error) { - if (!ipv6_mod_enabled() || family == AF_INET) + if (!IS_ENABLED(CONFIG_IPV6) || family == AF_INET) net_info_ratelimited("non-ECT from %pI4 " "with TOS=%#x\n", &((struct iphdr *)oiph)->saddr, @@ -213,12 +213,11 @@ static struct socket *bareudp_create_sock(struct net *net, __be16 port) int err; memset(&udp_conf, 0, sizeof(udp_conf)); - - if (ipv6_mod_enabled()) - udp_conf.family = AF_INET6; - else - udp_conf.family = AF_INET; - +#if IS_ENABLED(CONFIG_IPV6) + udp_conf.family = AF_INET6; +#else + udp_conf.family = AF_INET; +#endif udp_conf.local_udp_port = port; /* Open UDP socket */ err = udp_sock_create(net, &udp_conf, &sock); @@ -247,6 +246,12 @@ static int bareudp_socket_create(struct bareudp_dev *bareudp, __be16 port) tunnel_cfg.encap_destroy = NULL; setup_udp_tunnel_sock(bareudp->net, sock, &tunnel_cfg); + /* As the setup_udp_tunnel_sock does not call udp_encap_enable if the + * socket type is v6 an explicit call to udp_encap_enable is needed. + */ + if (sock->sk->sk_family == AF_INET6) + udp_encap_enable(); + rcu_assign_pointer(bareudp->sock, sock); return 0; } @@ -440,7 +445,7 @@ static netdev_tx_t bareudp_xmit(struct sk_buff *skb, struct net_device *dev) } rcu_read_lock(); - if (ipv6_mod_enabled() && info->mode & IP_TUNNEL_INFO_IPV6) + if (IS_ENABLED(CONFIG_IPV6) && info->mode & IP_TUNNEL_INFO_IPV6) err = bareudp6_xmit_skb(skb, dev, bareudp, info); else err = bareudp_xmit_skb(skb, dev, bareudp, info); @@ -470,7 +475,7 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, use_cache = ip_tunnel_dst_cache_usable(skb, info); - if (!ipv6_mod_enabled() || ip_tunnel_info_af(info) == AF_INET) { + if (!IS_ENABLED(CONFIG_IPV6) || ip_tunnel_info_af(info) == AF_INET) { struct rtable *rt; __be32 saddr; diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 19a19a7b7deb87b3a73895f044f4cd0e387650bb..19a7e4adb9338d945490fb68117221a23ba3529b 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1491,6 +1491,8 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) M_CAN_FIFO_DATA(i / 4), *(u32 *)(cf->data + i)); + can_put_echo_skb(skb, dev, 0); + if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { cccr = m_can_read(cdev, M_CAN_CCCR); cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT); @@ -1507,9 +1509,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) m_can_write(cdev, M_CAN_CCCR, cccr); } m_can_write(cdev, M_CAN_TXBTIE, 0x1); - - can_put_echo_skb(skb, dev, 0); - m_can_write(cdev, M_CAN_TXBAR, 0x1); /* End of xmit function for version 3.0.x */ } else { diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 189d226588133dcdf2d6442fecc33e2c3bf496c9..abe00a085f6fcd872481441120aa020471c6fe80 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -2578,7 +2578,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, out_kfree_buf_rx: kfree(buf_rx); - return err; + return 0; } #define MCP251XFD_QUIRK_ACTIVE(quirk) \ diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 6458da9c13b95500422a0beb364839db1f094122..249d2fba28c7f4d18fab66ea7346967c77dbb4cb 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -823,6 +823,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne usb_unanchor_urb(urb); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); + dev_kfree_skb(skb); atomic_dec(&dev->active_tx_urbs); diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index 21063335ab599cde2e410e7ca0389f6b3ae1bdb6..912160fd2ca02457f44c688e6040a1ff16bf6b09 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -33,6 +33,10 @@ #define MCBA_USB_RX_BUFF_SIZE 64 #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg)) +/* MCBA endpoint numbers */ +#define MCBA_USB_EP_IN 1 +#define MCBA_USB_EP_OUT 1 + /* Microchip command id */ #define MBCA_CMD_RECEIVE_MESSAGE 0xE3 #define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5 @@ -80,8 +84,6 @@ struct mcba_priv { atomic_t free_ctx_cnt; void *rxbuf[MCBA_MAX_RX_URBS]; dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS]; - int rx_pipe; - int tx_pipe; }; /* CAN frame */ @@ -270,8 +272,10 @@ static netdev_tx_t mcba_usb_xmit(struct mcba_priv *priv, memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE); - usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_SIZE, - mcba_usb_write_bulk_callback, ctx); + usb_fill_bulk_urb(urb, priv->udev, + usb_sndbulkpipe(priv->udev, MCBA_USB_EP_OUT), buf, + MCBA_USB_TX_BUFF_SIZE, mcba_usb_write_bulk_callback, + ctx); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(urb, &priv->tx_submitted); @@ -364,6 +368,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, xmit_failed: can_free_echo_skb(priv->netdev, ctx->ndx); mcba_usb_free_ctx(ctx); + dev_kfree_skb(skb); stats->tx_dropped++; return NETDEV_TX_OK; @@ -606,7 +611,7 @@ static void mcba_usb_read_bulk_callback(struct urb *urb) resubmit_urb: usb_fill_bulk_urb(urb, priv->udev, - priv->rx_pipe, + usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_OUT), urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); @@ -651,7 +656,7 @@ static int mcba_usb_start(struct mcba_priv *priv) urb->transfer_dma = buf_dma; usb_fill_bulk_urb(urb, priv->udev, - priv->rx_pipe, + usb_rcvbulkpipe(priv->udev, MCBA_USB_EP_IN), buf, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -805,13 +810,6 @@ static int mcba_usb_probe(struct usb_interface *intf, struct mcba_priv *priv; int err; struct usb_device *usbdev = interface_to_usbdev(intf); - struct usb_endpoint_descriptor *in, *out; - - err = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, NULL); - if (err) { - dev_err(&intf->dev, "Can't find endpoints\n"); - return err; - } netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS); if (!netdev) { @@ -857,9 +855,6 @@ static int mcba_usb_probe(struct usb_interface *intf, goto cleanup_free_candev; } - priv->rx_pipe = usb_rcvbulkpipe(priv->udev, in->bEndpointAddress); - priv->tx_pipe = usb_sndbulkpipe(priv->udev, out->bEndpointAddress); - devm_can_led_init(netdev); /* Start USB dev only if we have successfully registered CAN device */ diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 985e00aee4ee1253fd2d7399f1d551859e422843..ca7c55d6a41dbe2001655be026f063ed8e47bb39 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -670,20 +670,9 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, atomic_inc(&priv->active_tx_urbs); err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - can_free_echo_skb(netdev, context->echo_index); - - usb_unanchor_urb(urb); - usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); - - atomic_dec(&priv->active_tx_urbs); - - if (err == -ENODEV) - netif_device_detach(netdev); - else - netdev_warn(netdev, "failed tx_urb %d\n", err); - stats->tx_dropped++; - } else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) + if (unlikely(err)) + goto failed; + else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) /* Slow down tx path */ netif_stop_queue(netdev); @@ -702,6 +691,19 @@ nofreecontext: return NETDEV_TX_BUSY; +failed: + can_free_echo_skb(netdev, context->echo_index); + + usb_unanchor_urb(urb); + usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); + + atomic_dec(&priv->active_tx_urbs); + + if (err == -ENODEV) + netif_device_detach(netdev); + else + netdev_warn(netdev, "failed tx_urb %d\n", err); + nomembuf: usb_free_urb(urb); diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 282c53ef76d233535938091043c3d52072c36e9b..7000c6cd1e48bc5d8fbee7bd3b69523cc69f9186 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -148,7 +148,7 @@ static void vxcan_setup(struct net_device *dev) dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 0; - dev->flags = IFF_NOARP; + dev->flags = (IFF_NOARP|IFF_ECHO); dev->netdev_ops = &vxcan_netdev_ops; dev->needs_free_netdev = true; diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index cbf44fc7d03aa4f650c8b22e8d332096a13e6220..d82cee5d92022be1ee39e1ab1a314c2352cf1f3a 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -567,14 +567,14 @@ static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, static struct cfp_rule *bcm_sf2_cfp_rule_find(struct bcm_sf2_priv *priv, int port, u32 location) { - struct cfp_rule *rule; + struct cfp_rule *rule = NULL; list_for_each_entry(rule, &priv->cfp.rules_list, next) { if (rule->port == port && rule->fs.location == location) - return rule; + break; } - return NULL; + return rule; } static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port, diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c index 5639c5c59e255e6f639bad75a722d842f723c51c..8b00f8e6c02f4f2a2fbc545c026cb2daaa48528c 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -86,23 +86,12 @@ static const struct of_device_id ksz8795_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, ksz8795_dt_ids); -static const struct spi_device_id ksz8795_spi_ids[] = { - { "ksz8765" }, - { "ksz8794" }, - { "ksz8795" }, - { "ksz8863" }, - { "ksz8873" }, - { }, -}; -MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); - static struct spi_driver ksz8795_spi_driver = { .driver = { .name = "ksz8795-switch", .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz8795_dt_ids), }, - .id_table = ksz8795_spi_ids, .probe = ksz8795_spi_probe, .remove = ksz8795_spi_remove, .shutdown = ksz8795_spi_shutdown, diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index 9bda83d063e8ec652434b02aca2047d165f216de..1142768969c205b9c4f5a25bfc56bd452c4dd283 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -88,24 +88,12 @@ static const struct of_device_id ksz9477_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, ksz9477_dt_ids); -static const struct spi_device_id ksz9477_spi_ids[] = { - { "ksz9477" }, - { "ksz9897" }, - { "ksz9893" }, - { "ksz9563" }, - { "ksz8563" }, - { "ksz9567" }, - { }, -}; -MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids); - static struct spi_driver ksz9477_spi_driver = { .driver = { .name = "ksz9477-switch", .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz9477_dt_ids), }, - .id_table = ksz9477_spi_ids, .probe = ksz9477_spi_probe, .remove = ksz9477_spi_remove, .shutdown = ksz9477_spi_shutdown, diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e79a808375fc862fd886a1d57c97a92a6d1bc7ac..1992be77522ac0db4046e74b5e29badbba1718d9 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3297,7 +3297,6 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_set_link = mv88e6xxx_port_set_link, .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, - .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_set_ether_type = mv88e6351_port_set_ether_type, diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c index 065fdbe66c425de384dfaeccef0182f7eaae5f46..4ad8031ab6695707bd275a4e0d66b65dfe5c0d95 100644 --- a/drivers/net/ethernet/8390/mcf8390.c +++ b/drivers/net/ethernet/8390/mcf8390.c @@ -406,12 +406,12 @@ static int mcf8390_init(struct net_device *dev) static int mcf8390_probe(struct platform_device *pdev) { struct net_device *dev; - struct resource *mem; + struct resource *mem, *irq; resource_size_t msize; - int ret, irq; + int ret; - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq == NULL) { dev_err(&pdev->dev, "no IRQ specified?\n"); return -ENXIO; } @@ -434,7 +434,7 @@ static int mcf8390_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); platform_set_drvdata(pdev, dev); - dev->irq = irq; + dev->irq = irq->start; dev->base_addr = mem->start; ret = mcf8390_init(dev); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 78c7cbc372b0559c1aaf2a95bb9ac84c9dba860a..5f1fc6582d74a2b624ac3351b6e0ec41f400bc11 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -696,12 +696,6 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, buf_pool->rx_skb[skb_index] = NULL; datalen = xgene_enet_get_data_len(le64_to_cpu(raw_desc->m1)); - - /* strip off CRC as HW isn't doing this */ - nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0)); - if (!nv) - datalen -= 4; - skb_put(skb, datalen); prefetch(skb->data - NET_IP_ALIGN); skb->protocol = eth_type_trans(skb, ndev); @@ -723,8 +717,12 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, } } - if (!nv) + nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0)); + if (!nv) { + /* strip off CRC as HW isn't doing this */ + datalen -= 4; goto skip_jumbo; + } slots = page_pool->slots - 1; head = page_pool->head; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2a61229d3f9762cf0b3d389d1a3916ad0555c1da..bb3ba614fb17497d62566d41026997db23473a26 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2534,4 +2534,6 @@ void bnx2x_register_phc(struct bnx2x *bp); * Meant for implicit re-load flows. */ int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp); +int bnx2x_init_firmware(struct bnx2x *bp); +void bnx2x_release_firmware(struct bnx2x *bp); #endif /* bnx2x.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 198e041d841091d5d6bcbe76b0a858f6de715de0..41ebbb2c7d3ac3c8d1aa172d9a2a874e6f51b8d7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2363,30 +2363,24 @@ int bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err) /* is another pf loaded on this engine? */ if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { - u8 loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng; - u32 loaded_fw; + /* build my FW version dword */ + u32 my_fw = (bp->fw_major) + (bp->fw_minor << 8) + + (bp->fw_rev << 16) + (bp->fw_eng << 24); /* read loaded FW from chip */ - loaded_fw = REG_RD(bp, XSEM_REG_PRAM); + u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); - loaded_fw_major = loaded_fw & 0xff; - loaded_fw_minor = (loaded_fw >> 8) & 0xff; - loaded_fw_rev = (loaded_fw >> 16) & 0xff; - loaded_fw_eng = (loaded_fw >> 24) & 0xff; - - DP(BNX2X_MSG_SP, "loaded fw 0x%x major 0x%x minor 0x%x rev 0x%x eng 0x%x\n", - loaded_fw, loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng); + DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n", + loaded_fw, my_fw); /* abort nic load if version mismatch */ - if (loaded_fw_major != BCM_5710_FW_MAJOR_VERSION || - loaded_fw_minor != BCM_5710_FW_MINOR_VERSION || - loaded_fw_eng != BCM_5710_FW_ENGINEERING_VERSION || - loaded_fw_rev < BCM_5710_FW_REVISION_VERSION_V15) { + if (my_fw != loaded_fw) { if (print_err) - BNX2X_ERR("loaded FW incompatible. Aborting\n"); + BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. Aborting\n", + loaded_fw, my_fw); else - BNX2X_DEV_INFO("loaded FW incompatible, possibly due to MF UNDI\n"); - + BNX2X_DEV_INFO("bnx2x with FW %x was already loaded which mismatches my %x FW, possibly due to MF UNDI\n", + loaded_fw, my_fw); return -EBUSY; } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 6333471916be10ff9cb601f1a9ce9404e72a7a12..7fa271db41b0763c719b7ea223c79e166e1d72eb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12366,6 +12366,15 @@ static int bnx2x_init_bp(struct bnx2x *bp) bnx2x_read_fwinfo(bp); + if (IS_PF(bp)) { + rc = bnx2x_init_firmware(bp); + + if (rc) { + bnx2x_free_mem_bp(bp); + return rc; + } + } + func = BP_FUNC(bp); /* need to reset chip if undi was active */ @@ -12378,6 +12387,7 @@ static int bnx2x_init_bp(struct bnx2x *bp) rc = bnx2x_prev_unload(bp); if (rc) { + bnx2x_release_firmware(bp); bnx2x_free_mem_bp(bp); return rc; } @@ -13459,7 +13469,7 @@ do { \ (u8 *)bp->arr, len); \ } while (0) -static int bnx2x_init_firmware(struct bnx2x *bp) +int bnx2x_init_firmware(struct bnx2x *bp) { const char *fw_file_name, *fw_file_name_v15; struct bnx2x_fw_file_hdr *fw_hdr; @@ -13559,7 +13569,7 @@ request_firmware_exit: return rc; } -static void bnx2x_release_firmware(struct bnx2x *bp) +void bnx2x_release_firmware(struct bnx2x *bp) { kfree(bp->init_ops_offsets); kfree(bp->init_ops); @@ -14076,6 +14086,7 @@ static int bnx2x_init_one(struct pci_dev *pdev, return 0; init_one_freemem: + bnx2x_release_firmware(bp); bnx2x_free_mem_bp(bp); init_one_exit: diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 7dcd5613ee56f8139f5f59ee10ec562576b8d777..e19cf020e5ae1af76baa3132b2cd3397a10cddb8 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -76,7 +76,7 @@ static inline void bcmgenet_writel(u32 value, void __iomem *offset) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) __raw_writel(value, offset); else - writel(value, offset); + writel_relaxed(value, offset); } static inline u32 bcmgenet_readl(void __iomem *offset) @@ -84,7 +84,7 @@ static inline u32 bcmgenet_readl(void __iomem *offset) if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) return __raw_readl(offset); else - return readl(offset); + return readl_relaxed(offset); } static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv, @@ -2239,10 +2239,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, dma_length_status = status->length_status; if (dev->features & NETIF_F_RXCSUM) { rx_csum = (__force __be16)(status->rx_csum & 0xffff); - if (rx_csum) { - skb->csum = (__force __wsum)ntohs(rx_csum); - skb->ip_summed = CHECKSUM_COMPLETE; - } + skb->csum = (__force __wsum)ntohs(rx_csum); + skb->ip_summed = CHECKSUM_COMPLETE; } /* DMA flags and length are still valid no matter how diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index cf98a00296edf09b3e306c910207a68caba40a5b..9c1690f64a027b8de3c2e3344de0c53d3b758624 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -651,10 +651,7 @@ static int enetc_get_ts_info(struct net_device *ndev, #ifdef CONFIG_FSL_ENETC_PTP_CLOCK info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_RAW_HARDWARE | - SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; + SOF_TIMESTAMPING_RAW_HARDWARE; info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2070e26a3a358bc6041acfc35cd4c424556724fc..7b94764b4f5d9ccf6036be5cfb1e44f5bfe9d4ad 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7616,11 +7616,12 @@ int hclge_rm_uc_addr_common(struct hclge_vport *vport, hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hclge_prepare_mac_addr(&req, addr, false); ret = hclge_remove_mac_vlan_tbl(vport, &req); - if (!ret || ret == -ENOENT) { + if (!ret) { mutex_lock(&hdev->vport_lock); hclge_update_umv_space(vport, true); mutex_unlock(&hdev->vport_lock); - return 0; + } else if (ret == -ENOENT) { + ret = 0; } return ret; @@ -9197,11 +9198,11 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, } if (!ret) { - if (!is_kill) + if (is_kill) + hclge_rm_vport_vlan_table(vport, vlan_id, false); + else hclge_add_vport_vlan_table(vport, vlan_id, writen_to_tbl); - else if (is_kill && vlan_id != 0) - hclge_rm_vport_vlan_table(vport, vlan_id, false); } else if (is_kill) { /* when remove hw vlan filter failed, record the vlan id, * and try to remove it from hw later, to be consistence diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 75e4a698c3db20b71140cb694cba11e031697f0d..86c79f71c685a5f41a118685bb792f7e943466a0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -247,25 +247,21 @@ no_buffers: static struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp) { - unsigned int totalsize = xdp->data_end - xdp->data_meta; unsigned int metasize = xdp->data - xdp->data_meta; + unsigned int datasize = xdp->data_end - xdp->data; struct sk_buff *skb; - net_prefetch(xdp->data_meta); - /* allocate a skb to store the frags */ - skb = __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize, + skb = __napi_alloc_skb(&rx_ring->q_vector->napi, + xdp->data_end - xdp->data_hard_start, GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!skb)) return NULL; - memcpy(__skb_put(skb, totalsize), xdp->data_meta, - ALIGN(totalsize, sizeof(long))); - - if (metasize) { + skb_reserve(skb, xdp->data - xdp->data_hard_start); + memcpy(__skb_put(skb, datasize), xdp->data, datasize); + if (metasize) skb_metadata_set(skb, metasize); - __skb_pull(skb, metasize); - } xsk_buff_free(xdp); return skb; diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index c4c4649b2088e17653f3ab9267c71316e340a3d3..217e8333de6c66154cbe0d6b0af078b3200083ac 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -54,12 +54,6 @@ static int ocelot_chain_to_block(int chain, bool ingress) */ static int ocelot_chain_to_lookup(int chain) { - /* Backwards compatibility with older, single-chain tc-flower - * offload support in Ocelot - */ - if (chain == 0) - return 0; - return (chain / VCAP_LOOKUP) % 10; } @@ -68,15 +62,7 @@ static int ocelot_chain_to_lookup(int chain) */ static int ocelot_chain_to_pag(int chain) { - int lookup; - - /* Backwards compatibility with older, single-chain tc-flower - * offload support in Ocelot - */ - if (chain == 0) - return 0; - - lookup = ocelot_chain_to_lookup(chain); + int lookup = ocelot_chain_to_lookup(chain); /* calculate PAG value as chain index relative to the first PAG */ return chain - VCAP_IS2_CHAIN(lookup, 0); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index e14869a2e24a517d75e5b1e0afba00d4e93d7856..d355676f6c160d685239d52565cf96075297eae2 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -311,10 +311,10 @@ int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) static void ionic_dev_cmd_clean(struct ionic *ionic) { - struct ionic_dev *idev = &ionic->idev; + union __iomem ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs; - iowrite32(0, &idev->dev_cmd_regs->doorbell); - memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd)); + iowrite32(0, ®s->doorbell); + memset_io(®s->cmd, 0, sizeof(regs->cmd)); } int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 3541bc95493f0bb83cbfce9d445078eb835ac292..ef0ad4cf82e6060c9c6ccd07ccc7e27bd9a0bf2c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -2982,16 +2982,12 @@ static int qed_iov_pre_update_vport(struct qed_hwfn *hwfn, u8 mask = QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED; struct qed_filter_accept_flags *flags = ¶ms->accept_flags; struct qed_public_vf_info *vf_info; - u16 tlv_mask; - - tlv_mask = BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM) | - BIT(QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN); /* Untrusted VFs can't even be trusted to know that fact. * Simply indicate everything is configured fine, and trace * configuration 'behind their back'. */ - if (!(*tlvs & tlv_mask)) + if (!(*tlvs & BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM))) return 0; vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true); @@ -3008,13 +3004,6 @@ static int qed_iov_pre_update_vport(struct qed_hwfn *hwfn, flags->tx_accept_filter &= ~mask; } - if (params->update_accept_any_vlan_flg) { - vf_info->accept_any_vlan = params->accept_any_vlan; - - if (vf_info->forced_vlan && !vf_info->is_trusted_configured) - params->accept_any_vlan = false; - } - return 0; } @@ -4702,7 +4691,6 @@ static int qed_get_vf_config(struct qed_dev *cdev, tx_rate = vf_info->tx_rate; ivi->max_tx_rate = tx_rate ? tx_rate : link.speed; ivi->min_tx_rate = qed_iov_get_vf_min_rate(hwfn, vf_id); - ivi->trusted = vf_info->is_trusted_request; return 0; } @@ -5132,12 +5120,6 @@ static void qed_iov_handle_trust_change(struct qed_hwfn *hwfn) params.update_ctl_frame_check = 1; params.mac_chk_en = !vf_info->is_trusted_configured; - params.update_accept_any_vlan_flg = 0; - - if (vf_info->accept_any_vlan && vf_info->forced_vlan) { - params.update_accept_any_vlan_flg = 1; - params.accept_any_vlan = vf_info->accept_any_vlan; - } if (vf_info->rx_accept_mode & mask) { flags->update_rx_mode_config = 1; @@ -5153,20 +5135,13 @@ static void qed_iov_handle_trust_change(struct qed_hwfn *hwfn) if (!vf_info->is_trusted_configured) { flags->rx_accept_filter &= ~mask; flags->tx_accept_filter &= ~mask; - params.accept_any_vlan = false; } if (flags->update_rx_mode_config || flags->update_tx_mode_config || - params.update_ctl_frame_check || - params.update_accept_any_vlan_flg) { - DP_VERBOSE(hwfn, QED_MSG_IOV, - "vport update config for %s VF[abs 0x%x rel 0x%x]\n", - vf_info->is_trusted_configured ? "trusted" : "untrusted", - vf->abs_vf_id, vf->relative_vf_id); + params.update_ctl_frame_check) qed_sp_vport_update(hwfn, ¶ms, QED_SPQ_MODE_EBLOCK, NULL); - } } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 7ff23ef8ccc170c15b7c80d1dd6d1c34d8798b79..eacd6457f195ce650b35859ca442cbe73377479f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -62,7 +62,6 @@ struct qed_public_vf_info { bool is_trusted_request; u8 rx_accept_mode; u8 tx_accept_mode; - bool accept_any_vlan; }; struct qed_iov_vf_init_params { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h index 7519773eaca6ee5caa29f40c6f8aa891464760bd..5d79ee4370bcd5b89e0ca7cbc8b2e7b32c8c4d7b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h @@ -51,7 +51,7 @@ static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->get_hw_capability) return dcb->ops->get_hw_capability(dcb); - return -EOPNOTSUPP; + return 0; } static inline void qlcnic_dcb_free(struct qlcnic_dcb *dcb) @@ -65,7 +65,7 @@ static inline int qlcnic_dcb_attach(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->attach) return dcb->ops->attach(dcb); - return -EOPNOTSUPP; + return 0; } static inline int @@ -74,7 +74,7 @@ qlcnic_dcb_query_hw_capability(struct qlcnic_dcb *dcb, char *buf) if (dcb && dcb->ops->query_hw_capability) return dcb->ops->query_hw_capability(dcb, buf); - return -EOPNOTSUPP; + return 0; } static inline void qlcnic_dcb_get_info(struct qlcnic_dcb *dcb) @@ -89,7 +89,7 @@ qlcnic_dcb_query_cee_param(struct qlcnic_dcb *dcb, char *buf, u8 type) if (dcb && dcb->ops->query_cee_param) return dcb->ops->query_cee_param(dcb, buf, type); - return -EOPNOTSUPP; + return 0; } static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) @@ -97,7 +97,7 @@ static inline int qlcnic_dcb_get_cee_cfg(struct qlcnic_dcb *dcb) if (dcb && dcb->ops->get_cee_cfg) return dcb->ops->get_cee_cfg(dcb); - return -EOPNOTSUPP; + return 0; } static inline void qlcnic_dcb_aen_handler(struct qlcnic_dcb *dcb, void *msg) diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 69fc47089e625b4ab9077e4f6433f452f4b53dd2..54b53dbdb33cdbfa11e8f51b3358dc756de36871 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -3163,7 +3163,7 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, if (err) { printk(KERN_ERR "happymeal(PCI): Cannot register net device, " "aborting.\n"); - goto err_out_free_coherent; + goto err_out_iounmap; } pci_set_drvdata(pdev, hp); @@ -3196,10 +3196,6 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, return 0; -err_out_free_coherent: - dma_free_coherent(hp->dma_dev, PAGE_SIZE, - hp->happy_block, hp->hblock_dvma); - err_out_iounmap: iounmap(hp->gregs); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index bbdcba88c021efc5f9392ccbdfba351f34187537..0baf85122f5acebf183d1b2c2b5dc1ec1c4d7ee4 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -857,53 +857,46 @@ static void axienet_recv(struct net_device *ndev) while ((cur_p->status & XAXIDMA_BD_STS_COMPLETE_MASK)) { dma_addr_t phys; + tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; + /* Ensure we see complete descriptor update */ dma_rmb(); + phys = desc_get_phys_addr(lp, cur_p); + dma_unmap_single(ndev->dev.parent, phys, lp->max_frm_size, + DMA_FROM_DEVICE); skb = cur_p->skb; cur_p->skb = NULL; - - /* skb could be NULL if a previous pass already received the - * packet for this slot in the ring, but failed to refill it - * with a newly allocated buffer. In this case, don't try to - * receive it again. - */ - if (likely(skb)) { - length = cur_p->app4 & 0x0000FFFF; - - phys = desc_get_phys_addr(lp, cur_p); - dma_unmap_single(ndev->dev.parent, phys, lp->max_frm_size, - DMA_FROM_DEVICE); - - skb_put(skb, length); - skb->protocol = eth_type_trans(skb, ndev); - /*skb_checksum_none_assert(skb);*/ - skb->ip_summed = CHECKSUM_NONE; - - /* if we're doing Rx csum offload, set it up */ - if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { - csumstatus = (cur_p->app2 & - XAE_FULL_CSUM_STATUS_MASK) >> 3; - if (csumstatus == XAE_IP_TCP_CSUM_VALIDATED || - csumstatus == XAE_IP_UDP_CSUM_VALIDATED) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && - skb->protocol == htons(ETH_P_IP) && - skb->len > 64) { - skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); - skb->ip_summed = CHECKSUM_COMPLETE; + length = cur_p->app4 & 0x0000FFFF; + + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, ndev); + /*skb_checksum_none_assert(skb);*/ + skb->ip_summed = CHECKSUM_NONE; + + /* if we're doing Rx csum offload, set it up */ + if (lp->features & XAE_FEATURE_FULL_RX_CSUM) { + csumstatus = (cur_p->app2 & + XAE_FULL_CSUM_STATUS_MASK) >> 3; + if ((csumstatus == XAE_IP_TCP_CSUM_VALIDATED) || + (csumstatus == XAE_IP_UDP_CSUM_VALIDATED)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; } + } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && + skb->protocol == htons(ETH_P_IP) && + skb->len > 64) { + skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); + skb->ip_summed = CHECKSUM_COMPLETE; + } - netif_rx(skb); + netif_rx(skb); - size += length; - packets++; - } + size += length; + packets++; new_skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size); if (!new_skb) - break; + return; phys = dma_map_single(ndev->dev.parent, new_skb->data, lp->max_frm_size, @@ -912,7 +905,7 @@ static void axienet_recv(struct net_device *ndev) if (net_ratelimit()) netdev_err(ndev, "RX DMA mapping error\n"); dev_kfree_skb(new_skb); - break; + return; } desc_set_phys_addr(lp, phys, cur_p); @@ -920,11 +913,6 @@ static void axienet_recv(struct net_device *ndev) cur_p->status = 0; cur_p->skb = new_skb; - /* Only update tail_p to mark this slot as usable after it has - * been successfully refilled. - */ - tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci; - if (++lp->rx_bd_ci >= lp->rx_bd_num) lp->rx_bd_ci = 0; cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 02d6f3ad9aca8859adb402493dd3be81e98a1d11..bd0beb16d68a9f0a1644715616a522a976ee5de5 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -674,14 +674,14 @@ static void sixpack_close(struct tty_struct *tty) */ netif_stop_queue(sp->dev); - unregister_netdev(sp->dev); - del_timer_sync(&sp->tx_t); del_timer_sync(&sp->resync_t); /* Free all 6pack frame buffers. */ kfree(sp->rbuff); kfree(sp->xbuff); + + unregister_netdev(sp->dev); } /* Perform I/O control on an active 6pack channel. */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e3676386d0eeb2d1647e1a82a17766065fc2191b..261e6e55a907b2088f535908859afef1ad0589e2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1562,9 +1562,6 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, pcpu_sum = kvmalloc_array(num_possible_cpus(), sizeof(struct netvsc_ethtool_pcpu_stats), GFP_KERNEL); - if (!pcpu_sum) - return; - netvsc_get_pcpu_stats(dev, pcpu_sum); for_each_present_cpu(cpu) { struct netvsc_ethtool_pcpu_stats *this_sum = &pcpu_sum[cpu]; diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 0cde17bd743f3cb3798f5c282cbd3e7fcae630e9..644861366d5442c7aaca5c29c7801ae73a70e61e 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -11,7 +11,6 @@ */ #include "bcm-phy-lib.h" -#include #include #include #include @@ -623,26 +622,6 @@ static int brcm_fet_config_init(struct phy_device *phydev) if (err < 0) return err; - /* The datasheet indicates the PHY needs up to 1us to complete a reset, - * build some slack here. - */ - usleep_range(1000, 2000); - - /* The PHY requires 65 MDC clock cycles to complete a write operation - * and turnaround the line properly. - * - * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac) - * may flag the lack of turn-around as a read failure. This is - * particularly true with this combination since the MDIO controller - * only used 64 MDC cycles. This is not a critical failure in this - * specific case and it has no functional impact otherwise, so we let - * that one go through. If there is a genuine bus error, the next read - * of MII_BRCM_FET_INTREG will error out. - */ - err = phy_read(phydev, MII_BMCR); - if (err < 0 && err != -EIO) - return err; - reg = phy_read(phydev, MII_BRCM_FET_INTREG); if (reg < 0) return reg; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 54786712a99130583bf0546c2f9a500b9bb021b3..cb9d1852a75c8c0f23d68583f3309230bb84c8e8 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1536,8 +1536,8 @@ static int marvell_suspend(struct phy_device *phydev) int err; /* Suspend the fiber mode first */ - if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, - phydev->supported)) { + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported)) { err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1571,8 +1571,8 @@ static int marvell_resume(struct phy_device *phydev) int err; /* Resume the fiber mode first */ - if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, - phydev->supported)) { + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported)) { err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index e14fa72791b0e47f1a5a1c22e1538b1196611fcd..41a410124437d105b9657b9174d8b56f52606148 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2584,6 +2584,3 @@ MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl); MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver"); MODULE_AUTHOR("Nagaraju Lakkaraju"); MODULE_LICENSE("Dual MIT/GPL"); - -MODULE_FIRMWARE(MSCC_VSC8584_REVB_INT8051_FW); -MODULE_FIRMWARE(MSCC_VSC8574_REVB_INT8051_FW); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index e5b74485114675fae3cc291f1501a1cd06088c81..465e11dcdf12938d938a966b560a2fbbe20d6bd5 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -84,10 +84,9 @@ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, &buf, 4); - if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n", - index, ret); + if (unlikely(ret < 0)) { + netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n", + index, ret); return ret; } @@ -117,7 +116,7 @@ static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index, ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, &buf, 4); - if (ret < 0 && ret != -ENODEV) + if (unlikely(ret < 0)) netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n", index, ret); @@ -160,9 +159,6 @@ static int __must_check __smsc95xx_phy_wait_not_busy(struct usbnet *dev, do { ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm); if (ret < 0) { - /* Ignore -ENODEV error during disconnect() */ - if (ret == -ENODEV) - return 0; netdev_warn(dev->net, "Error reading MII_ACCESS\n"); return ret; } @@ -198,8 +194,7 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx, addr = mii_address_cmd(phy_id, idx, MII_READ_ | MII_BUSY_); ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error writing MII_ADDR\n"); + netdev_warn(dev->net, "Error writing MII_ADDR\n"); goto done; } @@ -211,8 +206,7 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx, ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error reading MII_DATA\n"); + netdev_warn(dev->net, "Error reading MII_DATA\n"); goto done; } @@ -220,10 +214,6 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx, done: mutex_unlock(&dev->phy_mutex); - - /* Ignore -ENODEV error during disconnect() */ - if (ret == -ENODEV) - return 0; return ret; } @@ -245,8 +235,7 @@ static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id, val = regval; ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error writing MII_DATA\n"); + netdev_warn(dev->net, "Error writing MII_DATA\n"); goto done; } @@ -254,8 +243,7 @@ static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id, addr = mii_address_cmd(phy_id, idx, MII_WRITE_ | MII_BUSY_); ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm); if (ret < 0) { - if (ret != -ENODEV) - netdev_warn(dev->net, "Error writing MII_ADDR\n"); + netdev_warn(dev->net, "Error writing MII_ADDR\n"); goto done; } @@ -1061,14 +1049,6 @@ static const struct net_device_ops smsc95xx_netdev_ops = { .ndo_set_features = smsc95xx_set_features, }; -static void smsc95xx_handle_link_change(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - phy_print_status(net->phydev); - usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); -} - static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) { struct smsc95xx_priv *pdata; @@ -1173,17 +1153,6 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->min_mtu = ETH_MIN_MTU; dev->net->max_mtu = ETH_DATA_LEN; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - - ret = phy_connect_direct(dev->net, pdata->phydev, - &smsc95xx_handle_link_change, - PHY_INTERFACE_MODE_MII); - if (ret) { - netdev_err(dev->net, "can't attach PHY to %s\n", pdata->mdiobus->id); - goto unregister_mdio; - } - - phy_attached_info(dev->net->phydev); - return 0; unregister_mdio: @@ -1201,25 +1170,47 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf) { struct smsc95xx_priv *pdata = dev->driver_priv; - phy_disconnect(dev->net->phydev); mdiobus_unregister(pdata->mdiobus); mdiobus_free(pdata->mdiobus); netif_dbg(dev, ifdown, dev->net, "free pdata\n"); kfree(pdata); } +static void smsc95xx_handle_link_change(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + phy_print_status(net->phydev); + usbnet_defer_kevent(dev, EVENT_LINK_CHANGE); +} + static int smsc95xx_start_phy(struct usbnet *dev) { - phy_start(dev->net->phydev); + struct smsc95xx_priv *pdata = dev->driver_priv; + struct net_device *net = dev->net; + int ret; + + ret = smsc95xx_reset(dev); + if (ret < 0) + return ret; + ret = phy_connect_direct(net, pdata->phydev, + &smsc95xx_handle_link_change, + PHY_INTERFACE_MODE_MII); + if (ret) { + netdev_err(net, "can't attach PHY to %s\n", pdata->mdiobus->id); + return ret; + } + + phy_attached_info(net->phydev); + phy_start(net->phydev); return 0; } -static int smsc95xx_stop(struct usbnet *dev) +static int smsc95xx_disconnect_phy(struct usbnet *dev) { - if (dev->net->phydev) - phy_stop(dev->net->phydev); - + phy_stop(dev->net->phydev); + phy_disconnect(dev->net->phydev); return 0; } @@ -1973,9 +1964,8 @@ static const struct driver_info smsc95xx_info = { .bind = smsc95xx_bind, .unbind = smsc95xx_unbind, .link_reset = smsc95xx_link_reset, - .reset = smsc95xx_reset, - .check_connect = smsc95xx_start_phy, - .stop = smsc95xx_stop, + .reset = smsc95xx_start_phy, + .stop = smsc95xx_disconnect_phy, .rx_fixup = smsc95xx_rx_fixup, .tx_fixup = smsc95xx_tx_fixup, .status = smsc95xx_status, diff --git a/drivers/net/wireguard/queueing.c b/drivers/net/wireguard/queueing.c index 8084e7408c0ae9065f57bc463921cb985fd68c5e..1de413b19e3424a2ace2edcbcf0d0d49c4be6167 100644 --- a/drivers/net/wireguard/queueing.c +++ b/drivers/net/wireguard/queueing.c @@ -4,7 +4,6 @@ */ #include "queueing.h" -#include struct multicore_worker __percpu * wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) @@ -43,7 +42,7 @@ void wg_packet_queue_free(struct crypt_queue *queue, bool purge) { free_percpu(queue->worker); WARN_ON(!purge && !__ptr_ring_empty(&queue->ring)); - ptr_ring_cleanup(&queue->ring, purge ? __skb_array_destroy_skb : NULL); + ptr_ring_cleanup(&queue->ring, purge ? (void(*)(void*))kfree_skb : NULL); } #define NEXT(skb) ((skb)->prev) diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c index 473221aa2236813d6188a078a7e38307cd0b59eb..52b9bc83abcbcca9007795fee738f1ad564e84e3 100644 --- a/drivers/net/wireguard/socket.c +++ b/drivers/net/wireguard/socket.c @@ -160,7 +160,6 @@ out: rcu_read_unlock_bh(); return ret; #else - kfree_skb(skb); return -EAFNOSUPPORT; #endif } @@ -242,7 +241,7 @@ int wg_socket_endpoint_from_skb(struct endpoint *endpoint, endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; endpoint->src4.s_addr = ip_hdr(skb)->daddr; endpoint->src_if4 = skb->skb_iif; - } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6)) { + } else if (skb->protocol == htons(ETH_P_IPV6)) { endpoint->addr6.sin6_family = AF_INET6; endpoint->addr6.sin6_port = udp_hdr(skb)->source; endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr; @@ -285,7 +284,7 @@ void wg_socket_set_peer_endpoint(struct wg_peer *peer, peer->endpoint.addr4 = endpoint->addr4; peer->endpoint.src4 = endpoint->src4; peer->endpoint.src_if4 = endpoint->src_if4; - } else if (IS_ENABLED(CONFIG_IPV6) && endpoint->addr.sa_family == AF_INET6) { + } else if (endpoint->addr.sa_family == AF_INET6) { peer->endpoint.addr6 = endpoint->addr6; peer->endpoint.src6 = endpoint->src6; } else { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index e5a296039f714a1d4a284402291d00a3318ecf42..daae470ecf5aa3f3495a623435d34a09111fa91d 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1477,11 +1477,11 @@ static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size) node = of_parse_phandle(dev->of_node, "memory-region", 0); if (node) { ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) { dev_err(dev, "failed to resolve msa fixed region\n"); return ret; } + of_node_put(node); ar->msa.paddr = r.start; ar->msa.mem_size = resource_size(&r); diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 20b9aa8ddf7d52e2574daf8d50a197ce6bc1f8b6..7d65c115669fe2a5f5d813884015b824552f4ad5 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -337,15 +337,14 @@ static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif, if (patterns[i].mask[j / 8] & BIT(j % 8)) bitmask[j] = 0xff; old_pattern.mask = bitmask; + new_pattern = old_pattern; if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) { - if (patterns[i].pkt_offset < ETH_HLEN) { + if (patterns[i].pkt_offset < ETH_HLEN) ath10k_wow_convert_8023_to_80211(&new_pattern, &old_pattern); - } else { - new_pattern = old_pattern; + else new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; - } } if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE)) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 994ec48b2f669588dbfe46c69611aad47aaebfbe..510e61e97dbcbd1dd2d4c1847d00f0afdbfd6385 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -30,7 +30,6 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, hdr->endpoint_id = epid; hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); - memset(hdr->control, 0, sizeof(hdr->control)); status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); @@ -273,10 +272,6 @@ int htc_connect_service(struct htc_target *target, conn_msg->dl_pipeid = endpoint->dl_pipeid; conn_msg->ul_pipeid = endpoint->ul_pipeid; - /* To prevent infoleak */ - conn_msg->svc_meta_len = 0; - conn_msg->pad = 0; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index b903b856bcf7b5547ed0d2771bcd3aefc3aa9a04..dbef9d8fc893b7350bccfd7b5b34fbdbf99ac9f5 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1916,7 +1916,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) WARN_ON(!(tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)); - tx_params |= (tx_streams - 1) << + tx_params = (tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; carl9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 20f4f8ea9f894c3ba1f21fce5f6d7505c1b44a06..bee9110b91f38620ef4b8f8c0e43f1c87698f808 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -666,14 +666,14 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, /* * Some users have reported their EEPROM programmed with - * 0x8000 set, this is not a supported regulatory domain - * but since we have more than one user with it we need - * a solution for them. We default to 0x64, which is the - * default Atheros world regulatory domain. + * 0x8000 or 0x0 set, this is not a supported regulatory + * domain but since we have more than one user with it we + * need a solution for them. We default to 0x64, which is + * the default Atheros world regulatory domain. */ static void ath_regd_sanitize(struct ath_regulatory *reg) { - if (reg->current_rd != COUNTRY_ERD_FLAG) + if (reg->current_rd != COUNTRY_ERD_FLAG && reg->current_rd != 0) return; printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n"); reg->current_rd = 0x64; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 37e6e49de3366b8a7176d1aa4fd2be9aabc4c549..9aaf6f74733336cbe842625821667068813323e9 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1362,9 +1362,6 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, if (iris_node) { if (of_device_is_compatible(iris_node, "qcom,wcn3620")) wcn->rf_id = RF_IRIS_WCN3620; - if (of_device_is_compatible(iris_node, "qcom,wcn3660") || - of_device_is_compatible(iris_node, "qcom,wcn3660b")) - wcn->rf_id = RF_IRIS_WCN3660; if (of_device_is_compatible(iris_node, "qcom,wcn3680")) wcn->rf_id = RF_IRIS_WCN3680; of_node_put(iris_node); diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 82be08265c06ca56efa586c0ce847258a3431084..5c40d0bdee2451245f0442da5077c5eed34699cc 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -96,7 +96,6 @@ enum wcn36xx_ampdu_state { #define RF_UNKNOWN 0x0000 #define RF_IRIS_WCN3620 0x3620 -#define RF_IRIS_WCN3660 0x3660 #define RF_IRIS_WCN3680 0x3680 static inline void buff_to_be(u32 *buf, size_t len) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index a2b8d9171af2abe41290eea365041be88076c062..d821a4758f8cf0d3df5f7092d7cda8478499d7ed 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -207,8 +207,6 @@ static int brcmf_init_nvram_parser(struct nvram_parser *nvp, size = BRCMF_FW_MAX_NVRAM_SIZE; else size = data_len; - /* Add space for properties we may add */ - size += strlen(BRCMF_FW_DEFAULT_BOARDREV) + 1; /* Alloc for extra 0 byte + roundup by 4 + length field */ size += 1 + 3 + sizeof(u32); nvp->nvram = kzalloc(size, GFP_KERNEL); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 61febc9bfa14ab344329e0255c1480079e2a691b..1f12dfb33938a9f64b9c2bdebbc729549dd39c40 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -447,6 +446,47 @@ brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, } +static void +brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, + void *srcaddr, u32 len) +{ + void __iomem *address = devinfo->tcm + mem_offset; + __le32 *src32; + __le16 *src16; + u8 *src8; + + if (((ulong)address & 4) || ((ulong)srcaddr & 4) || (len & 4)) { + if (((ulong)address & 2) || ((ulong)srcaddr & 2) || (len & 2)) { + src8 = (u8 *)srcaddr; + while (len) { + iowrite8(*src8, address); + address++; + src8++; + len--; + } + } else { + len = len / 2; + src16 = (__le16 *)srcaddr; + while (len) { + iowrite16(le16_to_cpu(*src16), address); + address += 2; + src16++; + len--; + } + } + } else { + len = len / 4; + src32 = (__le32 *)srcaddr; + while (len) { + iowrite32(le32_to_cpu(*src32), address); + address += 4; + src32++; + len--; + } + } +} + + static void brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, void *dstaddr, u32 len) @@ -1306,18 +1346,6 @@ static void brcmf_pcie_down(struct device *dev) { } -static int brcmf_pcie_preinit(struct device *dev) -{ - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; - - brcmf_dbg(PCIE, "Enter\n"); - - brcmf_pcie_intr_enable(buspub->devinfo); - brcmf_pcie_hostready(buspub->devinfo); - - return 0; -} static int brcmf_pcie_tx(struct device *dev, struct sk_buff *skb) { @@ -1426,7 +1454,6 @@ static int brcmf_pcie_reset(struct device *dev) } static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { - .preinit = brcmf_pcie_preinit, .txdata = brcmf_pcie_tx, .stop = brcmf_pcie_down, .txctl = brcmf_pcie_tx_ctlpkt, @@ -1534,8 +1561,8 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, return err; brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name); - memcpy_toio(devinfo->tcm + devinfo->ci->rambase, - (void *)fw->data, fw->size); + brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase, + (void *)fw->data, fw->size); resetintr = get_unaligned_le32(fw->data); release_firmware(fw); @@ -1549,7 +1576,7 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name); address = devinfo->ci->rambase + devinfo->ci->ramsize - nvram_len; - memcpy_toio(devinfo->tcm + address, nvram, nvram_len); + brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len); brcmf_fw_nvram_free(nvram); } else { brcmf_dbg(PCIE, "No matching NVRAM file found %s\n", @@ -1748,8 +1775,6 @@ static void brcmf_pcie_setup(struct device *dev, int ret, ret = brcmf_chip_get_raminfo(devinfo->ci); if (ret) { brcmf_err(bus, "Failed to get RAM info\n"); - release_firmware(fw); - brcmf_fw_nvram_free(nvram); goto fail; } @@ -1799,6 +1824,9 @@ static void brcmf_pcie_setup(struct device *dev, int ret, init_waitqueue_head(&devinfo->mbdata_resp_wait); + brcmf_pcie_intr_enable(devinfo); + brcmf_pcie_hostready(devinfo); + ret = brcmf_attach(&devinfo->pdev->dev); if (ret) goto fail; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 1e21cdbb7313b788a758ba1144c546f4895f6ae4..423d3c396b2d3f1047e4247b94ae7963ac730f22 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -304,7 +304,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); - return ret; + return 0; } static void iwlagn_mac_stop(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 54b28f0932e25709d32f649412ee12405ef5b0a6..6348dfa61724a6110923b9d06b0a65a36754b32c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1495,10 +1495,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) while (!sband && i < NUM_NL80211_BANDS) sband = mvm->hw->wiphy->bands[i++]; - if (WARN_ON_ONCE(!sband)) { - ret = -ENODEV; + if (WARN_ON_ONCE(!sband)) goto error; - } chan = &sband->channels[0]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index bdff89cc3105e6b51bbb27a04e5061b0062ac214..c9226dceb510c19eede46b476edd16d8ab39d7b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -618,9 +618,6 @@ mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); int i; - if (!sta_rates) - return; - spin_lock_bh(&dev->mt76.lock); for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx = sta_rates->rate[i].idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index defa207f53d6f5dbed3ce42c1e9305941d5182b4..88cdc2badeae7129d00bf301c7e1ab04abb620d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -673,9 +673,6 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); int i; - if (!sta_rates) - return; - spin_lock_bh(&dev->mt76.lock); for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx = sta_rates->rate[i].idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 41054ee43dbfad4aa007164ac694bad6178218be..9a7f317a098fc805ba661803d8eb456f051b807c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1259,11 +1259,8 @@ mt7915_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, generic = (struct wtbl_generic *)tlv; if (sta) { - if (vif->type == NL80211_IFTYPE_STATION) - generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); - else - generic->partial_aid = cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); + generic->partial_aid = cpu_to_le16(sta->aid); generic->muar_idx = mvif->omac_idx; generic->qos = sta->wme; } else { @@ -1317,15 +1314,12 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); - basic->aid = cpu_to_le16(sta->aid); break; case NL80211_IFTYPE_STATION: basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); - basic->aid = cpu_to_le16(vif->bss_conf.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - basic->aid = cpu_to_le16(sta->aid); break; default: WARN_ON(1); @@ -1333,6 +1327,7 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } memcpy(basic->peer_addr, sta->addr, ETH_ALEN); + basic->aid = cpu_to_le16(sta->aid); basic->qos = sta->wme; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 091eea0d958d1be13b632837f077fe75f7699fce..bf3fbd14eda3ccd8926f475f7b6f913ae59a124d 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -382,8 +382,6 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->sram = ioremap(link->resource[2]->start, resource_size(link->resource[2])); - if (!local->sram) - goto failed; /*** Set up 16k window for shared memory (receive buffer) ***************/ link->resource[3]->flags |= @@ -398,8 +396,6 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->rmem = ioremap(link->resource[3]->start, resource_size(link->resource[3])); - if (!local->rmem) - goto failed; /*** Set up window for attribute memory ***********************************/ link->resource[4]->flags |= @@ -414,8 +410,6 @@ static int ray_config(struct pcmcia_device *link) goto failed; local->amem = ioremap(link->resource[4]->start, resource_size(link->resource[4])); - if (!local->amem) - goto failed; dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c index 0841e0e370a03bf496b067c861829f21f19b0d84..c8bdf078d111522f4e7b5f0cc66ac57bbffc3647 100644 --- a/drivers/nfc/st21nfca/se.c +++ b/drivers/nfc/st21nfca/se.c @@ -320,11 +320,6 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, return -ENOMEM; transaction->aid_len = skb->data[1]; - - /* Checking if the length of the AID is valid */ - if (transaction->aid_len > sizeof(transaction->aid)) - return -EINVAL; - memcpy(transaction->aid, &skb->data[2], transaction->aid_len); @@ -334,11 +329,6 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, return -EPROTO; transaction->params_len = skb->data[transaction->aid_len + 3]; - - /* Total size is allocated (skb->len - 2) minus fixed array members */ - if (transaction->params_len > ((skb->len - 2) - sizeof(struct nfc_evt_transaction))) - return -EINVAL; - memcpy(transaction->params, skb->data + transaction->aid_len + 4, transaction->params_len); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 1d72653b5c8d172b56f55fe16741886c283a9e7a..e05cc9f8a9fd1bfe95e9965400e4fb72b7605cfe 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -1018,9 +1018,6 @@ static unsigned long default_align(struct nd_region *nd_region) } } - if (nd_region->ndr_size < MEMREMAP_COMPAT_ALIGN_MAX) - align = PAGE_SIZE; - mappings = max_t(u16, 1, nd_region->ndr_mappings); div_u64_rem(align, mappings, &remainder); if (remainder) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 853b9a24f744e318a8777caadc2117fe0a38399b..71c85c99e86c6c13dd0c1f79d872b32433a51d9b 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3681,15 +3681,16 @@ static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys, return NULL; } -static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys, - struct nvme_ns_ids *ids) +static int __nvme_check_ids(struct nvme_subsystem *subsys, + struct nvme_ns_head *new) { struct nvme_ns_head *h; lockdep_assert_held(&subsys->lock); list_for_each_entry(h, &subsys->nsheads, entry) { - if (nvme_ns_ids_valid(ids) && nvme_ns_ids_equal(ids, &h->ids)) + if (nvme_ns_ids_valid(&new->ids) && + nvme_ns_ids_equal(&new->ids, &h->ids)) return -EINVAL; } @@ -3723,7 +3724,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl, head->ids = *ids; kref_init(&head->ref); - ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, &head->ids); + ret = __nvme_check_ids(ctrl->subsys, head); if (ret) { dev_err(ctrl->device, "duplicate IDs for nsid %d\n", nsid); diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 7e3932033707282ddb27b3b912aa46924525832f..6105894a218a56575b7325c2fef80226fbde32bf 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -30,44 +30,6 @@ static int so_priority; module_param(so_priority, int, 0644); MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority"); -#ifdef CONFIG_DEBUG_LOCK_ALLOC -/* lockdep can detect a circular dependency of the form - * sk_lock -> mmap_lock (page fault) -> fs locks -> sk_lock - * because dependencies are tracked for both nvme-tcp and user contexts. Using - * a separate class prevents lockdep from conflating nvme-tcp socket use with - * user-space socket API use. - */ -static struct lock_class_key nvme_tcp_sk_key[2]; -static struct lock_class_key nvme_tcp_slock_key[2]; - -static void nvme_tcp_reclassify_socket(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (WARN_ON_ONCE(!sock_allow_reclassification(sk))) - return; - - switch (sk->sk_family) { - case AF_INET: - sock_lock_init_class_and_name(sk, "slock-AF_INET-NVME", - &nvme_tcp_slock_key[0], - "sk_lock-AF_INET-NVME", - &nvme_tcp_sk_key[0]); - break; - case AF_INET6: - sock_lock_init_class_and_name(sk, "slock-AF_INET6-NVME", - &nvme_tcp_slock_key[1], - "sk_lock-AF_INET6-NVME", - &nvme_tcp_sk_key[1]); - break; - default: - WARN_ON_ONCE(1); - } -} -#else -static void nvme_tcp_reclassify_socket(struct socket *sock) { } -#endif - enum nvme_tcp_send_state { NVME_TCP_SEND_CMD_PDU = 0, NVME_TCP_SEND_H2C_PDU, @@ -1460,8 +1422,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, goto err_destroy_mutex; } - nvme_tcp_reclassify_socket(queue->sock); - /* Single syn retry */ tcp_sock_set_syncnt(queue->sock->sk, 1); diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 9a8fa2e582d5be9dd080337bed03c5840a6d653e..f0f9d9007d49c8f4d3a3a6ccbdfd8a5453ecd31c 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1602,3 +1602,4 @@ module_init(nvmet_init); module_exit(nvmet_exit); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 8d0d1f61c650d43cb327d454389f8210f51c37b3..46935695cfb90867981d48a9042196ac7e4eaef3 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -160,12 +160,9 @@ int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, * write happen to have any RW1C (write-one-to-clear) bits set, we * just inadvertently cleared something we shouldn't have. */ - if (!bus->unsafe_warn) { - dev_warn(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", - size, pci_domain_nr(bus), bus->number, - PCI_SLOT(devfn), PCI_FUNC(devfn), where); - bus->unsafe_warn = 1; - } + dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", + size, pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where); mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); tmp = readl(addr) & mask; diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 49ff8bf10c7409d191f4750ced9a299ed57d60df..f30144c8c0bd2c6ae5adf93a7837c10e80d08e97 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -851,9 +851,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, case PCI_EXP_RTSTA: { u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG); u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG); - *value = msglog >> 16; - if (isr0 & PCIE_MSG_PM_PME_MASK) - *value |= PCI_EXP_RTSTA_PME; + *value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16); return PCI_BRIDGE_EMUL_HANDLED; } diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pci-xgene.c index e1c2daa50b4987d5668cb65fb15d5e6330022445..b651b6f4446917855d92875df4c6f93ce55aed10 100644 --- a/drivers/pci/controller/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c @@ -467,7 +467,7 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) return 1; } - if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) { + if ((size > SZ_1K) && (size < SZ_4G) && !(*ib_reg_mask & (1 << 0))) { *ib_reg_mask |= (1 << 0); return 0; } @@ -481,27 +481,28 @@ static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) } static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, - struct of_pci_range *range, u8 *ib_reg_mask) + struct resource_entry *entry, + u8 *ib_reg_mask) { void __iomem *cfg_base = port->cfg_base; struct device *dev = port->dev; void *bar_addr; u32 pim_reg; - u64 cpu_addr = range->cpu_addr; - u64 pci_addr = range->pci_addr; - u64 size = range->size; + u64 cpu_addr = entry->res->start; + u64 pci_addr = cpu_addr - entry->offset; + u64 size = resource_size(entry->res); u64 mask = ~(size - 1) | EN_REG; u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64; u32 bar_low; int region; - region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size); + region = xgene_pcie_select_ib_reg(ib_reg_mask, size); if (region < 0) { dev_warn(dev, "invalid pcie dma-range config\n"); return; } - if (range->flags & IORESOURCE_PREFETCH) + if (entry->res->flags & IORESOURCE_PREFETCH) flags |= PCI_BASE_ADDRESS_MEM_PREFETCH; bar_low = pcie_bar_low_val((u32)cpu_addr, flags); @@ -532,25 +533,13 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) { - struct device_node *np = port->node; - struct of_pci_range range; - struct of_pci_range_parser parser; - struct device *dev = port->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(port); + struct resource_entry *entry; u8 ib_reg_mask = 0; - if (of_pci_dma_range_parser_init(&parser, np)) { - dev_err(dev, "missing dma-ranges property\n"); - return -EINVAL; - } - - /* Get the dma-ranges from DT */ - for_each_of_pci_range(&parser, &range) { - u64 end = range.cpu_addr + range.size - 1; + resource_list_for_each_entry(entry, &bridge->dma_ranges) + xgene_pcie_setup_ib_reg(port, entry, &ib_reg_mask); - dev_dbg(dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", - range.flags, range.cpu_addr, end, range.pci_addr); - xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); - } return 0; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index af4c4cc837fcd7069f2920e35a31fc284c0cda11..30708af975adc6383fc496088c09bccd475eebce 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -98,8 +98,6 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout) if (slot_status & PCI_EXP_SLTSTA_CC) { pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); - ctrl->cmd_busy = 0; - smp_mb(); return 1; } msleep(10); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0d7109018a91f50da0f041d1b840a4a8551fd702..fbb4d765b43c8349a5fb0c0befd30216bc7d48db 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "pci.h" DEFINE_MUTEX(pci_slot_mutex); @@ -68,8 +69,11 @@ static void pci_dev_d3_sleep(struct pci_dev *dev) if (delay < pci_pm_d3hot_delay) delay = pci_pm_d3hot_delay; - if (delay) - msleep(delay); + if (delay) { + trace_android_rvh_pci_d3_sleep(dev, &delay); + if (delay) + msleep(delay); + } } #ifdef CONFIG_PCI_DOMAINS diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 52d454ec9bd2918885fd0076635c81d85ed0d0dc..d6974502d9622399e1172f45b956a80c9277e74c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1816,18 +1816,6 @@ static void quirk_alder_ioapic(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic); #endif -static void quirk_no_msi(struct pci_dev *dev) -{ - pci_info(dev, "avoiding MSI to work around a hardware defect\n"); - dev->no_msi = 1; -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4386, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4387, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4388, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4389, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438a, quirk_no_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x438b, quirk_no_msi); - static void quirk_pcie_mch(struct pci_dev *pdev) { pdev->no_msi = 1; diff --git a/drivers/phy/phy-core-mipi-dphy.c b/drivers/phy/phy-core-mipi-dphy.c index 0aa740b73d0db06adc659a4ef519d6f0a564e890..14e0551cd3190f71aeb85f0318c3d71c455836de 100644 --- a/drivers/phy/phy-core-mipi-dphy.c +++ b/drivers/phy/phy-core-mipi-dphy.c @@ -66,10 +66,10 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock, cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui); cfg->init = 100; - cfg->lpx = 50000; + cfg->lpx = 60000; cfg->ta_get = 5 * cfg->lpx; cfg->ta_go = 4 * cfg->lpx; - cfg->ta_sure = cfg->lpx; + cfg->ta_sure = 2 * cfg->lpx; cfg->wakeup = 1000; cfg->hs_clk_rate = hs_clk_rate; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 730581d130649bcf5878b7682b3125e666376f57..a02ad10ec6fada549a1f03d2903d6c11da1aa4aa 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1039,7 +1039,6 @@ int mtk_pctrl_init(struct platform_device *pdev, node = of_parse_phandle(np, "mediatek,pctl-regmap", 0); if (node) { pctl->regmap1 = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(pctl->regmap1)) return PTR_ERR(pctl->regmap1); } else if (regmap) { @@ -1053,7 +1052,6 @@ int mtk_pctrl_init(struct platform_device *pdev, node = of_parse_phandle(np, "mediatek,pctl-regmap", 1); if (node) { pctl->regmap2 = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(pctl->regmap2)) return PTR_ERR(pctl->regmap2); } diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c index d0a4ebbe1e7e65f6e04532bc02f8101afbb3fbd1..623af4410b07c70d6d011c775cb692d7f8fbd5bd 100644 --- a/drivers/pinctrl/mediatek/pinctrl-paris.c +++ b/drivers/pinctrl/mediatek/pinctrl-paris.c @@ -96,16 +96,20 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); if (err) goto out; - if (ret == MTK_PUPD_SET_R1R0_00) - ret = MTK_DISABLE; if (param == PIN_CONFIG_BIAS_DISABLE) { - if (ret != MTK_DISABLE) - err = -EINVAL; + if (ret == MTK_PUPD_SET_R1R0_00) + ret = MTK_DISABLE; } else if (param == PIN_CONFIG_BIAS_PULL_UP) { - if (!pullup || ret == MTK_DISABLE) + /* When desire to get pull-up value, return + * error if current setting is pull-down + */ + if (!pullup) err = -EINVAL; } else if (param == PIN_CONFIG_BIAS_PULL_DOWN) { - if (pullup || ret == MTK_DISABLE) + /* When desire to get pull-down value, return + * error if current setting is pull-up + */ + if (pullup) err = -EINVAL; } } else { @@ -184,7 +188,8 @@ out: } static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - enum pin_config_param param, u32 arg) + enum pin_config_param param, + enum pin_config_param arg) { struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); const struct mtk_pin_desc *desc; @@ -580,9 +585,6 @@ ssize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw, if (gpio >= hw->soc->npins) return -EINVAL; - if (mtk_is_virt_gpio(hw, gpio)) - return -EINVAL; - desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; pinmux = mtk_pctrl_get_pinmux(hw, gpio); if (pinmux >= hw->soc->nfuncs) @@ -717,10 +719,10 @@ static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, unsigned long *config) { struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - struct mtk_pinctrl_group *grp = &hw->groups[group]; - /* One pin per group only */ - return mtk_pinconf_get(pctldev, grp->pin, config); + *config = hw->groups[group].config; + + return 0; } static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, @@ -736,6 +738,8 @@ static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, pinconf_to_config_argument(configs[i])); if (ret < 0) return ret; + + grp->config = configs[i]; } return 0; diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 6d77feda9090a9ec6af22ef545ef785bd53a5dbf..657e35a75d84aad961606193d5bb089401127872 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1883,10 +1883,8 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) } prcm_np = of_parse_phandle(np, "prcm", 0); - if (prcm_np) { + if (prcm_np) npct->prcm_base = of_iomap(prcm_np, 0); - of_node_put(prcm_np); - } if (!npct->prcm_base) { if (version == PINCTRL_NMK_STN8815) { dev_info(&pdev->dev, diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index ce36b6ff7b95e4668b7aa8fb77aca0a32cda402a..6de31b5ee358c62adfd1672c0120d015bee3e129 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -78,6 +78,7 @@ struct npcm7xx_gpio { struct gpio_chip gc; int irqbase; int irq; + void *priv; struct irq_chip irq_chip; u32 pinctrl_id; int (*direction_input)(struct gpio_chip *chip, unsigned offset); @@ -225,7 +226,7 @@ static void npcmgpio_irq_handler(struct irq_desc *desc) chained_irq_enter(chip, desc); sts = ioread32(bank->base + NPCM7XX_GP_N_EVST); en = ioread32(bank->base + NPCM7XX_GP_N_EVEN); - dev_dbg(bank->gc.parent, "==> got irq sts %.8x %.8x\n", sts, + dev_dbg(chip->parent_device, "==> got irq sts %.8x %.8x\n", sts, en); sts &= en; @@ -240,33 +241,33 @@ static int npcmgpio_set_irq_type(struct irq_data *d, unsigned int type) gpiochip_get_data(irq_data_get_irq_chip_data(d)); unsigned int gpio = BIT(d->hwirq); - dev_dbg(bank->gc.parent, "setirqtype: %u.%u = %u\n", gpio, + dev_dbg(d->chip->parent_device, "setirqtype: %u.%u = %u\n", gpio, d->irq, type); switch (type) { case IRQ_TYPE_EDGE_RISING: - dev_dbg(bank->gc.parent, "edge.rising\n"); + dev_dbg(d->chip->parent_device, "edge.rising\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_FALLING: - dev_dbg(bank->gc.parent, "edge.falling\n"); + dev_dbg(d->chip->parent_device, "edge.falling\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_EDGE_BOTH: - dev_dbg(bank->gc.parent, "edge.both\n"); + dev_dbg(d->chip->parent_device, "edge.both\n"); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_EVBE, gpio); break; case IRQ_TYPE_LEVEL_LOW: - dev_dbg(bank->gc.parent, "level.low\n"); + dev_dbg(d->chip->parent_device, "level.low\n"); npcm_gpio_set(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; case IRQ_TYPE_LEVEL_HIGH: - dev_dbg(bank->gc.parent, "level.high\n"); + dev_dbg(d->chip->parent_device, "level.high\n"); npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_POL, gpio); break; default: - dev_dbg(bank->gc.parent, "invalid irq type\n"); + dev_dbg(d->chip->parent_device, "invalid irq type\n"); return -EINVAL; } @@ -288,7 +289,7 @@ static void npcmgpio_irq_ack(struct irq_data *d) gpiochip_get_data(irq_data_get_irq_chip_data(d)); unsigned int gpio = d->hwirq; - dev_dbg(bank->gc.parent, "irq_ack: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "irq_ack: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVST); } @@ -300,7 +301,7 @@ static void npcmgpio_irq_mask(struct irq_data *d) unsigned int gpio = d->hwirq; /* Clear events */ - dev_dbg(bank->gc.parent, "irq_mask: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "irq_mask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENC); } @@ -312,7 +313,7 @@ static void npcmgpio_irq_unmask(struct irq_data *d) unsigned int gpio = d->hwirq; /* Enable events */ - dev_dbg(bank->gc.parent, "irq_unmask: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "irq_unmask: %u.%u\n", gpio, d->irq); iowrite32(BIT(gpio), bank->base + NPCM7XX_GP_N_EVENS); } @@ -322,7 +323,7 @@ static unsigned int npcmgpio_irq_startup(struct irq_data *d) unsigned int gpio = d->hwirq; /* active-high, input, clear interrupt, enable interrupt */ - dev_dbg(gc->parent, "startup: %u.%u\n", gpio, d->irq); + dev_dbg(d->chip->parent_device, "startup: %u.%u\n", gpio, d->irq); npcmgpio_direction_input(gc, gpio); npcmgpio_irq_ack(d); npcmgpio_irq_unmask(d); @@ -904,7 +905,7 @@ static struct npcm7xx_func npcm7xx_funcs[] = { #define DRIVE_STRENGTH_HI_SHIFT 12 #define DRIVE_STRENGTH_MASK 0x0000FF00 -#define DSTR(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ +#define DS(lo, hi) (((lo) << DRIVE_STRENGTH_LO_SHIFT) | \ ((hi) << DRIVE_STRENGTH_HI_SHIFT)) #define DSLO(x) (((x) >> DRIVE_STRENGTH_LO_SHIFT) & 0xF) #define DSHI(x) (((x) >> DRIVE_STRENGTH_HI_SHIFT) & 0xF) @@ -924,31 +925,31 @@ struct npcm7xx_pincfg { static const struct npcm7xx_pincfg pincfg[] = { /* PIN FUNCTION 1 FUNCTION 2 FUNCTION 3 FLAGS */ NPCM7XX_PINCFG(0, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(1, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(2, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(3, iox1, MFSEL1, 30, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(4, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW), NPCM7XX_PINCFG(5, iox2, MFSEL3, 14, smb1d, I2CSEGSEL, 7, none, NONE, 0, SLEW), NPCM7XX_PINCFG(6, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW), NPCM7XX_PINCFG(7, iox2, MFSEL3, 14, smb2d, I2CSEGSEL, 10, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(8, lkgpo1, FLOCKR1, 4, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(9, lkgpo2, FLOCKR1, 8, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(10, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(11, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(12, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW), NPCM7XX_PINCFG(13, gspi, MFSEL1, 24, smb5b, I2CSEGSEL, 19, none, NONE, 0, SLEW), NPCM7XX_PINCFG(14, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW), NPCM7XX_PINCFG(15, gspi, MFSEL1, 24, smb5c, I2CSEGSEL, 20, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(16, lkgpo0, FLOCKR1, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(17, pspi2, MFSEL3, 13, smb4den, I2CSEGSEL, 23, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(18, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(19, pspi2, MFSEL3, 13, smb4b, I2CSEGSEL, 14, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(20, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0), NPCM7XX_PINCFG(21, smb4c, I2CSEGSEL, 15, smb15, MFSEL3, 8, none, NONE, 0, 0), NPCM7XX_PINCFG(22, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0), NPCM7XX_PINCFG(23, smb4d, I2CSEGSEL, 16, smb14, MFSEL3, 7, none, NONE, 0, 0), - NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(24, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(25, ioxh, MFSEL3, 18, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(26, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(27, smb5, MFSEL1, 2, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(28, smb4, MFSEL1, 1, none, NONE, 0, none, NONE, 0, 0), @@ -964,12 +965,12 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(39, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW), NPCM7XX_PINCFG(40, smb3b, I2CSEGSEL, 11, none, NONE, 0, none, NONE, 0, SLEW), NPCM7XX_PINCFG(41, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, DSTR(2, 4) | GPO), + NPCM7XX_PINCFG(42, bmcuart0a, MFSEL1, 9, none, NONE, 0, none, NONE, 0, DS(2, 4) | GPO), NPCM7XX_PINCFG(43, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0), NPCM7XX_PINCFG(44, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, bmcuart1, MFSEL3, 24, 0), NPCM7XX_PINCFG(45, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DSTR(2, 8)), - NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DSTR(2, 8)), + NPCM7XX_PINCFG(46, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)), + NPCM7XX_PINCFG(47, uart1, MFSEL1, 10, jtag2, MFSEL4, 0, none, NONE, 0, DS(2, 8)), NPCM7XX_PINCFG(48, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, GPO), NPCM7XX_PINCFG(49, uart2, MFSEL1, 11, bmcuart0b, MFSEL4, 1, none, NONE, 0, 0), NPCM7XX_PINCFG(50, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), @@ -979,8 +980,8 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(54, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(55, uart2, MFSEL1, 11, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(56, r1err, MFSEL1, 12, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), - NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0, none, NONE, 0, DS(2, 4)), NPCM7XX_PINCFG(59, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(60, smb3d, I2CSEGSEL, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(61, uart1, MFSEL1, 10, none, NONE, 0, none, NONE, 0, GPO), @@ -1003,19 +1004,19 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(77, fanin13, MFSEL2, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(78, fanin14, MFSEL2, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(79, fanin15, MFSEL2, 15, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(84, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(85, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(86, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(87, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(88, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(89, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(90, r2err, MFSEL1, 15, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), - NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DSTR(2, 4)), + NPCM7XX_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0, none, NONE, 0, DS(2, 4)), NPCM7XX_PINCFG(93, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0), NPCM7XX_PINCFG(94, ga20kbc, MFSEL1, 17, smb5d, I2CSEGSEL, 21, none, NONE, 0, 0), NPCM7XX_PINCFG(95, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0), @@ -1061,34 +1062,34 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(133, smb10, MFSEL4, 13, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(134, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(135, smb11, MFSEL4, 14, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(136, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(137, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(138, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(139, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(140, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(141, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(142, sd1, MFSEL3, 12, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(143, sd1, MFSEL3, 12, sd1pwr, MFSEL4, 5, none, NONE, 0, 0), - NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(144, pwm4, MFSEL2, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(145, pwm5, MFSEL2, 21, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(146, pwm6, MFSEL2, 22, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(147, pwm7, MFSEL2, 23, none, NONE, 0, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(148, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(149, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(150, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(151, mmc8, MFSEL3, 11, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(152, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(153, mmcwp, FLOCKR1, 24, none, NONE, 0, none, NONE, 0, 0), /* Z1/A1 */ - NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(154, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(155, mmccd, MFSEL3, 25, mmcrst, MFSEL4, 6, none, NONE, 0, 0), /* Z1/A1 */ - NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - - NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, DSTR(8, 12)), - NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(156, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(157, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(158, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(159, mmc, MFSEL3, 10, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + + NPCM7XX_PINCFG(160, clkout, MFSEL1, 21, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(161, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, DS(8, 12)), + NPCM7XX_PINCFG(162, serirq, NONE, 0, gpio, MFSEL1, 31, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(163, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, 0), NPCM7XX_PINCFG(164, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), NPCM7XX_PINCFG(165, lpc, NONE, 0, espi, MFSEL4, 8, gpio, MFSEL1, 26, SLEWLPC), @@ -1101,25 +1102,25 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(172, smb6, MFSEL3, 1, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(173, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(174, smb7, MFSEL3, 2, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), + NPCM7XX_PINCFG(175, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(176, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(177, pspi1, MFSEL3, 4, faninx, MFSEL3, 3, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(178, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(179, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(180, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), NPCM7XX_PINCFG(181, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(182, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), - NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NONE, 0, DSTR(2, 4)), - NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), /* XX */ - - NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), /* XX */ + NPCM7XX_PINCFG(183, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(184, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(185, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(186, spi3, MFSEL4, 16, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(187, spi3cs1, MFSEL4, 17, none, NONE, 0, none, NONE, 0, DS(8, 12)), + NPCM7XX_PINCFG(188, spi3quad, MFSEL4, 20, spi3cs2, MFSEL4, 18, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(189, spi3quad, MFSEL4, 20, spi3cs3, MFSEL4, 19, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(190, gpio, FLOCKR1, 20, nprd_smi, NONE, 0, none, NONE, 0, DS(2, 4)), + NPCM7XX_PINCFG(191, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */ + + NPCM7XX_PINCFG(192, none, NONE, 0, none, NONE, 0, none, NONE, 0, DS(8, 12)), /* XX */ NPCM7XX_PINCFG(193, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(194, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(195, smb0b, I2CSEGSEL, 0, none, NONE, 0, none, NONE, 0, 0), @@ -1130,11 +1131,11 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(200, r2, MFSEL1, 14, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(201, r1, MFSEL3, 9, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(202, smb0c, I2CSEGSEL, 1, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(203, faninx, MFSEL3, 3, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(204, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW), NPCM7XX_PINCFG(205, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DSTR(4, 8)), - NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DSTR(4, 8)), + NPCM7XX_PINCFG(206, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)), + NPCM7XX_PINCFG(207, ddc, NONE, 0, gpio, MFSEL3, 22, none, NONE, 0, DS(4, 8)), NPCM7XX_PINCFG(208, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(209, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(210, rg2, MFSEL4, 24, ddr, MFSEL3, 26, none, NONE, 0, 0), @@ -1146,20 +1147,20 @@ static const struct npcm7xx_pincfg pincfg[] = { NPCM7XX_PINCFG(216, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(217, rg2mdio, MFSEL4, 23, ddr, MFSEL3, 26, none, NONE, 0, 0), NPCM7XX_PINCFG(218, wdog1, MFSEL3, 19, none, NONE, 0, none, NONE, 0, 0), - NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NONE, 0, DSTR(4, 8)), + NPCM7XX_PINCFG(219, wdog2, MFSEL3, 20, none, NONE, 0, none, NONE, 0, DS(4, 8)), NPCM7XX_PINCFG(220, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(221, smb12, MFSEL3, 5, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(222, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(223, smb13, MFSEL3, 6, none, NONE, 0, none, NONE, 0, 0), NPCM7XX_PINCFG(224, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, SLEW), - NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW | GPO), - NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DSTR(8, 12) | SLEW), - NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, none, NONE, 0, DSTR(8, 12)), + NPCM7XX_PINCFG(225, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(226, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW | GPO), + NPCM7XX_PINCFG(227, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(228, spixcs1, MFSEL4, 28, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(229, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(230, spix, MFSEL4, 27, none, NONE, 0, none, NONE, 0, DS(8, 12) | SLEW), + NPCM7XX_PINCFG(231, clkreq, MFSEL4, 9, none, NONE, 0, none, NONE, 0, DS(8, 12)), NPCM7XX_PINCFG(253, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC1 power */ NPCM7XX_PINCFG(254, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* SDHC2 power */ NPCM7XX_PINCFG(255, none, NONE, 0, none, NONE, 0, none, NONE, 0, GPI), /* DACOSEL */ @@ -1560,7 +1561,7 @@ static int npcm7xx_get_groups_count(struct pinctrl_dev *pctldev) { struct npcm7xx_pinctrl *npcm = pinctrl_dev_get_drvdata(pctldev); - dev_dbg(npcm->dev, "group size: %zu\n", ARRAY_SIZE(npcm7xx_groups)); + dev_dbg(npcm->dev, "group size: %d\n", ARRAY_SIZE(npcm7xx_groups)); return ARRAY_SIZE(npcm7xx_groups); } diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 42e27dba62e26292554cb9b5c6b7f3414c48b6f3..1e225d513988857391264d4155a9bf014f5b0c09 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -30,10 +30,10 @@ static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", "ohms", true), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, - "input bias pull to pin specific state", "ohms", true), - PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", "ohms", true), + "input bias pull to pin specific state", NULL, false), + PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 9df48e0cf4cb4c028ac66b20177396a8068e1f15..53a0badc6b035e4afd24e2d285f6e23755b65be4 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -3774,7 +3774,6 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) node = of_parse_phandle(np, "rockchip,grf", 0); if (node) { info->regmap_base = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(info->regmap_base)) return PTR_ERR(info->regmap_base); } else { @@ -3811,7 +3810,6 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) node = of_parse_phandle(np, "rockchip,pmu", 0); if (node) { info->regmap_pmu = syscon_node_to_regmap(node); - of_node_put(node); if (IS_ERR(info->regmap_pmu)) return PTR_ERR(info->regmap_pmu); } diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c index 258972672eda1077871df9e3db2deb015397e076..9d168b90cd2810e7ae5eb3813ae0dfe5e58e88b7 100644 --- a/drivers/pinctrl/renesas/core.c +++ b/drivers/pinctrl/renesas/core.c @@ -739,7 +739,7 @@ static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; } #ifdef DEBUG #define SH_PFC_MAX_REGS 300 -#define SH_PFC_MAX_ENUMS 5000 +#define SH_PFC_MAX_ENUMS 3000 static unsigned int sh_pfc_errors __initdata = 0; static unsigned int sh_pfc_warnings __initdata = 0; @@ -851,8 +851,7 @@ static void __init sh_pfc_check_cfg_reg(const char *drvname, sh_pfc_check_reg(drvname, cfg_reg->reg); if (cfg_reg->field_width) { - fw = cfg_reg->field_width; - n = (cfg_reg->reg_width / fw) << fw; + n = cfg_reg->reg_width / cfg_reg->field_width; /* Skip field checks (done at build time) */ goto check_enum_ids; } diff --git a/drivers/pinctrl/renesas/pfc-r8a77470.c b/drivers/pinctrl/renesas/pfc-r8a77470.c index 14005725a726b1c7fa9d46bb27da2bbde68de6a2..b3b116da1bb0dd3521fa2a619133e776079d6d2e 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77470.c +++ b/drivers/pinctrl/renesas/pfc-r8a77470.c @@ -2121,7 +2121,7 @@ static const unsigned int vin0_clk_mux[] = { VI0_CLK_MARK, }; /* - VIN1 ------------------------------------------------------------------- */ -static const union vin_data12 vin1_data_pins = { +static const union vin_data vin1_data_pins = { .data12 = { RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4), @@ -2131,7 +2131,7 @@ static const union vin_data12 vin1_data_pins = { RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 16), }, }; -static const union vin_data12 vin1_data_mux = { +static const union vin_data vin1_data_mux = { .data12 = { VI1_DATA0_MARK, VI1_DATA1_MARK, VI1_DATA2_MARK, VI1_DATA3_MARK, diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 56fff83a143bda97c4379e82b99b9b888e0ce84f..7f809a57bee50db67cab65e22fef2654220d7f8a 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1002,16 +1002,6 @@ samsung_pinctrl_get_soc_data_for_of_alias(struct platform_device *pdev) return &(of_data->ctrl[id]); } -static void samsung_banks_of_node_put(struct samsung_pinctrl_drv_data *d) -{ - struct samsung_pin_bank *bank; - unsigned int i; - - bank = d->pin_banks; - for (i = 0; i < d->nr_banks; ++i, ++bank) - of_node_put(bank->of_node); -} - /* retrieve the soc specific data */ static const struct samsung_pin_ctrl * samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, @@ -1126,19 +1116,19 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) if (ctrl->retention_data) { drvdata->retention_ctrl = ctrl->retention_data->init(drvdata, ctrl->retention_data); - if (IS_ERR(drvdata->retention_ctrl)) { - ret = PTR_ERR(drvdata->retention_ctrl); - goto err_put_banks; - } + if (IS_ERR(drvdata->retention_ctrl)) + return PTR_ERR(drvdata->retention_ctrl); } ret = samsung_pinctrl_register(pdev, drvdata); if (ret) - goto err_put_banks; + return ret; ret = samsung_gpiolib_register(pdev, drvdata); - if (ret) - goto err_unregister; + if (ret) { + samsung_pinctrl_unregister(pdev, drvdata); + return ret; + } if (ctrl->eint_gpio_init) ctrl->eint_gpio_init(drvdata); @@ -1148,12 +1138,6 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drvdata); return 0; - -err_unregister: - samsung_pinctrl_unregister(pdev, drvdata); -err_put_banks: - samsung_banks_of_node_put(drvdata); - return ret; } /* diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 88cbc434c06b224b07c3b5d1cdc3fac7d2a8b9f9..f901d2e43166c339971aed719f8d749026dd4ad1 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -2,7 +2,6 @@ # tell define_trace.h where to find the cros ec trace header CFLAGS_cros_ec_trace.o:= -I$(src) -CFLAGS_cros_ec_sensorhub_ring.o:= -I$(src) obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o @@ -21,7 +20,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_chardev.o obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o -cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o +cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o cros_ec_trace.o obj-$(CONFIG_CROS_EC_SENSORHUB) += cros-ec-sensorhub.o obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c index 71948dade0e2aedd0a1f1b4ea09dc954c6fb5b5e..98e37080f760913ecdbeb53f611ce71cfbecbc7f 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -17,8 +17,7 @@ #include #include -#define CREATE_TRACE_POINTS -#include "cros_ec_sensorhub_trace.h" +#include "cros_ec_trace.h" /* Precision of fixed point for the m values from the filter */ #define M_PRECISION BIT(23) diff --git a/drivers/platform/chrome/cros_ec_sensorhub_trace.h b/drivers/platform/chrome/cros_ec_sensorhub_trace.h deleted file mode 100644 index 57d9b47859692710b2048007524a01457a2bca48..0000000000000000000000000000000000000000 --- a/drivers/platform/chrome/cros_ec_sensorhub_trace.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Trace events for the ChromeOS Sensorhub kernel module - * - * Copyright 2021 Google LLC. - */ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM cros_ec - -#if !defined(_CROS_EC_SENSORHUB_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) -#define _CROS_EC_SENSORHUB_TRACE_H_ - -#include -#include - -#include - -TRACE_EVENT(cros_ec_sensorhub_timestamp, - TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_timestamp, - s64 current_timestamp, s64 current_time), - TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_timestamp, - current_time), - TP_STRUCT__entry( - __field(u32, ec_sample_timestamp) - __field(u32, ec_fifo_timestamp) - __field(s64, fifo_timestamp) - __field(s64, current_timestamp) - __field(s64, current_time) - __field(s64, delta) - ), - TP_fast_assign( - __entry->ec_sample_timestamp = ec_sample_timestamp; - __entry->ec_fifo_timestamp = ec_fifo_timestamp; - __entry->fifo_timestamp = fifo_timestamp; - __entry->current_timestamp = current_timestamp; - __entry->current_time = current_time; - __entry->delta = current_timestamp - current_time; - ), - TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", - __entry->ec_sample_timestamp, - __entry->ec_fifo_timestamp, - __entry->fifo_timestamp, - __entry->current_timestamp, - __entry->current_time, - __entry->delta - ) -); - -TRACE_EVENT(cros_ec_sensorhub_data, - TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, - s64 current_timestamp, s64 current_time), - TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timestamp, current_time), - TP_STRUCT__entry( - __field(u32, ec_sensor_num) - __field(u32, ec_fifo_timestamp) - __field(s64, fifo_timestamp) - __field(s64, current_timestamp) - __field(s64, current_time) - __field(s64, delta) - ), - TP_fast_assign( - __entry->ec_sensor_num = ec_sensor_num; - __entry->ec_fifo_timestamp = ec_fifo_timestamp; - __entry->fifo_timestamp = fifo_timestamp; - __entry->current_timestamp = current_timestamp; - __entry->current_time = current_time; - __entry->delta = current_timestamp - current_time; - ), - TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", - __entry->ec_sensor_num, - __entry->ec_fifo_timestamp, - __entry->fifo_timestamp, - __entry->current_timestamp, - __entry->current_time, - __entry->delta - ) -); - -TRACE_EVENT(cros_ec_sensorhub_filter, - TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 dy), - TP_ARGS(state, dx, dy), - TP_STRUCT__entry( - __field(s64, dx) - __field(s64, dy) - __field(s64, median_m) - __field(s64, median_error) - __field(s64, history_len) - __field(s64, x) - __field(s64, y) - ), - TP_fast_assign( - __entry->dx = dx; - __entry->dy = dy; - __entry->median_m = state->median_m; - __entry->median_error = state->median_error; - __entry->history_len = state->history_len; - __entry->x = state->x_offset; - __entry->y = state->y_offset; - ), - TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld len: %lld x: %12lld y: %12lld", - __entry->dx, - __entry->dy, - __entry->median_m, - __entry->median_error, - __entry->history_len, - __entry->x, - __entry->y - ) -); - - -#endif /* _CROS_EC_SENSORHUB_TRACE_H_ */ - -/* this part must be outside header guard */ - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . - -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE cros_ec_sensorhub_trace - -#include diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chrome/cros_ec_trace.h index 9bb5cd2c98b8b4690f4633883103c21a801ba04d..7e7cfc98657a4aea599e93efb75094f6df4c4144 100644 --- a/drivers/platform/chrome/cros_ec_trace.h +++ b/drivers/platform/chrome/cros_ec_trace.h @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -70,6 +71,100 @@ TRACE_EVENT(cros_ec_request_done, __entry->retval) ); +TRACE_EVENT(cros_ec_sensorhub_timestamp, + TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_timestamp, + current_time), + TP_STRUCT__entry( + __field(u32, ec_sample_timestamp) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sample_timestamp = ec_sample_timestamp; + __entry->ec_fifo_timestamp = ec_fifo_timestamp; + __entry->fifo_timestamp = fifo_timestamp; + __entry->current_timestamp = current_timestamp; + __entry->current_time = current_time; + __entry->delta = current_timestamp - current_time; + ), + TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", + __entry->ec_sample_timestamp, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_data, + TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timestamp, current_time), + TP_STRUCT__entry( + __field(u32, ec_sensor_num) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sensor_num = ec_sensor_num; + __entry->ec_fifo_timestamp = ec_fifo_timestamp; + __entry->fifo_timestamp = fifo_timestamp; + __entry->current_timestamp = current_timestamp; + __entry->current_time = current_time; + __entry->delta = current_timestamp - current_time; + ), + TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", + __entry->ec_sensor_num, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_filter, + TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 dy), + TP_ARGS(state, dx, dy), + TP_STRUCT__entry( + __field(s64, dx) + __field(s64, dy) + __field(s64, median_m) + __field(s64, median_error) + __field(s64, history_len) + __field(s64, x) + __field(s64, y) + ), + TP_fast_assign( + __entry->dx = dx; + __entry->dy = dy; + __entry->median_m = state->median_m; + __entry->median_error = state->median_error; + __entry->history_len = state->history_len; + __entry->x = state->x_offset; + __entry->y = state->y_offset; + ), + TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld len: %lld x: %12lld y: %12lld", + __entry->dx, + __entry->dy, + __entry->median_m, + __entry->median_error, + __entry->history_len, + __entry->x, + __entry->y + ) +); + + #endif /* _CROS_EC_TRACE_H_ */ /* this part must be outside header guard */ diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 935db0e2f1cd80f80e619b2b615c8491ab806495..f0cf5e76597e9feec59c4026286831af73524061 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -711,13 +711,7 @@ static int cros_typec_probe(struct platform_device *pdev) return -ENOMEM; typec->dev = dev; - typec->ec = dev_get_drvdata(pdev->dev.parent); - if (!typec->ec) { - dev_err(dev, "couldn't find parent EC device\n"); - return -ENODEV; - } - platform_set_drvdata(pdev, typec); ret = cros_typec_get_cmd_version(typec); diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index eac3e6b4ea113064aa47f41bf587ab22a85ac68f..a2d846c4a7eef53c05745e7ef9514662876563e9 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -470,17 +470,10 @@ static DEVICE_ATTR_RW(charge_control_thresholds); static int huawei_wmi_battery_add(struct power_supply *battery) { - int err = 0; + device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); + device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); - err = device_create_file(&battery->dev, &dev_attr_charge_control_start_threshold); - if (err) - return err; - - err = device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold); - if (err) - device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold); - - return err; + return 0; } static int huawei_wmi_battery_remove(struct power_supply *battery) diff --git a/drivers/power/reset/gemini-poweroff.c b/drivers/power/reset/gemini-poweroff.c index b7f7a8225f22e133726833e78b39636bec967607..90e35c07240aee158c3478a4f6a248c15b138552 100644 --- a/drivers/power/reset/gemini-poweroff.c +++ b/drivers/power/reset/gemini-poweroff.c @@ -107,8 +107,8 @@ static int gemini_poweroff_probe(struct platform_device *pdev) return PTR_ERR(gpw->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + if (!irq) + return -EINVAL; gpw->dev = dev; diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index a6b4a94c276627009ce4dbf4d25b92b3f200f73c..f1da757c939f8acdfa192997bfc3fb6325b15eee 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2541,10 +2541,8 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di) ret = kobject_init_and_add(&di->fg_kobject, &ab8500_fg_ktype, NULL, "battery"); - if (ret < 0) { - kobject_put(&di->fg_kobject); + if (ret < 0) dev_err(di->dev, "failed to create sysfs entry\n"); - } return ret; } diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 8c3c378dce0d545076017f54a1c5ce1658fb13a4..845af0f44c022c853a2d5dc9f0eb5351211132d3 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -41,7 +41,6 @@ #define BQ24190_REG_POC_CHG_CONFIG_DISABLE 0x0 #define BQ24190_REG_POC_CHG_CONFIG_CHARGE 0x1 #define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2 -#define BQ24190_REG_POC_CHG_CONFIG_OTG_ALT 0x3 #define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1)) #define BQ24190_REG_POC_SYS_MIN_SHIFT 1 #define BQ24190_REG_POC_SYS_MIN_MIN 3000 @@ -553,11 +552,7 @@ static int bq24190_vbus_is_enabled(struct regulator_dev *dev) pm_runtime_mark_last_busy(bdi->dev); pm_runtime_put_autosuspend(bdi->dev); - if (ret) - return ret; - - return (val == BQ24190_REG_POC_CHG_CONFIG_OTG || - val == BQ24190_REG_POC_CHG_CONFIG_OTG_ALT); + return ret ? ret : val == BQ24190_REG_POC_CHG_CONFIG_OTG; } static const struct regulator_ops bq24190_vbus_ops = { diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index 908cfd45d262403013fc0020d6a5a77218bfe47e..e05cee457471bf1ff39db193930f5090309e1901 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -408,112 +408,44 @@ static const struct power_supply_desc wm8350_usb_desc = { * Initialisation *********************************************************************/ -static int wm8350_init_charger(struct wm8350 *wm8350) +static void wm8350_init_charger(struct wm8350 *wm8350) { - int ret; - /* register our interest in charger events */ - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350_charger_handler, 0, "Battery hot", wm8350); - if (ret) - goto err; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350_charger_handler, 0, "Battery cold", wm8350); - if (ret) - goto free_chg_bat_hot; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350_charger_handler, 0, "Battery fail", wm8350); - if (ret) - goto free_chg_bat_cold; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350_charger_handler, 0, "Charger timeout", wm8350); - if (ret) - goto free_chg_bat_fail; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END, wm8350_charger_handler, 0, "Charge end", wm8350); - if (ret) - goto free_chg_to; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START, wm8350_charger_handler, 0, "Charge start", wm8350); - if (ret) - goto free_chg_end; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350_charger_handler, 0, "Fast charge ready", wm8350); - if (ret) - goto free_chg_start; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350_charger_handler, 0, "Battery <3.9V", wm8350); - if (ret) - goto free_chg_fast_rdy; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350_charger_handler, 0, "Battery <3.1V", wm8350); - if (ret) - goto free_chg_vbatt_lt_3p9; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, + wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350_charger_handler, 0, "Battery <2.85V", wm8350); - if (ret) - goto free_chg_vbatt_lt_3p1; /* and supply change events */ - ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350_charger_handler, 0, "USB", wm8350); - if (ret) - goto free_chg_vbatt_lt_2p85; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350_charger_handler, 0, "Wall", wm8350); - if (ret) - goto free_ext_usb_fb; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, + wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350_charger_handler, 0, "Battery", wm8350); - if (ret) - goto free_ext_wall_fb; - - return 0; - -free_ext_wall_fb: - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); -free_ext_usb_fb: - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); -free_chg_vbatt_lt_2p85: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); -free_chg_vbatt_lt_3p1: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); -free_chg_vbatt_lt_3p9: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); -free_chg_fast_rdy: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350); -free_chg_start: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); -free_chg_end: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); -free_chg_to: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); -free_chg_bat_fail: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); -free_chg_bat_cold: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); -free_chg_bat_hot: - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); -err: - return ret; } static void free_charger_irq(struct wm8350 *wm8350) @@ -524,7 +456,6 @@ static void free_charger_irq(struct wm8350 *wm8350) wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 9b15b6a79082a776ee1d77f211b612e1162c79dd..5ff11145c1a309716227196c909894a22ca90476 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -400,6 +400,12 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT, BIT(lpc18xx_pwm->period_event)); + ret = pwmchip_add(&lpc18xx_pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); + goto disable_pwmclk; + } + for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { struct lpc18xx_pwm_data *data; @@ -409,12 +415,14 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) GFP_KERNEL); if (!data) { ret = -ENOMEM; - goto disable_pwmclk; + goto remove_pwmchip; } pwm_set_chip_data(pwm, data); } + platform_set_drvdata(pdev, lpc18xx_pwm); + val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); val &= ~LPC18XX_PWM_BIDIR; val &= ~LPC18XX_PWM_CTRL_HALT; @@ -422,16 +430,10 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) val |= LPC18XX_PWM_PRE(0); lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val); - ret = pwmchip_add(&lpc18xx_pwm->chip); - if (ret < 0) { - dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); - goto disable_pwmclk; - } - - platform_set_drvdata(pdev, lpc18xx_pwm); - return 0; +remove_pwmchip: + pwmchip_remove(&lpc18xx_pwm->chip); disable_pwmclk: clk_disable_unprepare(lpc18xx_pwm->pwm_clk); return ret; diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 8d784a2a09d867c04d74486a33ec516d7a767b65..03e146e98abd5eadb82b213824fba5a252f700b8 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -1185,10 +1185,8 @@ static int rpm_reg_probe(struct platform_device *pdev) for_each_available_child_of_node(dev->of_node, node) { vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) { - of_node_put(node); + if (!vreg) return -ENOMEM; - } ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data); diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 991b4730d7687a89a6f8696d4e36597365d6e8d9..ee46bfbf5eee7e25380208372c5ac0a47ae8293f 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -37,24 +37,11 @@ static const struct regmap_config attiny_regmap_config = { static int attiny_lcd_power_enable(struct regulator_dev *rdev) { unsigned int data; - int ret, i; regmap_write(rdev->regmap, REG_POWERON, 1); - msleep(80); - /* Wait for nPWRDWN to go low to indicate poweron is done. */ - for (i = 0; i < 20; i++) { - ret = regmap_read(rdev->regmap, REG_PORTB, &data); - if (!ret) { - if (data & BIT(0)) - break; - } - usleep_range(10000, 12000); - } - usleep_range(10000, 12000); - - if (ret) - pr_err("%s: regmap_read_poll_timeout failed %d\n", __func__, ret); + regmap_read_poll_timeout(rdev->regmap, REG_PORTB, data, + data & BIT(0), 10, 1000000); /* Default to the same orientation as the closed source * firmware used for the panel. Runtime rotation @@ -70,34 +57,23 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) { regmap_write(rdev->regmap, REG_PWM, 0); regmap_write(rdev->regmap, REG_POWERON, 0); - msleep(30); + udelay(1); return 0; } static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) { unsigned int data; - int ret, i; + int ret; - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_POWERON, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } + ret = regmap_read(rdev->regmap, REG_POWERON, &data); if (ret < 0) return ret; if (!(data & BIT(0))) return 0; - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_PORTB, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } - + ret = regmap_read(rdev->regmap, REG_PORTB, &data); if (ret < 0) return ret; @@ -127,32 +103,20 @@ static int attiny_update_status(struct backlight_device *bl) { struct regmap *regmap = bl_get_data(bl); int brightness = bl->props.brightness; - int ret, i; if (bl->props.power != FB_BLANK_UNBLANK || bl->props.fb_blank != FB_BLANK_UNBLANK) brightness = 0; - for (i = 0; i < 10; i++) { - ret = regmap_write(regmap, REG_PWM, brightness); - if (!ret) - break; - } - - return ret; + return regmap_write(regmap, REG_PWM, brightness); } static int attiny_get_brightness(struct backlight_device *bl) { struct regmap *regmap = bl_get_data(bl); - int ret, brightness, i; - - for (i = 0; i < 10; i++) { - ret = regmap_read(regmap, REG_PWM, &brightness); - if (!ret) - break; - } + int ret, brightness; + ret = regmap_read(regmap, REG_PWM, &brightness); if (ret) return ret; @@ -202,7 +166,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c, } regmap_write(regmap, REG_POWERON, 0); - msleep(30); + mdelay(1); config.dev = &i2c->dev; config.regmap = regmap; diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index d7478c6bc0c892162710f5fdef3318f7156c029b..44aebfc3bf712d3023a551f8a0e96c58dedea9b5 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -406,7 +406,6 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) return ret; diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 1b3aa84e36e7ad051daeab86cd776d6236268a96..ebc3e755bcbcd488229024a2614e6dbfaf6af675 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1594,20 +1594,18 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) * reserved memory regions from device's memory-region property. */ child = of_get_child_by_name(qproc->dev->of_node, "mba"); - if (!child) { + if (!child) node = of_parse_phandle(qproc->dev->of_node, "memory-region", 0); - } else { + else node = of_parse_phandle(child, "memory-region", 0); - of_node_put(child); - } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mba region\n"); return ret; } + of_node_put(node); qproc->mba_phys = r.start; qproc->mba_size = resource_size(&r); @@ -1624,15 +1622,14 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) } else { child = of_get_child_by_name(qproc->dev->of_node, "mpss"); node = of_parse_phandle(child, "memory-region", 0); - of_node_put(child); } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mpss region\n"); return ret; } + of_node_put(node); qproc->mpss_phys = qproc->mpss_reloc = r.start; qproc->mpss_size = resource_size(&r); diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 4e2527fcae3c254417924d6ce519be5ab6649510..e2501687a945c69755d72aa6020c1506b54e0bc3 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -448,7 +448,6 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss) } ret = of_address_to_resource(node, 0, &r); - of_node_put(node); if (ret) return ret; diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 581930483ef843c0e96b1c0fcba824c36f5952a7..b5a1e3b697d9f9eb3f06ae0e316f913dccaf4736 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -76,7 +76,7 @@ static ssize_t rproc_coredump_write(struct file *filp, int ret, err = 0; char buf[20]; - if (count < 1 || count > sizeof(buf)) + if (count > sizeof(buf)) return -EINVAL; ret = copy_from_user(buf, user_buf, count); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 146056858135e304fce9d0a173d8d667427b5394..794a4f036b99834c8fa15bcc834dddcfaa1090ba 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -807,13 +807,9 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); struct rtc_time tm; ktime_t now; - int err; - - err = __rtc_read_time(rtc, &tm); - if (err) - return err; timer->enabled = 1; + __rtc_read_time(rtc, &tm); now = rtc_tm_to_ktime(tm); /* Skip over expired timers */ @@ -827,6 +823,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) trace_rtc_timer_enqueue(timer); if (!next || ktime_before(timer->node.expires, next->expires)) { struct rtc_wkalrm alarm; + int err; alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index a8998b016b862576bc9eecefeb5276ddcc1d2011..50a1c3478a6e0922a37a64baa9798e8c2ecdb5b5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -514,7 +514,7 @@ MODULE_PARM_DESC(intr_conv, "interrupt converge enable (0-1)"); /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ static int prot_mask; -module_param(prot_mask, int, 0444); +module_param(prot_mask, int, 0); MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=0x0 "); static bool auto_affine_msi_experimental; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a1a06a832d866aac25a2849584033ec735ca225d..8b9a39077dbabb8210a9dbb4d1c896619f37ad1e 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -202,7 +202,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) task->total_xfer_len = qc->nbytes; task->num_scatter = qc->n_elem; task->data_dir = qc->dma_dir; - } else if (!ata_is_data(qc->tf.protocol)) { + } else if (qc->tf.protocol == ATA_PROT_NODATA) { task->data_dir = DMA_NONE; } else { for_each_sg(qc->sg, sg, qc->n_elem, si) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 3153f164554aabaa6fbbed8d847b76316cc2b318..3fbbdf084d67a3f574b2de37c6394d3e3b2c4639 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1832,10 +1832,9 @@ mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc, u8 poll) enable_irq(reply_q->os_irq); } } - - if (poll) - _base_process_reply_queue(reply_q); } + if (poll) + _base_process_reply_queue(reply_q); } /** diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index cd0e1d31db7013da02c8060734b8f6c2e5c3341d..9b318958d78cc393a2a33c5db0b73d401e9d6aae 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1727,7 +1727,6 @@ static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_ha_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; - ccb->n_elem = 0; circularQ = &pm8001_ha->inbnd_q_tbl[0]; @@ -1789,7 +1788,6 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_ha_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; - ccb->n_elem = 0; pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG; pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG; @@ -1806,7 +1804,7 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, sata_cmd.tag = cpu_to_le32(ccb_tag); sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m = cpu_to_le32((0x1 << 7) | (0x5 << 9)); + sata_cmd.ncqtag_atap_dir_m |= ((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, @@ -2367,8 +2365,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) len = sizeof(struct pio_setup_fis); pm8001_dbg(pm8001_ha, IO, "PIO read len = %d\n", len); - } else if (t->ata_task.use_ncq && - t->data_dir != DMA_NONE) { + } else if (t->ata_task.use_ncq) { len = sizeof(struct set_dev_bits_fis); pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", len); @@ -4223,22 +4220,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u32 opc = OPC_INB_SATA_HOST_OPSTART; memset(&sata_cmd, 0, sizeof(sata_cmd)); circularQ = &pm8001_ha->inbnd_q_tbl[0]; - - if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) { + if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.use_ncq && - dev->sata_dev.class != ATA_DEV_ATAPI) { - ATAP = 0x07; /* FPDMA */ - pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); - } else if (task->ata_task.dma_xfer) { + if (task->ata_task.dma_xfer) { ATAP = 0x06; /* DMA */ pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP = 0x05; /* PIO*/ pm8001_dbg(pm8001_ha, IO, "PIO\n"); } + if (task->ata_task.use_ncq && + dev->sata_dev.class != ATA_DEV_ATAPI) { + ATAP = 0x07; /* FPDMA */ + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); + } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); @@ -4578,7 +4575,7 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8); sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag); if (pm8001_ha->chip_id != chip_8001) - sspTMCmd.ds_ads_m = cpu_to_le32(0x08); + sspTMCmd.ds_ads_m = 0x08; circularQ = &pm8001_ha->inbnd_q_tbl[0]; ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, sizeof(sspTMCmd), 0); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index b5e60553acdc598c942f077a4ecad0a6cdcdebc2..2a3ce4680734be48f141037bdccbc954337df186 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1199,11 +1199,9 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) else page_code = THERMAL_PAGE_CODE_8H; - payload.cfg_pg[0] = - cpu_to_le32((THERMAL_LOG_ENABLE << 9) | - (THERMAL_ENABLE << 8) | page_code); - payload.cfg_pg[1] = - cpu_to_le32((LTEMPHIL << 24) | (RTEMPHIL << 8)); + payload.cfg_pg[0] = (THERMAL_LOG_ENABLE << 9) | + (THERMAL_ENABLE << 8) | page_code; + payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8); pm8001_dbg(pm8001_ha, DEV, "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", @@ -1243,41 +1241,43 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) circularQ = &pm8001_ha->inbnd_q_tbl[0]; payload.tag = cpu_to_le32(tag); - SASConfigPage.pageCode = cpu_to_le32(SAS_PROTOCOL_TIMER_CONFIG_PAGE); - SASConfigPage.MST_MSI = cpu_to_le32(3 << 15); - SASConfigPage.STP_SSP_MCT_TMO = - cpu_to_le32((STP_MCT_TMO << 16) | SSP_MCT_TMO); - SASConfigPage.STP_FRM_TMO = - cpu_to_le32((SAS_MAX_OPEN_TIME << 24) | - (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER); - SASConfigPage.STP_IDLE_TMO = cpu_to_le32(STP_IDLE_TIME); - - SASConfigPage.OPNRJT_RTRY_INTVL = - cpu_to_le32((SAS_MFD << 16) | SAS_OPNRJT_RTRY_INTVL); - SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = - cpu_to_le32((SAS_DOPNRJT_RTRY_TMO << 16) | SAS_COPNRJT_RTRY_TMO); - SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = - cpu_to_le32((SAS_DOPNRJT_RTRY_THR << 16) | SAS_COPNRJT_RTRY_THR); - SASConfigPage.MAX_AIP = cpu_to_le32(SAS_MAX_AIP); + SASConfigPage.pageCode = SAS_PROTOCOL_TIMER_CONFIG_PAGE; + SASConfigPage.MST_MSI = 3 << 15; + SASConfigPage.STP_SSP_MCT_TMO = (STP_MCT_TMO << 16) | SSP_MCT_TMO; + SASConfigPage.STP_FRM_TMO = (SAS_MAX_OPEN_TIME << 24) | + (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER; + SASConfigPage.STP_IDLE_TMO = STP_IDLE_TIME; + + if (SASConfigPage.STP_IDLE_TMO > 0x3FFFFFF) + SASConfigPage.STP_IDLE_TMO = 0x3FFFFFF; + + + SASConfigPage.OPNRJT_RTRY_INTVL = (SAS_MFD << 16) | + SAS_OPNRJT_RTRY_INTVL; + SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = (SAS_DOPNRJT_RTRY_TMO << 16) + | SAS_COPNRJT_RTRY_TMO; + SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = (SAS_DOPNRJT_RTRY_THR << 16) + | SAS_COPNRJT_RTRY_THR; + SASConfigPage.MAX_AIP = SAS_MAX_AIP; pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n", - le32_to_cpu(SASConfigPage.pageCode)); + SASConfigPage.pageCode); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n", - le32_to_cpu(SASConfigPage.MST_MSI)); + SASConfigPage.MST_MSI); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.STP_SSP_MCT_TMO)); + SASConfigPage.STP_SSP_MCT_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.STP_FRM_TMO)); + SASConfigPage.STP_FRM_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.STP_IDLE_TMO)); + SASConfigPage.STP_IDLE_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n", - le32_to_cpu(SASConfigPage.OPNRJT_RTRY_INTVL)); + SASConfigPage.OPNRJT_RTRY_INTVL); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%08x\n", - le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO)); + SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%08x\n", - le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR)); + SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR); pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n", - le32_to_cpu(SASConfigPage.MAX_AIP)); + SASConfigPage.MAX_AIP); memcpy(&payload.cfg_pg, &SASConfigPage, sizeof(SASProtocolTimerConfig_t)); @@ -1403,13 +1403,12 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) /* Currently only one key is used. New KEK index is 1. * Current KEK index is 1. Store KEK to NVRAM is 1. */ - payload.new_curidx_ksop = - cpu_to_le32(((1 << 24) | (1 << 16) | (1 << 8) | - KEK_MGMT_SUBOP_KEYCARDUPDATE)); + payload.new_curidx_ksop = ((1 << 24) | (1 << 16) | (1 << 8) | + KEK_MGMT_SUBOP_KEYCARDUPDATE); pm8001_dbg(pm8001_ha, DEV, "Saving Encryption info to flash. payload 0x%x\n", - le32_to_cpu(payload.new_curidx_ksop)); + payload.new_curidx_ksop); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, sizeof(payload), 0); @@ -1750,7 +1749,6 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_ha_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; - ccb->n_elem = 0; circularQ = &pm8001_ha->inbnd_q_tbl[0]; @@ -1832,7 +1830,7 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, sata_cmd.tag = cpu_to_le32(ccb_tag); sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.ncqtag_atap_dir_m_dad = cpu_to_le32(((0x1 << 7) | (0x5 << 9))); + sata_cmd.ncqtag_atap_dir_m_dad |= ((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, @@ -2466,8 +2464,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) len = sizeof(struct pio_setup_fis); pm8001_dbg(pm8001_ha, IO, "PIO read len = %d\n", len); - } else if (t->ata_task.use_ncq && - t->data_dir != DMA_NONE) { + } else if (t->ata_task.use_ncq) { len = sizeof(struct set_dev_bits_fis); pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", len); @@ -4310,15 +4307,13 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, struct ssp_ini_io_start_req ssp_cmd; u32 tag = ccb->ccb_tag; int ret; - u64 phys_addr, end_addr; + u64 phys_addr, start_addr, end_addr; u32 end_addr_high, end_addr_low; struct inbound_queue_table *circularQ; u32 q_index, cpu_id; u32 opc = OPC_INB_SSPINIIOSTART; - memset(&ssp_cmd, 0, sizeof(ssp_cmd)); memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); - /* data address domain added for spcv; set to 0 by host, * used internally by controller * 0 for SAS 1.1 and SAS 2.0 compatible TLR @@ -4329,7 +4324,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id); ssp_cmd.tag = cpu_to_le32(tag); if (task->ssp_task.enable_first_burst) - ssp_cmd.ssp_iu.efb_prio_attr = 0x80; + ssp_cmd.ssp_iu.efb_prio_attr |= 0x80; ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3); ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7); memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd, @@ -4361,24 +4356,21 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.enc_esgl = cpu_to_le32(1<<31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - ssp_cmd.enc_addr_low = cpu_to_le32(lower_32_bits(dma_addr)); ssp_cmd.enc_addr_high = cpu_to_le32(upper_32_bits(dma_addr)); ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); ssp_cmd.enc_esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(ssp_cmd.enc_len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); - - if (end_addr_high != le32_to_cpu(ssp_cmd.enc_addr_high)) { + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + ssp_cmd.enc_len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); + if (end_addr_high != ssp_cmd.enc_addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(ssp_cmd.enc_len), + start_addr, ssp_cmd.enc_len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); @@ -4387,7 +4379,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, cpu_to_le32(lower_32_bits(phys_addr)); ssp_cmd.enc_addr_high = cpu_to_le32(upper_32_bits(phys_addr)); - ssp_cmd.enc_esgl = cpu_to_le32(1U<<31); + ssp_cmd.enc_esgl = cpu_to_le32(1<<31); } } else if (task->num_scatter == 0) { ssp_cmd.enc_addr_low = 0; @@ -4395,10 +4387,8 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); ssp_cmd.enc_esgl = 0; } - /* XTS mode. All other fields are 0 */ - ssp_cmd.key_cmode = cpu_to_le32(0x6 << 4); - + ssp_cmd.key_cmode = 0x6 << 4; /* set tweak values. Should be the start lba */ ssp_cmd.twk_val0 = cpu_to_le32((task->ssp_task.cmd->cmnd[2] << 24) | (task->ssp_task.cmd->cmnd[3] << 16) | @@ -4420,22 +4410,20 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.esgl = cpu_to_le32(1<<31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr)); ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr)); ssp_cmd.len = cpu_to_le32(task->total_xfer_len); ssp_cmd.esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(ssp_cmd.len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); - if (end_addr_high != le32_to_cpu(ssp_cmd.addr_high)) { + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + ssp_cmd.len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); + if (end_addr_high != ssp_cmd.addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(ssp_cmd.len), + start_addr, ssp_cmd.len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); @@ -4469,7 +4457,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, u32 q_index, cpu_id; struct sata_start_req sata_cmd; u32 hdr_tag, ncg_tag = 0; - u64 phys_addr, end_addr; + u64 phys_addr, start_addr, end_addr; u32 end_addr_high, end_addr_low; u32 ATAP = 0x0; u32 dir; @@ -4481,21 +4469,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, q_index = (u32) (cpu_id) % (pm8001_ha->max_q_num); circularQ = &pm8001_ha->inbnd_q_tbl[q_index]; - if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) { + if (task->data_dir == DMA_NONE) { ATAP = 0x04; /* no data*/ pm8001_dbg(pm8001_ha, IO, "no data\n"); } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.use_ncq && - dev->sata_dev.class != ATA_DEV_ATAPI) { - ATAP = 0x07; /* FPDMA */ - pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); - } else if (task->ata_task.dma_xfer) { + if (task->ata_task.dma_xfer) { ATAP = 0x06; /* DMA */ pm8001_dbg(pm8001_ha, IO, "DMA\n"); } else { ATAP = 0x05; /* PIO*/ pm8001_dbg(pm8001_ha, IO, "PIO\n"); } + if (task->ata_task.use_ncq && + dev->sata_dev.class != ATA_DEV_ATAPI) { + ATAP = 0x07; /* FPDMA */ + pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); + } } if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); @@ -4529,38 +4518,32 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; - sata_cmd.enc_addr_low = - cpu_to_le32(lower_32_bits(phys_addr)); - sata_cmd.enc_addr_high = - cpu_to_le32(upper_32_bits(phys_addr)); + sata_cmd.enc_addr_low = lower_32_bits(phys_addr); + sata_cmd.enc_addr_high = upper_32_bits(phys_addr); sata_cmd.enc_esgl = cpu_to_le32(1 << 31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - - sata_cmd.enc_addr_low = - cpu_to_le32(lower_32_bits(dma_addr)); - sata_cmd.enc_addr_high = - cpu_to_le32(upper_32_bits(dma_addr)); + sata_cmd.enc_addr_low = lower_32_bits(dma_addr); + sata_cmd.enc_addr_high = upper_32_bits(dma_addr); sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); sata_cmd.enc_esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(sata_cmd.enc_len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); - if (end_addr_high != le32_to_cpu(sata_cmd.enc_addr_high)) { + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + sata_cmd.enc_len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); + if (end_addr_high != sata_cmd.enc_addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(sata_cmd.enc_len), + start_addr, sata_cmd.enc_len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; sata_cmd.enc_addr_low = - cpu_to_le32(lower_32_bits(phys_addr)); + lower_32_bits(phys_addr); sata_cmd.enc_addr_high = - cpu_to_le32(upper_32_bits(phys_addr)); + upper_32_bits(phys_addr); sata_cmd.enc_esgl = cpu_to_le32(1 << 31); } @@ -4571,8 +4554,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, sata_cmd.enc_esgl = 0; } /* XTS mode. All other fields are 0 */ - sata_cmd.key_index_mode = cpu_to_le32(0x6 << 4); - + sata_cmd.key_index_mode = 0x6 << 4; /* set tweak values. Should be the start lba */ sata_cmd.twk_val0 = cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) | @@ -4598,31 +4580,31 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, phys_addr = ccb->ccb_dma_handle; sata_cmd.addr_low = lower_32_bits(phys_addr); sata_cmd.addr_high = upper_32_bits(phys_addr); - sata_cmd.esgl = cpu_to_le32(1U << 31); + sata_cmd.esgl = cpu_to_le32(1 << 31); } else if (task->num_scatter == 1) { u64 dma_addr = sg_dma_address(task->scatter); - sata_cmd.addr_low = lower_32_bits(dma_addr); sata_cmd.addr_high = upper_32_bits(dma_addr); sata_cmd.len = cpu_to_le32(task->total_xfer_len); sata_cmd.esgl = 0; - /* Check 4G Boundary */ - end_addr = dma_addr + le32_to_cpu(sata_cmd.len) - 1; - end_addr_low = lower_32_bits(end_addr); - end_addr_high = upper_32_bits(end_addr); + start_addr = cpu_to_le64(dma_addr); + end_addr = (start_addr + sata_cmd.len) - 1; + end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); + end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); if (end_addr_high != sata_cmd.addr_high) { pm8001_dbg(pm8001_ha, FAIL, "The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", - dma_addr, - le32_to_cpu(sata_cmd.len), + start_addr, sata_cmd.len, end_addr_high, end_addr_low); pm8001_chip_make_sg(task->scatter, 1, ccb->buf_prd); phys_addr = ccb->ccb_dma_handle; - sata_cmd.addr_low = lower_32_bits(phys_addr); - sata_cmd.addr_high = upper_32_bits(phys_addr); - sata_cmd.esgl = cpu_to_le32(1U << 31); + sata_cmd.addr_low = + lower_32_bits(phys_addr); + sata_cmd.addr_high = + upper_32_bits(phys_addr); + sata_cmd.esgl = cpu_to_le32(1 << 31); } } else if (task->num_scatter == 0) { sata_cmd.addr_low = 0; @@ -4630,28 +4612,27 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, sata_cmd.len = cpu_to_le32(task->total_xfer_len); sata_cmd.esgl = 0; } - /* scsi cdb */ sata_cmd.atapi_scsi_cdb[0] = cpu_to_le32(((task->ata_task.atapi_packet[0]) | - (task->ata_task.atapi_packet[1] << 8) | - (task->ata_task.atapi_packet[2] << 16) | - (task->ata_task.atapi_packet[3] << 24))); + (task->ata_task.atapi_packet[1] << 8) | + (task->ata_task.atapi_packet[2] << 16) | + (task->ata_task.atapi_packet[3] << 24))); sata_cmd.atapi_scsi_cdb[1] = cpu_to_le32(((task->ata_task.atapi_packet[4]) | - (task->ata_task.atapi_packet[5] << 8) | - (task->ata_task.atapi_packet[6] << 16) | - (task->ata_task.atapi_packet[7] << 24))); + (task->ata_task.atapi_packet[5] << 8) | + (task->ata_task.atapi_packet[6] << 16) | + (task->ata_task.atapi_packet[7] << 24))); sata_cmd.atapi_scsi_cdb[2] = cpu_to_le32(((task->ata_task.atapi_packet[8]) | - (task->ata_task.atapi_packet[9] << 8) | - (task->ata_task.atapi_packet[10] << 16) | - (task->ata_task.atapi_packet[11] << 24))); + (task->ata_task.atapi_packet[9] << 8) | + (task->ata_task.atapi_packet[10] << 16) | + (task->ata_task.atapi_packet[11] << 24))); sata_cmd.atapi_scsi_cdb[3] = cpu_to_le32(((task->ata_task.atapi_packet[12]) | - (task->ata_task.atapi_packet[13] << 8) | - (task->ata_task.atapi_packet[14] << 16) | - (task->ata_task.atapi_packet[15] << 24))); + (task->ata_task.atapi_packet[13] << 8) | + (task->ata_task.atapi_packet[14] << 16) | + (task->ata_task.atapi_packet[15] << 24))); } /* Check for read log for failed drive and return */ diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d0407f44de78da687d67b87922cf77eaab2070e3..e40a37236aa10a5d0c2728d957122f3b858d56da 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -555,7 +555,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return -EINVAL; - if (!IS_NOCACHE_VPD_TYPE(ha)) + if (IS_NOCACHE_VPD_TYPE(ha)) goto skip; faddr = ha->flt_region_vpd << 2; @@ -739,7 +739,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, ql_log(ql_log_info, vha, 0x706f, "Issuing MPI reset.\n"); - if (IS_QLA83XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { uint32_t idc_control; qla83xx_idc_lock(vha, 0); @@ -1050,6 +1050,9 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon) continue; if (iter->type == 3 && !(IS_CNA_CAPABLE(ha))) continue; + if (iter->type == 0x27 && + (!IS_QLA27XX(ha) || !IS_QLA28XX(ha))) + continue; sysfs_remove_bin_file(&host->shost_gendev.kobj, iter->attr); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 8a8e0920d2b41e478c173f67445292faa6cc6528..e1fd91a58120240b281842dff166e3f10f3d94b5 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2796,11 +2796,7 @@ struct ct_fdmi2_hba_attributes { #define FDMI_PORT_SPEED_8GB 0x10 #define FDMI_PORT_SPEED_16GB 0x20 #define FDMI_PORT_SPEED_32GB 0x40 -#define FDMI_PORT_SPEED_20GB 0x80 -#define FDMI_PORT_SPEED_40GB 0x100 -#define FDMI_PORT_SPEED_128GB 0x200 -#define FDMI_PORT_SPEED_64GB 0x400 -#define FDMI_PORT_SPEED_256GB 0x800 +#define FDMI_PORT_SPEED_64GB 0x80 #define FDMI_PORT_SPEED_UNKNOWN 0x8000 #define FC_CLASS_2 0x04 @@ -5175,8 +5171,4 @@ struct sff_8247_a0 { #include "qla_gbl.h" #include "qla_dbg.h" #include "qla_inline.h" - -#define IS_SESSION_DELETED(_fcport) (_fcport->disc_state == DSC_DELETE_PEND || \ - _fcport->disc_state == DSC_DELETED) - #endif diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 73015c69b5e892b1c909659064212fa19a4ab726..e28c4b7ec55ffb55ce4aa10e43c62719955007f5 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -676,7 +676,8 @@ qla2x00_rff_id(scsi_qla_host_t *vha, u8 type) return (QLA_SUCCESS); } - return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), type); + return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), + FC4_TYPE_FCP_SCSI); } static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, @@ -726,7 +727,7 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ ct_req->req.rff_id.port_id = port_id_to_be_id(*d_id); ct_req->req.rff_id.fc4_feature = fc4feature; - ct_req->req.rff_id.fc4_type = fc4type; /* SCSI-FCP or FC-NVMe */ + ct_req->req.rff_id.fc4_type = fc4type; /* SCSI - FCP */ sp->u.iocb_cmd.u.ctarg.req_size = RFF_ID_REQ_SIZE; sp->u.iocb_cmd.u.ctarg.rsp_size = RFF_ID_RSP_SIZE; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9452848ede3f86d29e9f1b5df196f8a484e37e9d..fdae25ec554d9f1ba2ee6b35ba52dea859f76e5f 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -570,14 +570,6 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, struct srb_iocb *lio; int rval = QLA_FUNCTION_FAILED; - if (IS_SESSION_DELETED(fcport)) { - ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC is being delete - not sending command.\n", - __func__, fcport->port_name); - fcport->flags &= ~FCF_ASYNC_ACTIVE; - return rval; - } - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) return rval; @@ -961,9 +953,6 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, set_bit(RELOGIN_NEEDED, &vha->dpc_flags); } break; - case ISP_CFG_NL: - qla24xx_fcport_handle_login(vha, fcport); - break; default: break; } @@ -1324,21 +1313,14 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) struct port_database_24xx *pd; struct qla_hw_data *ha = vha->hw; - if (IS_SESSION_DELETED(fcport)) { + if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT) || + fcport->loop_id == FC_NO_LOOP_ID) { ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC is being delete - not sending command.\n", - __func__, fcport->port_name); - fcport->flags &= ~FCF_ASYNC_ACTIVE; + "%s: %8phC - not sending command.\n", + __func__, fcport->port_name); return rval; } - if (!vha->flags.online || fcport->flags & FCF_ASYNC_SENT) { - ql_log(ql_log_warn, vha, 0xffff, - "%s: %8phC online %d flags %x - not sending command.\n", - __func__, fcport->port_name, vha->flags.online, fcport->flags); - goto done; - } - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; @@ -1498,11 +1480,6 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport) u8 login = 0; int rc; - ql_dbg(ql_dbg_disc, vha, 0x307b, - "%s %8phC DS %d LS %d lid %d retries=%d\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state, fcport->loop_id, fcport->login_retry); - if (qla_tgt_mode_enabled(vha)) return; @@ -1560,8 +1537,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen, fcport->login_gen, fcport->loop_id, fcport->scan_state); - if (fcport->scan_state != QLA_FCPORT_FOUND || - fcport->disc_state == DSC_DELETE_PEND) + if (fcport->scan_state != QLA_FCPORT_FOUND) return 0; if ((fcport->loop_id != FC_NO_LOOP_ID) && @@ -1582,7 +1558,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) if (vha->host->active_mode == MODE_TARGET && !N2N_TOPO(vha->hw)) return 0; - if (fcport->flags & (FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE)) { + if (fcport->flags & FCF_ASYNC_SENT) { set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return 0; } @@ -2138,7 +2114,12 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x20eb, "%s %d %8phC cmd error %x\n", __func__, __LINE__, ea->fcport->port_name, ea->data[1]); - qlt_schedule_sess_for_deletion(ea->fcport); + ea->fcport->flags &= ~FCF_ASYNC_SENT; + qla2x00_set_fcport_disc_state(ea->fcport, DSC_LOGIN_FAILED); + if (ea->data[1] & QLA_LOGIO_LOGIN_RETRIED) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + else + qla2x00_mark_device_lost(vha, ea->fcport, 1); break; case MBS_LOOP_ID_USED: /* data[1] = IO PARAM 1 = nport ID */ @@ -3328,14 +3309,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) struct rsp_que *rsp = ha->rsp_q_map[0]; struct qla2xxx_fw_dump *fw_dump; - if (ha->fw_dump) { - ql_dbg(ql_dbg_init, vha, 0x00bd, - "Firmware dump already allocated.\n"); - return; - } - - ha->fw_dumped = 0; - ha->fw_dump_cap_flags = 0; dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0; req_q_size = rsp_q_size = 0; @@ -3346,7 +3319,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { - if (IS_QLA83XX(ha)) + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem); else if (IS_QLA81XX(ha)) fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); @@ -3358,7 +3331,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); if (ha->mqenable) { - if (!IS_QLA83XX(ha)) + if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && + !IS_QLA28XX(ha)) mq_size = sizeof(struct qla2xxx_mq_chain); /* * Allocate maximum buffer size for all queues - Q0. @@ -3919,7 +3893,8 @@ enable_82xx_npiv: ha->fw_major_version, ha->fw_minor_version, ha->fw_subminor_version); - if (IS_QLA83XX(ha)) { + if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ha->flags.fac_supported = 0; rval = QLA_SUCCESS; } @@ -5407,13 +5382,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) memcpy(fcport->node_name, new_fcport->node_name, WWN_SIZE); fcport->scan_state = QLA_FCPORT_FOUND; - if (fcport->login_retry == 0) { - fcport->login_retry = vha->hw->login_retry_count; - ql_dbg(ql_dbg_disc, vha, 0x2135, - "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", - fcport->port_name, fcport->loop_id, - fcport->login_retry); - } found++; break; } @@ -5547,8 +5515,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) if (atomic_read(&fcport->state) == FCS_ONLINE) return; - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - rport_ids.node_name = wwn_to_u64(fcport->node_name); rport_ids.port_name = wwn_to_u64(fcport->port_name); rport_ids.port_id = fcport->d_id.b.domain << 16 | @@ -5649,7 +5615,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_reg_remote_port(vha, fcport); break; case MODE_TARGET: - qla2x00_set_fcport_state(fcport, FCS_ONLINE); if (!vha->vha_tgt.qla_tgt->tgt_stop && !vha->vha_tgt.qla_tgt->tgt_stopped) qlt_fc_port_added(vha, fcport); @@ -5664,6 +5629,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) break; } + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) { if (fcport->id_changed) { fcport->id_changed = 0; @@ -9160,7 +9127,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->rsp->req = qpair->req; qpair->rsp->qpair = qpair; /* init qpair to this cpu. Will adjust at run time. */ - qla_cpu_update(qpair, raw_smp_processor_id()); + qla_cpu_update(qpair, smp_processor_id()); if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index e54cc2a761dd46ee110c2149b79d327ed0218d2f..c532c74ca1ab9e17ece023d6ee69e4b5edc1a799 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2910,7 +2910,6 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); - break; } fallthrough; default: @@ -2920,7 +2919,9 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) fw_status[0], fw_status[1], fw_status[2]); fcport->flags &= ~FCF_ASYNC_SENT; - qlt_schedule_sess_for_deletion(fcport); + qla2x00_set_fcport_disc_state(fcport, + DSC_LOGIN_FAILED); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); break; } break; @@ -2932,7 +2933,8 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) fw_status[0], fw_status[1], fw_status[2]); sp->fcport->flags &= ~FCF_ASYNC_SENT; - qlt_schedule_sess_for_deletion(fcport); + qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_FAILED); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index c5c7d60ab25241a0c1ba787e9268d30d6a5c2bcd..5e040b6debc84ef224dbf7e05ffac1dc931eea16 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2248,7 +2248,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) iocb->u.tmf.data = QLA_FUNCTION_FAILED; } else if ((le16_to_cpu(sts->scsi_status) & SS_RESPONSE_INFO_LEN_VALID)) { - host_to_fcp_swap(sts->data, sizeof(sts->data)); if (le32_to_cpu(sts->rsp_data_len) < 4) { ql_log(ql_log_warn, fcport->vha, 0x503b, "Async-%s error - hdl=%x not enough response(%d).\n", diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bbb57edc1f66290b72495b3dcabf7652385aef2f..734745f450211a921beda952e2371011a6f663d5 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -9,12 +9,6 @@ #include #include -#ifdef CONFIG_PPC -#define IS_PPCARCH true -#else -#define IS_PPCARCH false -#endif - static struct mb_cmd_name { uint16_t cmd; const char *str; @@ -704,9 +698,6 @@ again: vha->min_supported_speed = nv->min_supported_speed; } - - if (IS_PPCARCH) - mcp->mb[11] |= BIT_4; } if (ha->flags.exlogins_enabled) @@ -2993,7 +2984,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha) ha->orig_fw_iocb_count = mcp->mb[10]; if (ha->flags.npiv_supported) ha->max_npiv_vports = mcp->mb[11]; - if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) + if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) ha->fw_max_fcf_count = mcp->mb[12]; } @@ -5554,7 +5546,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) - mcp->in_mb |= MBX_4|MBX_3; + mcp->in_mb |= MBX_3; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index ba1b1c7549d359f9e025d1ac61f74466ab193e34..5acee3c798d42771e739201f043e9c44ce42dcb6 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -35,11 +35,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) (fcport->nvme_flag & NVME_FLAG_REGISTERED)) return 0; - if (atomic_read(&fcport->state) == FCS_ONLINE) - return 0; - - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - fcport->nvme_flag &= ~NVME_FLAG_RESETTING; memset(&req, 0, sizeof(struct nvme_fc_port_info)); @@ -170,18 +165,6 @@ out: qla2xxx_rel_qpair_sp(sp->qpair, sp); } -static void qla_nvme_ls_unmap(struct srb *sp, struct nvmefc_ls_req *fd) -{ - if (sp->flags & SRB_DMA_VALID) { - struct srb_iocb *nvme = &sp->u.iocb_cmd; - struct qla_hw_data *ha = sp->fcport->vha->hw; - - dma_unmap_single(&ha->pdev->dev, nvme->u.nvme.cmd_dma, - fd->rqstlen, DMA_TO_DEVICE); - sp->flags &= ~SRB_DMA_VALID; - } -} - static void qla_nvme_release_ls_cmd_kref(struct kref *kref) { struct srb *sp = container_of(kref, struct srb, cmd_kref); @@ -198,8 +181,6 @@ static void qla_nvme_release_ls_cmd_kref(struct kref *kref) spin_unlock_irqrestore(&priv->cmd_lock, flags); fd = priv->fd; - - qla_nvme_ls_unmap(sp, fd); fd->done(fd, priv->comp_status); out: qla2x00_rel_sp(sp); @@ -346,8 +327,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, fd->rqstlen, DMA_TO_DEVICE); - sp->flags |= SRB_DMA_VALID; - rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, @@ -355,7 +334,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, wake_up(&sp->nvme_ls_waitq); sp->priv = NULL; priv->sp = NULL; - qla_nvme_ls_unmap(sp, fd); qla2x00_rel_sp(sp); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 419156121cb59a9ededeef864994c7c9a3b6d05a..e7f73a167fbd64136e64ad305d4eb0ee399724da 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3673,7 +3673,8 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha) if (ha->mqiobase) iounmap(ha->mqiobase); - if (ha->msixbase) + if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) && + ha->msixbase) iounmap(ha->msixbase); } } @@ -5389,11 +5390,6 @@ void qla2x00_relogin(struct scsi_qla_host *vha) memset(&ea, 0, sizeof(ea)); ea.fcport = fcport; qla24xx_handle_relogin_event(vha, &ea); - } else if (vha->hw->current_topology == - ISP_CFG_NL && - IS_QLA2XXX_MIDTYPE(vha->hw)) { - (void)qla24xx_fcport_handle_login(vha, - fcport); } else if (vha->hw->current_topology == ISP_CFG_NL) { fcport->login_retry--; diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 0fa9c529fca11a51d7191a089335c212fec035d3..0f92e9a044dcdb4e27c4226b6f96792bde915824 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -844,7 +844,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) ha->flt_region_nvram = start; break; case FLT_REG_IMG_PRI_27XX: - if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + if (IS_QLA27XX(ha) && !IS_QLA28XX(ha)) ha->flt_region_img_status_pri = start; break; case FLT_REG_IMG_SEC_27XX: @@ -1356,7 +1356,7 @@ next: flash_data_addr(ha, faddr), le32_to_cpu(*dwptr)); if (ret) { ql_dbg(ql_dbg_user, vha, 0x7006, - "Failed slow write %x (%x)\n", faddr, *dwptr); + "Failed slopw write %x (%x)\n", faddr, *dwptr); break; } } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index cf9ae0ab489a0ef2566c0c1d58abcbe897a2c75c..ebed14bed7835cc46a1512c6afc05198bd67f08a 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3256,7 +3256,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), cmd->reset_count, qpair->chip_reset); - res = 0; goto out_unmap_unlock; } @@ -7077,7 +7076,8 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) if (!QLA_TGT_MODE_ENABLED()) return; - if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + if ((ql2xenablemsix == 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || + IS_QLA28XX(ha)) { ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in; ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out; } else { diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f11f51e2465f5dea81fef1810d7368e11ff005cb..cfa588e915619a5b3d434d1c079158ba1d071d63 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -448,8 +448,13 @@ static void scsi_report_sense(struct scsi_device *sdev, if (sshdr->asc == 0x29) { evt_type = SDEV_EVT_POWER_ON_RESET_OCCURRED; - sdev_printk(KERN_WARNING, sdev, - "Power-on or device reset occurred\n"); + /* + * Do not print message if it is an expected side-effect + * of runtime PM. + */ + if (!sdev->silence_suspend) + sdev_printk(KERN_WARNING, sdev, + "Power-on or device reset occurred\n"); } if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9de0bd97c556eda9402a129b5d65a113c8e8185f..edb1e26c734b1a28542d63f58d575c36c8ae17ac 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3663,7 +3663,8 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) return 0; if (sdkp->WCE && sdkp->media_present) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); + if (!sdkp->device->silence_suspend) + sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); ret = sd_sync_cache(sdkp, &sshdr); if (ret) { @@ -3685,7 +3686,8 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) } if (sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); + if (!sdkp->device->silence_suspend) + sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); /* an error is not worth aborting a system sleep */ ret = sd_start_stop_device(sdkp, 0); if (ignore_stop_errors) diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c index fc5b214347b364b2dffdf05d28cf9026ad00a09f..86a938075f308bd41d568127b93214fb129154e2 100644 --- a/drivers/scsi/ufs/ufs-mediatek.c +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -557,7 +557,7 @@ static void ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba *hba) struct ufs_mtk_host *host = ufshcd_get_variant(hba); host->reg_va09 = regulator_get(hba->dev, "va09"); - if (!host->reg_va09) + if (IS_ERR(host->reg_va09)) dev_info(hba->dev, "failed to get va09"); else host->caps |= UFS_MTK_CAP_VA09_PWR_CTRL; @@ -1189,6 +1189,7 @@ static int ufs_mtk_probe(struct platform_device *pdev) } link = device_link_add(dev, &reset_pdev->dev, DL_FLAG_AUTOPROBE_CONSUMER); + put_device(&reset_pdev->dev); if (!link) { dev_notice(dev, "add reset device_link fail\n"); goto skip_reset; diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index b3c792fc7bad60391bbd57031c0a94e93ea0541b..280c56db3b12672dd3a59ed1cdb03eff50e645d0 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -44,6 +44,12 @@ /* WriteBooster buffer is available only for the logical unit from 0 to 7 */ #define UFS_UPIU_MAX_WB_LUN_ID 8 +/* + * WriteBooster buffer lifetime has a limit setted by vendor. + * If it is over the limit, WriteBooster feature will be disabled. + */ +#define UFS_WB_EXCEED_LIFETIME 0x0B + /* Well known logical unit id in LUN field of UPIU */ enum { UFS_UPIU_REPORT_LUNS_WLUN = 0x81, diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index a673eedb2f059be2b163a94c3d622fa289962881..f76692053ca17813a1d237fb35aed0e327a832ea 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -421,6 +421,13 @@ static int ufs_intel_lkf_init(struct ufs_hba *hba) return err; } +static int ufs_intel_adl_init(struct ufs_hba *hba) +{ + hba->nop_out_timeout = 200; + hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8; + return ufs_intel_common_init(hba); +} + static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = { .name = "intel-pci", .init = ufs_intel_common_init, @@ -449,6 +456,15 @@ static struct ufs_hba_variant_ops ufs_intel_lkf_hba_vops = { .device_reset = ufs_intel_device_reset, }; +static struct ufs_hba_variant_ops ufs_intel_adl_hba_vops = { + .name = "intel-pci", + .init = ufs_intel_adl_init, + .exit = ufs_intel_common_exit, + .link_startup_notify = ufs_intel_link_startup_notify, + .resume = ufs_intel_resume, + .device_reset = ufs_intel_device_reset, +}; + #ifdef CONFIG_PM_SLEEP static int ufshcd_pci_restore(struct device *dev) { @@ -561,6 +577,8 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, { PCI_VDEVICE(INTEL, 0x98FA), (kernel_ulong_t)&ufs_intel_lkf_hba_vops }, + { PCI_VDEVICE(INTEL, 0x51FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x54FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, { } /* terminate list */ }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d892faaef7bf2ddee5c9de27caa6bd05ea4701fe..93046952cbb0305deb510c95cc5cb8bdad6db1c9 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -86,8 +86,6 @@ /* Polling time to wait for fDeviceInit */ #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */ -#define wlun_dev_to_hba(dv) shost_priv(to_scsi_device(dv)->host) - #define ufshcd_toggle_vreg(_dev, _vreg, _on) \ ({ \ int _ret; \ @@ -118,8 +116,13 @@ int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, if (!regs) return -ENOMEM; - for (pos = 0; pos < len; pos += 4) + for (pos = 0; pos < len; pos += 4) { + if (offset == 0 && + pos >= REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER && + pos <= REG_UIC_ERROR_CODE_DME) + continue; regs[pos / 4] = ufshcd_readl(hba, offset + pos); + } ufshcd_hex_dump(prefix, regs, len); kfree(regs); @@ -385,7 +388,7 @@ static void ufshcd_add_uic_command_trace(struct ufs_hba *hba, static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, enum ufs_trace_str_t str_t) { - u64 lba; + u64 lba = 0; u8 opcode = 0, group_id = 0; u32 intr, doorbell; struct ufshcd_lrb *lrbp = &hba->lrb[tag]; @@ -402,7 +405,6 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, return; opcode = cmd->cmnd[0]; - lba = scsi_get_lba(cmd); if (opcode == READ_10 || opcode == WRITE_10) { /* @@ -410,6 +412,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, */ transfer_len = be32_to_cpu(lrbp->ucd_req_ptr->sc.exp_data_transfer_len); + lba = scsi_get_lba(cmd); if (opcode == WRITE_10) group_id = lrbp->cmd->cmnd[6]; } else if (opcode == UNMAP) { @@ -417,6 +420,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag, * The number of Bytes to be unmapped beginning with the lba. */ transfer_len = blk_rq_bytes(rq); + lba = scsi_get_lba(cmd); } intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS); @@ -603,7 +607,12 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) "INVALID MODE", }; - dev_err(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", + /* + * Using dev_dbg to avoid messages during runtime PM to avoid + * never-ending cycles of messages written back to storage by user space + * causing runtime resume, causing more messages and so on. + */ + dev_dbg(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", __func__, hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, @@ -1107,6 +1116,12 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba) return pending; } +/* + * Wait until all pending SCSI commands and TMFs have finished or the timeout + * has expired. + * + * Return: 0 upon success; -EBUSY upon timeout. + */ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) { @@ -1140,7 +1155,7 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, } spin_unlock_irqrestore(hba->host->host_lock, flags); - schedule(); + io_schedule_timeout(msecs_to_jiffies(20)); if (ktime_to_us(ktime_sub(ktime_get(), start)) > wait_timeout_us) { timeout = true; @@ -1211,9 +1226,14 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) return ret; } -static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) +/* + * Wait until all pending SCSI commands and TMFs have finished or the timeout + * has expired. + * + * Return: 0 upon success; -EBUSY upon timeout. + */ +static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us) { - #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ int ret = 0; /* * make sure that there are no outstanding requests when @@ -1222,8 +1242,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) ufshcd_scsi_block_requests(hba); down_write(&hba->clk_scaling_lock); - if (!hba->clk_scaling.is_allowed || - ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) { + if (ufshcd_wait_for_doorbell_clr(hba, timeout_us)) { ret = -EBUSY; up_write(&hba->clk_scaling_lock); ufshcd_scsi_unblock_requests(hba); @@ -1261,10 +1280,18 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) int ret = 0; bool is_writelock = true; - ret = ufshcd_clock_scaling_prepare(hba); + if (!hba->clk_scaling.is_allowed) + return -EBUSY; + + ret = ufshcd_clock_scaling_prepare(hba, 1 * USEC_PER_SEC); if (ret) return ret; + if (!hba->clk_scaling.is_allowed) { + ret = -EBUSY; + goto out_unprepare; + } + /* scale down the gear before scaling down clocks */ if (!scale_up) { ret = ufshcd_scale_gear(hba, false); @@ -1678,6 +1705,26 @@ unblock_reqs: ufshcd_scsi_unblock_requests(hba); } +/* + * Block processing of new SCSI commands and wait until pending SCSI + * commands and TMFs have finished. ufshcd_exec_dev_cmd() and + * ufshcd_issue_devman_upiu_cmd() are not affected by this function. + * + * Return: 0 upon success; -EBUSY upon timeout. + */ +int ufshcd_freeze_scsi_devs(struct ufs_hba *hba, u64 timeout_us) +{ + return ufshcd_clock_scaling_prepare(hba, timeout_us); +} +EXPORT_SYMBOL_GPL(ufshcd_freeze_scsi_devs); + +/* Resume processing of SCSI commands. */ +void ufshcd_unfreeze_scsi_devs(struct ufs_hba *hba) +{ + ufshcd_clock_scaling_unprepare(hba, true); +} +EXPORT_SYMBOL_GPL(ufshcd_unfreeze_scsi_devs); + /** * ufshcd_hold - Enable clocks that were gated earlier due to ufshcd_release. * Also, exit from hibern8 mode and set the link as active. @@ -5065,6 +5112,12 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) pm_runtime_get_noresume(&sdev->sdev_gendev); else if (ufshcd_is_rpm_autosuspend_allowed(hba)) sdev->rpm_autosuspend = 1; + /* + * Do not print messages during runtime PM to avoid never-ending cycles + * of messages written back to storage by user space causing runtime + * resume, causing more messages and so on. + */ + sdev->silence_suspend = 1; ufshcd_crypto_setup_rq_keyslot_manager(hba, q); @@ -5825,6 +5878,47 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba, return false; } +static void ufshcd_wb_force_disable(struct ufs_hba *hba) +{ + if (!(hba->quirks & UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL)) + ufshcd_wb_toggle_flush(hba, false); + + ufshcd_wb_toggle_flush_during_h8(hba, false); + ufshcd_wb_toggle(hba, false); + hba->caps &= ~UFSHCD_CAP_WB_EN; + + dev_info(hba->dev, "%s: WB force disabled\n", __func__); +} + +static bool ufshcd_is_wb_buf_lifetime_available(struct ufs_hba *hba) +{ + u32 lifetime; + int ret; + u8 index; + + index = ufshcd_wb_get_query_index(hba); + ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST, + index, 0, &lifetime); + if (ret) { + dev_err(hba->dev, + "%s: bWriteBoosterBufferLifeTimeEst read failed %d\n", + __func__, ret); + return false; + } + + if (lifetime == UFS_WB_EXCEED_LIFETIME) { + dev_err(hba->dev, "%s: WB buf lifetime is exhausted 0x%02X\n", + __func__, lifetime); + return false; + } + + dev_dbg(hba->dev, "%s: WB buf lifetime is 0x%02X\n", + __func__, lifetime); + + return true; +} + static bool ufshcd_wb_need_flush(struct ufs_hba *hba) { int ret; @@ -5833,6 +5927,12 @@ static bool ufshcd_wb_need_flush(struct ufs_hba *hba) if (!ufshcd_is_wb_allowed(hba)) return false; + + if (!ufshcd_is_wb_buf_lifetime_available(hba)) { + ufshcd_wb_force_disable(hba); + return false; + } + /* * The ufs device needs the vcc to be ON to flush. * With user-space reduction enabled, it's enough to enable flush @@ -7388,7 +7488,13 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, if (!hba->vreg_info.vcc || !hba->vreg_info.vccq || !hba->vreg_info.vccq2) { - dev_err(hba->dev, + /* + * Using dev_dbg to avoid messages during runtime PM to avoid + * never-ending cycles of messages written back to storage by + * user space causing runtime resume, causing more messages and + * so on. + */ + dev_dbg(hba->dev, "%s: Regulator capability was not set, actvIccLevel=%d", __func__, icc_level); goto out; @@ -7535,6 +7641,7 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) if (!ufshcd_is_wb_allowed(hba)) return; + /* * Probe WB only for UFS-2.2 and UFS-3.1 (and later) devices or * UFS devices with quirk UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES @@ -7586,6 +7693,10 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, u8 *desc_buf) if (!d_lu_wb_buf_alloc) goto wb_disabled; } + + if (!ufshcd_is_wb_buf_lifetime_available(hba)) + goto wb_disabled; + return; wb_disabled: @@ -7864,7 +7975,7 @@ static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba) peer_pa_tactivate_us = peer_pa_tactivate * gran_to_us_table[peer_granularity - 1]; - if (pa_tactivate_us > peer_pa_tactivate_us) { + if (pa_tactivate_us >= peer_pa_tactivate_us) { u32 new_peer_pa_tactivate; new_peer_pa_tactivate = pa_tactivate_us / @@ -8664,7 +8775,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) * @pwr_mode: device power mode to set * * Returns 0 if requested power mode is set successfully - * Returns non-zero if failed to set the requested power mode + * Returns < 0 if failed to set the requested power mode */ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, enum ufs_dev_pwr_mode pwr_mode) @@ -8718,8 +8829,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, sdev_printk(KERN_WARNING, sdp, "START_STOP failed for power mode: %d, result %x\n", pwr_mode, ret); - if (ret > 0 && scsi_sense_valid(&sshdr)) - scsi_print_sense_hdr(sdp, NULL, &sshdr); + if (ret > 0) { + if (scsi_sense_valid(&sshdr)) + scsi_print_sense_hdr(sdp, NULL, &sshdr); + ret = -EIO; + } } if (!ret) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 88bc1b9c8768d1864663969fd8e02d351f4e7d43..4fc5deaa99dd62ddf8be120687a8bfcbd3f183f4 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -1219,11 +1219,11 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, u8 param_offset, u8 *param_read_buf, u8 param_size); +int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 selector, + u32 *attr_val); int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val); -int ufshcd_query_attr_retry(struct ufs_hba *hba, - enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, - u32 *attr_val); int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res); int ufshcd_query_flag_retry(struct ufs_hba *hba, @@ -1241,6 +1241,9 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); +int ufshcd_freeze_scsi_devs(struct ufs_hba *hba, u64 timeout_us); +void ufshcd_unfreeze_scsi_devs(struct ufs_hba *hba); + void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, int *desc_length); diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index 40c6c4515e6c67b5c1534fb69fff55a031580278..63078ce2a70e524851c708aaf946e0978e7ae23e 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -320,7 +320,7 @@ ufshpb_set_hpb_read_to_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, cdb[0] = UFSHPB_READ; if (hba->dev_quirks & UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ) - ppn_tmp = swab64(ppn); + ppn_tmp = (__force __be64)swab64((__force u64)ppn); /* ppn value is stored as big-endian in the host memory */ memcpy(&cdb[6], &ppn_tmp, sizeof(__be64)); diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 85f82e195ef8b7115536ea852a7fafd94cd1a3d2..f1875dc31ae2cb8991e98a3a28e6b52fcd5405a9 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -206,7 +206,6 @@ struct ocmem *of_get_ocmem(struct device *dev) ocmem = platform_get_drvdata(pdev); if (!ocmem) { dev_err(dev, "Cannot get ocmem\n"); - put_device(&pdev->dev); return ERR_PTR(-ENODEV); } return ocmem; diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 941499b117580fb8e6d49874030272a9c68f50f4..4fe88d4690e2b259de1279de7a3af46e76af533c 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -548,7 +548,7 @@ static int qmp_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(&pdev->dev, irq, qmp_intr, 0, + ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT, "aoss-qmp", qmp); if (ret < 0) { dev_err(&pdev->dev, "failed to request interrupt\n"); diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index c6084c0d35302ca2b94943d07d2bdc41dcb1a58f..f2168e4259b231485a91ade30f3515e48d8732ba 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -387,9 +387,6 @@ static int rpmpd_probe(struct platform_device *pdev) data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), GFP_KERNEL); - if (!data->domains) - return -ENOMEM; - data->num_domains = num; for (i = 0; i < num; i++) { diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index ef3f95fefab582d264e8fbbb5fe1d3ec45147cb9..e9ece45d7a3334e7612cc4f61c616873472e312c 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -447,9 +447,9 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { + if (!irq) { dev_err(&pdev->dev, "no irq resource\n"); - return irq; + return -ENXIO; } ret = devm_request_irq(dev, irq, wkup_m3_txev_handler, diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 824d9f900aca74e41e4b62a04420e7a0c8c951ec..dad4326a2a714219577d31eda64f22a28592e7aa 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -521,8 +521,8 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) /* Clear wake status */ wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); - wake_sts |= (SDW_SHIM_WAKESTS_STATUS << link_id); - intel_writew(shim, SDW_SHIM_WAKESTS, wake_sts); + wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); } mutex_unlock(sdw->link_res->shim_lock); } diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 4fb19e6f94b05256400c0d27b621418d10a63684..96b418293bf2a493dca92f016e7dc342120db141 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -304,21 +304,25 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf, writel(data, mxic->regs + TXD(nbytes % 4)); - ret = readl_poll_timeout(mxic->regs + INT_STS, sts, - sts & INT_TX_EMPTY, 0, USEC_PER_SEC); - if (ret) - return ret; - - ret = readl_poll_timeout(mxic->regs + INT_STS, sts, - sts & INT_RX_NOT_EMPTY, 0, - USEC_PER_SEC); - if (ret) - return ret; - - data = readl(mxic->regs + RXD); if (rxbuf) { + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + ret = readl_poll_timeout(mxic->regs + INT_STS, sts, + sts & INT_RX_NOT_EMPTY, 0, + USEC_PER_SEC); + if (ret) + return ret; + + data = readl(mxic->regs + RXD); data >>= (8 * (4 - nbytes)); memcpy(rxbuf + pos, &data, nbytes); + WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); + } else { + readl(mxic->regs + RXD); } WARN_ON(readl(mxic->regs + INT_STS) & INT_RX_NOT_EMPTY); diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 4eb979a096c78a49a9f3c272653a2766bdeece29..aafac128bb5f1816b092eff0a020c0b34ec9760f 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -74,23 +74,14 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param) return true; } -static void lpss_dma_put_device(void *dma_dev) -{ - pci_dev_put(dma_dev); -} - static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { struct pci_dev *dma_dev; - int ret; c->num_chipselect = 1; c->max_clk_rate = 50000000; dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); - ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); - if (ret) - return ret; if (c->tx_param) { struct dw_dma_slave *slave = c->tx_param; @@ -114,9 +105,8 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); struct dw_dma_slave *tx, *rx; - struct pci_dev *dma_dev; - int ret; switch (PCI_FUNC(dev->devfn)) { case 0: @@ -141,11 +131,6 @@ static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) return -ENODEV; } - dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); - ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); - if (ret) - return ret; - tx = c->tx_param; tx->dma_dev = &dma_dev->dev; diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index ed42665b12241b803a2dc7e2e6071b01bbda043d..a2e5907276e7fd6ce045ece59ceb8b0064d143b3 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1353,10 +1353,6 @@ static int tegra_spi_probe(struct platform_device *pdev) tspi->phys = r->start; spi_irq = platform_get_irq(pdev, 0); - if (spi_irq < 0) { - ret = spi_irq; - goto exit_free_master; - } tspi->irq = spi_irq; tspi->clk = devm_clk_get(&pdev->dev, "spi"); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 9e2b812b9025f69a668f157decf4a4a36b281848..669fc4286231f508743c50ffce21e86c0cb0b6d5 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1006,8 +1006,14 @@ static int tegra_slink_probe(struct platform_device *pdev) struct resource *r; int ret, spi_irq; const struct tegra_slink_chip_data *cdata = NULL; + const struct of_device_id *match; - cdata = of_device_get_match_data(&pdev->dev); + match = of_match_device(tegra_slink_of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + cdata = match->data; master = spi_alloc_master(&pdev->dev, sizeof(*tspi)); if (!master) { diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 3d3ac48243ebd6ae8813c527210ee87d98246afe..1dd2af9cc237441effef5a5ca9d55f54e454e24a 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1165,10 +1165,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_all; } - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); - if (ret) - goto clk_dis_all; - + dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS; ctlr->mem_ops = &zynqmp_qspi_mem_ops; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 2ff27f33210451dbb63ad52a49ce98e554f85f47..c640a9f4f1c8ff0cb4fc0ab4ba6edae97f2378dc 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -881,10 +881,10 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev, int i, ret; if (vmalloced_buf || kmap_buf) { - desc_len = min_t(unsigned long, max_seg_size, PAGE_SIZE); + desc_len = min_t(int, max_seg_size, PAGE_SIZE); sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); } else if (virt_addr_valid(buf)) { - desc_len = min_t(size_t, max_seg_size, ctlr->max_dma_len); + desc_len = min_t(int, max_seg_size, ctlr->max_dma_len); sgs = DIV_ROUND_UP(len, desc_len); } else { return -EINVAL; diff --git a/drivers/staging/android/ion/ion_buffer.c b/drivers/staging/android/ion/ion_buffer.c index 9baca1a472b6a456bf3cbe473d6a76ccc131dbc0..9c7a353a422096592ecb7efb7f4a118f09d40df3 100644 --- a/drivers/staging/android/ion/ion_buffer.c +++ b/drivers/staging/android/ion/ion_buffer.c @@ -249,6 +249,9 @@ void *ion_buffer_kmap_get(struct ion_buffer *buffer) void *vaddr; if (buffer->kmap_cnt) { + if (buffer->kmap_cnt == INT_MAX) + return ERR_PTR(-EOVERFLOW); + buffer->kmap_cnt++; return buffer->vaddr; } diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c index 0a2dbed9ffc74f3399fa0fc6e1de2afb648d3de8..3a280cc1892ca027062006f5e4b6450123f29543 100644 --- a/drivers/staging/fbtft/fb_st7789v.c +++ b/drivers/staging/fbtft/fb_st7789v.c @@ -82,8 +82,6 @@ enum st7789v_command { */ static int init_display(struct fbtft_par *par) { - par->fbtftops.reset(par); - /* turn off sleep mode */ write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); mdelay(120); diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 20183b2ea127962f347a9af6a7a4ea1a37eb5926..fef0055b89909fc0454870e602cecad237554873 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -107,9 +107,9 @@ static unsigned int ad7280a_devaddr(unsigned int addr) { return ((addr & 0x1) << 4) | - ((addr & 0x2) << 2) | + ((addr & 0x2) << 3) | (addr & 0x4) | - ((addr & 0x8) >> 2) | + ((addr & 0x8) >> 3) | ((addr & 0x10) >> 4); } diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c index b1614cce2dfb05dda05aac6d3d860caaceac1c2e..f638d0bd09fe6f4d3c956e17f79c050ac56de31d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.c +++ b/drivers/staging/media/atomisp/pci/atomisp_acc.c @@ -439,18 +439,6 @@ int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd, return 0; } -static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *asd, - int i, - struct atomisp_acc_fw *acc_fw) -{ - while (--i >= 0) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } -} - /* * Appends the loaded acceleration binary extensions to the * current ISP mode. Must be called just before sh_css_start(). @@ -489,20 +477,16 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) acc_fw->fw, acc_flag_to_pipe[i].pipe_id, acc_fw->type); - if (ret) { - atomisp_acc_unload_some_extensions(asd, i, acc_fw); + if (ret) goto error; - } ext_loaded = true; } } ret = atomisp_css_set_acc_parameters(acc_fw); - if (ret < 0) { - atomisp_acc_unload_some_extensions(asd, i, acc_fw); + if (ret < 0) goto error; - } } if (!ext_loaded) @@ -511,7 +495,6 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) ret = atomisp_css_update_stream(asd); if (ret) { dev_err(isp->dev, "%s: update stream failed.\n", __func__); - atomisp_acc_unload_extensions(asd); goto error; } @@ -519,6 +502,13 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) return 0; error: + while (--i >= 0) { + if (acc_fw->flags & acc_flag_to_pipe[i].flag) { + atomisp_css_unload_acc_extension(asd, acc_fw->fw, + acc_flag_to_pipe[i].pipe_id); + } + } + list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) { if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index c9ee85037644fdd893ca94f3889d16515ef6967a..34480ca164746fe58d1f141ba1dbc7ff4fbcd223 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -729,21 +729,6 @@ static int axp_regulator_set(struct device *dev, struct gmin_subdev *gs, return 0; } -/* - * Some boards contain a hw-bug where turning eldo2 back on after having turned - * it off causes the CPLM3218 ambient-light-sensor on the image-sensor's I2C bus - * to crash, hanging the bus. Do not turn eldo2 off on these systems. - */ -static const struct dmi_system_id axp_leave_eldo2_on_ids[] = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), - DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab duo W1 10.1 (VT4)"), - }, - }, - { } -}; - static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) { int ret; @@ -778,9 +763,6 @@ static int axp_v1p8_off(struct device *dev, struct gmin_subdev *gs) if (ret) return ret; - if (dmi_check_system(axp_leave_eldo2_on_ids)) - return 0; - ret = axp_regulator_set(dev, gs, gs->eldo2_sel_reg, gs->eldo2_1p8v, ELDO_CTRL_REG, gs->eldo2_ctrl_shift, false); return ret; diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c index c1cda16f2dc018d10ca9014511dca2c3688ec80b..6a5ee46070898b3b15cd44b1cf4ea594a5e3f307 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -39,7 +39,7 @@ struct hmm_bo_device bo_device; struct hmm_pool dynamic_pool; struct hmm_pool reserved_pool; -static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; +static ia_css_ptr dummy_ptr; static bool hmm_initialized; struct _hmm_mem_stat hmm_mem_stat; @@ -209,7 +209,7 @@ int hmm_init(void) void hmm_cleanup(void) { - if (dummy_ptr == mmgr_EXCEPTION) + if (!dummy_ptr) return; sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); @@ -288,8 +288,7 @@ void hmm_free(ia_css_ptr virt) dev_dbg(atomisp_dev, "%s: free 0x%08x\n", __func__, virt); - if (WARN_ON(virt == mmgr_EXCEPTION)) - return; + WARN_ON(!virt); bo = hmm_bo_device_search_start(&bo_device, (unsigned int)virt); diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index ed244aee196c3d6d631a7f64905679050de6cf08..b88dc4ed06db710806a1d647bf5624e582dca395 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -23,7 +23,7 @@ static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | H1_REG_IN_IMG_CTRL_OVRFLB(0) + | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0) | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/staging/media/hantro/hantro_h1_regs.h index 30e7e7b920b553aeca0c3fc1ca4be04712d8ef42..d6e9825bb5c7be3ca3e336c3649c5bfc7b697b78 100644 --- a/drivers/staging/media/hantro/hantro_h1_regs.h +++ b/drivers/staging/media/hantro/hantro_h1_regs.h @@ -47,7 +47,7 @@ #define H1_REG_IN_IMG_CTRL 0x03c #define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) #define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define H1_REG_IN_IMG_CTRL_OVRFLB(x) ((x) << 6) +#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) #define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) #define H1_REG_ENC_CTRL0 0x040 #define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c index 86ccc8937afcaf0a89c96cfc92d3a13de3ee2121..db7022707ff8dd4ce5cfd9f89203c2e46885da3b 100644 --- a/drivers/staging/media/meson/vdec/esparser.c +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -328,12 +328,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) offset = esparser_get_offset(sess); - ret = amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); - if (ret) { - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - return ret; - } - + amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X flags = %08X\n", vb->timestamp, payload_size, offset, vbuf->flags); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c index db4a854e59a38df94fc72084c38e8fc9174e7783..7f07a9175815f025a918e0ecb33788e516e2735c 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.c +++ b/drivers/staging/media/meson/vdec/vdec_helpers.c @@ -227,16 +227,13 @@ int amvdec_set_canvases(struct amvdec_session *sess, } EXPORT_SYMBOL_GPL(amvdec_set_canvases); -int amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) +void amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) { struct amvdec_timestamp *new_ts; unsigned long flags; new_ts = kzalloc(sizeof(*new_ts), GFP_KERNEL); - if (!new_ts) - return -ENOMEM; - new_ts->ts = ts; new_ts->tc = tc; new_ts->offset = offset; @@ -245,7 +242,6 @@ int amvdec_add_ts(struct amvdec_session *sess, u64 ts, spin_lock_irqsave(&sess->ts_spinlock, flags); list_add_tail(&new_ts->list, &sess->timestamps); spin_unlock_irqrestore(&sess->ts_spinlock, flags); - return 0; } EXPORT_SYMBOL_GPL(amvdec_add_ts); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h index 798e5a8a9b3f19b83f4d56779bbb3e2b358b0d40..cfaed52ab526577e17d2d50659a9761a498a9235 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.h +++ b/drivers/staging/media/meson/vdec/vdec_helpers.h @@ -55,8 +55,8 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess, * @offset: offset in the VIFIFO where the associated packet was written * @flags the vb2_v4l2_buffer flags */ -int amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 flags); +void amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 flags); void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); /** diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index d3e26bfe6c90b21c9a222263c483a2c69f35f694..de7442d4834dcab1237dc7f9558021c6871c1551 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -38,7 +38,7 @@ struct cedrus_h264_sram_ref_pic { #define CEDRUS_H264_FRAME_NUM 18 -#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (32 * SZ_1K) +#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K) #define CEDRUS_MIN_PIC_INFO_BUF_SIZE (130 * SZ_1K) static void cedrus_h264_write_sram(struct cedrus_dev *dev, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 368439cf5e1744229dda9b6fb16eb7ee4267d551..10744fab7ceaa1e11471d9b4ace77794d45e2bd7 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -23,7 +23,7 @@ * Subsequent BSP implementations seem to double the neighbor info buffer size * for the H6 SoC, which may be related to 10 bit H265 support. */ -#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (794 * SZ_1K) +#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (397 * SZ_1K) #define CEDRUS_H265_ENTRY_POINTS_BUF_SIZE (4 * SZ_1K) #define CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE 160 diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index 3f223e5b1872ba2e687721639a0793ba8a7ae364..e7fe8da7732c7845189fe9b0fb52bde7db288829 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -314,6 +314,6 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) #endif -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir); +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq); void zoran_queue_exit(struct zoran *zr); int zr_set_buf(struct zoran *zr); diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index fe0cca12119c7510c6041f2fc5800fe1f26a52c9..dfc60e2e9dd7ab355cffd7731fa4b1a9e290aa39 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -802,52 +802,6 @@ int zoran_check_jpg_settings(struct zoran *zr, return 0; } -static int zoran_init_video_device(struct zoran *zr, struct video_device *video_dev, int dir) -{ - int err; - - /* Now add the template and register the device unit. */ - *video_dev = zoran_template; - video_dev->v4l2_dev = &zr->v4l2_dev; - video_dev->lock = &zr->lock; - video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | dir; - - strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); - /* - * It's not a mem2mem device, but you can both capture and output from one and the same - * device. This should really be split up into two device nodes, but that's a job for - * another day. - */ - video_dev->vfl_dir = VFL_DIR_M2M; - zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - err = video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); - if (err < 0) - return err; - video_set_drvdata(video_dev, zr); - return 0; -} - -static void zoran_exit_video_devices(struct zoran *zr) -{ - video_unregister_device(zr->video_dev); - kfree(zr->video_dev); -} - -static int zoran_init_video_devices(struct zoran *zr) -{ - int err; - - zr->video_dev = video_device_alloc(); - if (!zr->video_dev) - return -ENOMEM; - - err = zoran_init_video_device(zr, zr->video_dev, V4L2_CAP_VIDEO_CAPTURE); - if (err) - kfree(zr->video_dev); - return err; -} - void zoran_open_init_params(struct zoran *zr) { int i; @@ -919,11 +873,17 @@ static int zr36057_init(struct zoran *zr) zoran_open_init_params(zr); /* allocate memory *before* doing anything to the hardware in case allocation fails */ + zr->video_dev = video_device_alloc(); + if (!zr->video_dev) { + err = -ENOMEM; + goto exit; + } zr->stat_com = dma_alloc_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), &zr->p_sc, GFP_KERNEL); if (!zr->stat_com) { - return -ENOMEM; + err = -ENOMEM; + goto exit_video; } for (j = 0; j < BUZ_NUM_STAT_COM; j++) zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ @@ -936,9 +896,26 @@ static int zr36057_init(struct zoran *zr) goto exit_statcom; } - err = zoran_init_video_devices(zr); - if (err) + /* Now add the template and register the device unit. */ + *zr->video_dev = zoran_template; + zr->video_dev->v4l2_dev = &zr->v4l2_dev; + zr->video_dev->lock = &zr->lock; + zr->video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; + + strscpy(zr->video_dev->name, ZR_DEVNAME(zr), sizeof(zr->video_dev->name)); + /* + * It's not a mem2mem device, but you can both capture and output from one and the same + * device. This should really be split up into two device nodes, but that's a job for + * another day. + */ + zr->video_dev->vfl_dir = VFL_DIR_M2M; + + zoran_queue_init(zr, &zr->vq); + + err = video_register_device(zr->video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); + if (err < 0) goto exit_statcomb; + video_set_drvdata(zr->video_dev, zr); zoran_init_hardware(zr); if (!pass_through) { @@ -953,6 +930,9 @@ exit_statcomb: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); exit_statcom: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc); +exit_video: + kfree(zr->video_dev); +exit: return err; } @@ -984,7 +964,7 @@ static void zoran_remove(struct pci_dev *pdev) dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); pci_release_regions(pdev); pci_disable_device(zr->pci_dev); - zoran_exit_video_devices(zr); + video_unregister_device(zr->video_dev); exit_free: v4l2_ctrl_handler_free(&zr->hdl); v4l2_device_unregister(&zr->v4l2_dev); @@ -1088,10 +1068,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) - return err; - err = vb2_dma_contig_set_max_seg_size(&pdev->dev, U32_MAX); - if (err) - return err; + return -ENODEV; + vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); nr = zoran_num++; if (nr >= BUZ_MAX) { diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c index 913f5a3c5bfce083389678c797ed4c999b461ab4..e569a1341d0103d2b329841ba81b228fa64c443d 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/staging/media/zoran/zoran_device.c @@ -879,7 +879,7 @@ static void zoran_reap_stat_com(struct zoran *zr) if (zr->jpg_settings.tmp_dcm == 1) i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; + i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2 + 1; stat_com = le32_to_cpu(zr->stat_com[i]); if ((stat_com & 1) == 0) { @@ -891,11 +891,6 @@ static void zoran_reap_stat_com(struct zoran *zr) size = (stat_com & GENMASK(22, 1)) >> 1; buf = zr->inuse[i]; - if (!buf) { - spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); - pci_err(zr->pci_dev, "No buffer at slot %d\n", i); - return; - } buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index ea04f6c732b212bf61f17e444012244a0f1719cf..808196ea5b81b14e8e6ae46657a95c7c19fbad81 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -255,6 +255,8 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); strscpy(cap->driver, "zoran", sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci_dev)); + cap->device_caps = zr->video_dev->device_caps; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -580,9 +582,6 @@ static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) struct zoran *zr = video_drvdata(file); int res = 0; - if (zr->norm == std) - return 0; - if (zr->running != ZORAN_MAP_MODE_NONE) return -EBUSY; @@ -738,7 +737,6 @@ static int zoran_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - parm->parm.capture.readbuffers = 9; return 0; } @@ -869,10 +867,6 @@ int zr_set_buf(struct zoran *zr) vbuf = &buf->vbuf; buf->vbuf.field = V4L2_FIELD_INTERLACED; - if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) - buf->vbuf.field = V4L2_FIELD_INTERLACED; - else - buf->vbuf.field = V4L2_FIELD_TOP; vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size); vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); zr->inuse[0] = NULL; @@ -932,7 +926,6 @@ static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) zr->stat_com[j] = cpu_to_le32(1); zr->inuse[j] = NULL; } - zr->vbseq = 0; if (zr->map_mode != ZORAN_MAP_MODE_RAW) { pci_info(zr->pci_dev, "START JPG\n"); @@ -1013,7 +1006,7 @@ static const struct vb2_ops zr_video_qops = { .wait_finish = vb2_ops_wait_finish, }; -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq) { int err; @@ -1021,9 +1014,8 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) INIT_LIST_HEAD(&zr->queued_bufs); vq->dev = &zr->pci_dev->dev; - vq->type = dir; - - vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->io_modes = VB2_USERPTR | VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; vq->drv_priv = zr; vq->buf_struct_size = sizeof(struct zr_buffer); vq->ops = &zr_video_qops; diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index d48ca5a25c2c4f635b176ba74c26a68485b48d95..a7c0d3115d7264f36b25c563a9ccee03c9923e2d 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -11,8 +11,7 @@ memory@0 { device_type = "memory"; - reg = <0x00000000 0x1c000000>, - <0x20000000 0x04000000>; + reg = <0x0 0x1c000000>, <0x20000000 0x4000000>; }; chosen { @@ -38,16 +37,24 @@ gpio-leds { compatible = "gpio-leds"; - power { - label = "green:power"; + system { + label = "gb-pc1:green:system"; gpios = <&gpio 6 GPIO_ACTIVE_LOW>; - linux,default-trigger = "default-on"; }; - system { - label = "green:system"; + status { + label = "gb-pc1:green:status"; gpios = <&gpio 8 GPIO_ACTIVE_LOW>; - linux,default-trigger = "disk-activity"; + }; + + lan1 { + label = "gb-pc1:green:lan1"; + gpios = <&gpio 24 GPIO_ACTIVE_LOW>; + }; + + lan2 { + label = "gb-pc1:green:lan2"; + gpios = <&gpio 25 GPIO_ACTIVE_LOW>; }; }; }; @@ -87,8 +94,9 @@ partition@50000 { label = "firmware"; - reg = <0x50000 0x1fb0000>; + reg = <0x50000 0x1FB0000>; }; + }; }; @@ -114,12 +122,9 @@ }; &pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&state_default>; - - state_default: state-default { - gpio-pinmux { - groups = "rgmii2", "uart3", "wdt"; + state_default: pinctrl0 { + default_gpio: gpio { + groups = "wdt", "rgmii2", "uart3"; function = "gpio"; }; }; @@ -128,13 +133,12 @@ &switch0 { ports { port@0 { - status = "okay"; label = "ethblack"; + status = "ok"; }; - port@4 { - status = "okay"; label = "ethblue"; + status = "ok"; }; }; }; diff --git a/drivers/staging/mt7621-dts/gbpc2.dts b/drivers/staging/mt7621-dts/gbpc2.dts index 6f6fed071dda01de8bded044ecf49b1698fd2c5f..52760e7351f6c855ed6d9b2fe0521c067461f705 100644 --- a/drivers/staging/mt7621-dts/gbpc2.dts +++ b/drivers/staging/mt7621-dts/gbpc2.dts @@ -1,121 +1,21 @@ /dts-v1/; -#include "mt7621.dtsi" - -#include -#include +#include "gbpc1.dts" / { compatible = "gnubee,gb-pc2", "mediatek,mt7621-soc"; model = "GB-PC2"; - - memory@0 { - device_type = "memory"; - reg = <0x00000000 0x1c000000>, - <0x20000000 0x04000000>; - }; - - chosen { - bootargs = "console=ttyS0,57600"; - }; - - palmbus: palmbus@1e000000 { - i2c@900 { - status = "okay"; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - - reset { - label = "reset"; - gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; - linux,code = ; - }; - }; -}; - -&sdhci { - status = "okay"; -}; - -&spi0 { - status = "okay"; - - m25p80@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - broken-flash-reset; - - partition@0 { - label = "u-boot"; - reg = <0x0 0x30000>; - read-only; - }; - - partition@30000 { - label = "u-boot-env"; - reg = <0x30000 0x10000>; - read-only; - }; - - factory: partition@40000 { - label = "factory"; - reg = <0x40000 0x10000>; - read-only; - }; - - partition@50000 { - label = "firmware"; - reg = <0x50000 0x1fb0000>; - }; - }; }; -&pcie { - status = "okay"; +&default_gpio { + groups = "wdt", "uart3"; + function = "gpio"; }; -&pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&state_default>; - - state_default: state-default { - gpio-pinmux { - groups = "wdt"; - function = "gpio"; - }; - }; +&gmac1 { + status = "ok"; }; -ðernet { - gmac1: mac@1 { - status = "okay"; - phy-handle = <ðphy7>; - }; - - mdio-bus { - ethphy7: ethernet-phy@7 { - reg = <7>; - phy-mode = "rgmii-rxid"; - }; - }; -}; - -&switch0 { - ports { - port@0 { - status = "okay"; - label = "ethblack"; - }; - - port@4 { - status = "okay"; - label = "ethblue"; - }; - }; +&phy_external { + status = "ok"; }; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 91a7fa74829643d898dcb515ce1caeceabf7b411..27222f7b246fd970d982be1c483a87aa6838b7ac 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -56,9 +56,9 @@ regulator-max-microvolt = <3300000>; enable-active-high; regulator-always-on; - }; + }; - mmc_fixed_1v8_io: fixedregulator@1 { + mmc_fixed_1v8_io: fixedregulator@1 { compatible = "regulator-fixed"; regulator-name = "mmc_io"; regulator-min-microvolt = <1800000>; @@ -412,32 +412,37 @@ mediatek,ethsys = <ðsys>; - pinctrl-names = "default"; - pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>, <&rgmii2_pins>; gmac0: mac@0 { compatible = "mediatek,eth-mac"; reg = <0>; phy-mode = "rgmii"; - fixed-link { speed = <1000>; full-duplex; pause; }; }; - gmac1: mac@1 { compatible = "mediatek,eth-mac"; reg = <1>; status = "off"; phy-mode = "rgmii-rxid"; + phy-handle = <&phy_external>; }; - mdio-bus { #address-cells = <1>; #size-cells = <0>; + phy_external: ethernet-phy@5 { + status = "off"; + reg = <5>; + phy-mode = "rgmii-rxid"; + + pinctrl-names = "default"; + pinctrl-0 = <&rgmii2_pins>; + }; + switch0: switch0@0 { compatible = "mediatek,mt7621"; #address-cells = <1>; @@ -451,43 +456,36 @@ #address-cells = <1>; #size-cells = <0>; reg = <0>; - port@0 { status = "off"; reg = <0>; label = "lan0"; }; - port@1 { status = "off"; reg = <1>; label = "lan1"; }; - port@2 { status = "off"; reg = <2>; label = "lan2"; }; - port@3 { status = "off"; reg = <3>; label = "lan3"; }; - port@4 { status = "off"; reg = <4>; label = "lan4"; }; - port@6 { reg = <6>; label = "cpu"; ethernet = <&gmac0>; phy-mode = "trgmii"; - fixed-link { speed = <1000>; full-duplex; diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 56ae882fb7b39c930f71ce689165e0f0f2bf5fb5..1411f0cb40c51c4cb150726b18d13902883ccc45 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3652,6 +3652,7 @@ static void __exit target_core_exit_configfs(void) MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); module_init(target_core_init_configfs); module_exit(target_core_exit_configfs); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 7143d03f0e027e916e179cd2b44301609816fb6e..cfa1bbef32e2ec2023748d6f663b6de8e14df7f8 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -956,6 +956,7 @@ static void __exit fileio_module_exit(void) MODULE_DESCRIPTION("TCM FILEIO subsystem plugin"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); module_init(fileio_module_init); module_exit(fileio_module_exit); diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 72a26867c2092fff21799ca3c89b4bd2633d7775..793d7b58fc6501b80b77bb5b42ee6439f9955e69 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -53,7 +53,7 @@ struct int3400_thermal_priv { struct art *arts; int trt_count; struct trt *trts; - u32 uuid_bitmap; + u8 uuid_bitmap; int rel_misc_dev_res; int current_uuid_index; char *data_vault; @@ -466,11 +466,6 @@ static void int3400_setup_gddv(struct int3400_thermal_priv *priv) priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer, obj->package.elements[0].buffer.length, GFP_KERNEL); - if (!priv->data_vault) { - kfree(buffer.pointer); - return; - } - bin_attr_data_vault.private = priv->data_vault; bin_attr_data_vault.size = obj->package.elements[0].buffer.length; kfree(buffer.pointer); diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 796fbff623f6e9fbe0c27290922cd0bebd689ca5..2af1e5751bd6302463a397cedd68bdccb23d8313 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1470,9 +1470,7 @@ out_error: */ static int __init hvc_iucv_config(char *val) { - if (kstrtoul(val, 10, &hvc_iucv_devices)) - pr_warn("hvc_iucv= invalid parameter value '%s'\n", val); - return 1; + return kstrtoul(val, 10, &hvc_iucv_devices); } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8344265a1948bf78acc66f836f79e75cd7d33f93..3703987c46661396bbf3c276a4ce295e3157ca0b 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -858,7 +858,6 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) struct mxser_port *info = container_of(port, struct mxser_port, port); unsigned long page; unsigned long flags; - int ret; page = __get_free_page(GFP_KERNEL); if (!page) @@ -868,9 +867,9 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (!info->ioaddr || !info->type) { set_bit(TTY_IO_ERROR, &tty->flags); + free_page(page); spin_unlock_irqrestore(&info->slock, flags); - ret = 0; - goto err_free_xmit; + return 0; } info->port.xmit_buf = (unsigned char *) page; @@ -896,10 +895,8 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); return 0; - } - - ret = -ENODEV; - goto err_free_xmit; + } else + return -ENODEV; } /* @@ -944,10 +941,6 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); return 0; -err_free_xmit: - free_page(page); - info->port.xmit_buf = NULL; - return ret; } /* diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index b3c3f7e5851aba3a17ccb7f80f18586c5aac4e4c..890fa7ddaa7f36650a1b69a8554e5567fd674f84 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -64,19 +64,10 @@ int serial8250_tx_dma(struct uart_8250_port *p) struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; struct dma_async_tx_descriptor *desc; - struct uart_port *up = &p->port; int ret; - if (dma->tx_running) { - if (up->x_char) { - dmaengine_pause(dma->txchan); - uart_xchar_out(up, UART_TX); - dmaengine_resume(dma->txchan); - } + if (dma->tx_running) return 0; - } else if (up->x_char) { - uart_xchar_out(up, UART_TX); - } if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) { /* We have been called from __dma_tx_complete() */ diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index dfb730b7ea2ae7b20ab0e42ff49d4ff78cb302b8..4dee8a9e0c9512ae65f39e8b44e3bf10e861db29 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -121,7 +121,8 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { struct dw_dma_slave *param = &lpss->dma_param; struct pci_dev *pdev = to_pci_dev(port->dev); - struct pci_dev *dma_dev; + unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn); switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: @@ -140,8 +141,6 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return -EINVAL; } - dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); - param->dma_dev = &dma_dev->dev; param->m_master = 0; param->p_master = 1; @@ -157,26 +156,11 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) return 0; } -static void byt_serial_exit(struct lpss8250 *lpss) -{ - struct dw_dma_slave *param = &lpss->dma_param; - - /* Paired with pci_get_slot() in the byt_serial_setup() above */ - put_device(param->dma_dev); -} - static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { return 0; } -static void ehl_serial_exit(struct lpss8250 *lpss) -{ - struct uart_8250_port *up = serial8250_get_port(lpss->data.line); - - up->dma = NULL; -} - #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, @@ -351,7 +335,8 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_exit: - lpss->board->exit(lpss); + if (lpss->board->exit) + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); return ret; } @@ -362,7 +347,8 @@ static void lpss8250_remove(struct pci_dev *pdev) serial8250_unregister_port(lpss->data.line); - lpss->board->exit(lpss); + if (lpss->board->exit) + lpss->board->exit(lpss); pci_free_irq_vectors(pdev); } @@ -370,14 +356,12 @@ static const struct lpss8250_board byt_board = { .freq = 100000000, .base_baud = 2764800, .setup = byt_serial_setup, - .exit = byt_serial_exit, }; static const struct lpss8250_board ehl_board = { .freq = 200000000, .base_baud = 12500000, .setup = ehl_serial_setup, - .exit = ehl_serial_exit, }; static const struct lpss8250_board qrk_board = { diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index e6c1791609ddf339427212a857eddcb1f98d8a10..efa0515139f8ec052486a414f614519780ff96d3 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -73,11 +73,6 @@ static int pnw_setup(struct mid8250 *mid, struct uart_port *p) return 0; } -static void pnw_exit(struct mid8250 *mid) -{ - pci_dev_put(mid->dma_dev); -} - static int tng_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; @@ -129,11 +124,6 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) return 0; } -static void tng_exit(struct mid8250 *mid) -{ - pci_dev_put(mid->dma_dev); -} - static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; @@ -340,9 +330,9 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, mid); return 0; - err: - mid->board->exit(mid); + if (mid->board->exit) + mid->board->exit(mid); return ret; } @@ -352,7 +342,8 @@ static void mid8250_remove(struct pci_dev *pdev) serial8250_unregister_port(mid->line); - mid->board->exit(mid); + if (mid->board->exit) + mid->board->exit(mid); } static const struct mid8250_board pnw_board = { @@ -360,7 +351,6 @@ static const struct mid8250_board pnw_board = { .freq = 50000000, .base_baud = 115200, .setup = pnw_setup, - .exit = pnw_exit, }; static const struct mid8250_board tng_board = { @@ -368,7 +358,6 @@ static const struct mid8250_board tng_board = { .freq = 38400000, .base_baud = 1843200, .setup = tng_setup, - .exit = tng_exit, }; static const struct mid8250_board dnv_board = { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3055353514e1dd891f3cbe5278513d77311624bb..7c07ebb37b1b9c07ff15a6f5f303ac493f7421dc 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1620,18 +1620,6 @@ static inline void start_tx_rs485(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_em485 *em485 = up->em485; - /* - * While serial8250_em485_handle_stop_tx() is a noop if - * em485->active_timer != &em485->stop_tx_timer, it might happen that - * the timer is still armed and triggers only after the current bunch of - * chars is send and em485->active_timer == &em485->stop_tx_timer again. - * So cancel the timer. There is still a theoretical race condition if - * the timer is already running and only comes around to check for - * em485->active_timer when &em485->stop_tx_timer is armed again. - */ - if (em485->active_timer == &em485->stop_tx_timer) - hrtimer_try_to_cancel(&em485->stop_tx_timer); - em485->active_timer = NULL; if (em485->tx_stopped) { @@ -1817,7 +1805,9 @@ void serial8250_tx_chars(struct uart_8250_port *up) int count; if (port->x_char) { - uart_xchar_out(port, UART_TX); + serial_out(up, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; return; } if (uart_tx_stopped(port)) { diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 79b7db8580e05c9240e447b83d42137fc7f3a8a9..49d0c7f2b29b8f927915327025a84a555a73a7bd 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -403,16 +403,16 @@ static int kgdboc_option_setup(char *opt) { if (!opt) { pr_err("config string not provided\n"); - return 1; + return -EINVAL; } if (strlen(opt) >= MAX_CONFIG_LEN) { pr_err("config string too long\n"); - return 1; + return -ENOSPC; } strcpy(config, opt); - return 1; + return 0; } __setup("kgdboc=", kgdboc_option_setup); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 19f0c5db11e3364c2716c6158f724cf8c2013e05..be0d9922e320e04a0c609cbece0e66a8b698b1a0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -676,20 +676,6 @@ static void uart_flush_buffer(struct tty_struct *tty) tty_port_tty_wakeup(&state->port); } -/* - * This function performs low-level write of high-priority XON/XOFF - * character and accounting for it. - * - * Requires uart_port to implement .serial_out(). - */ -void uart_xchar_out(struct uart_port *uport, int offset) -{ - serial_port_out(uport, offset, uport->x_char); - uport->icount.tx++; - uport->x_char = 0; -} -EXPORT_SYMBOL_GPL(uart_xchar_out); - /* * This function is used to send a high-priority XON/XOFF character to * the device diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 49f59d53b4b26d213b21efa62eee468c79a20e0c..58274c507353120062531efac0f1b174219e9fb1 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1889,7 +1889,6 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, struct usbtmc_ctrlrequest request; u8 *buffer = NULL; int rv; - unsigned int is_in, pipe; unsigned long res; res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); @@ -1899,14 +1898,12 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (request.req.wLength > USBTMC_BUFSIZE) return -EMSGSIZE; - is_in = request.req.bRequestType & USB_DIR_IN; - if (request.req.wLength) { buffer = kmalloc(request.req.wLength, GFP_KERNEL); if (!buffer) return -ENOMEM; - if (!is_in) { + if ((request.req.bRequestType & USB_DIR_IN) == 0) { /* Send control data to device */ res = copy_from_user(buffer, request.data, request.req.wLength); @@ -1917,12 +1914,8 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, } } - if (is_in) - pipe = usb_rcvctrlpipe(data->usb_dev, 0); - else - pipe = usb_sndctrlpipe(data->usb_dev, 0); rv = usb_control_msg(data->usb_dev, - pipe, + usb_rcvctrlpipe(data->usb_dev, 0), request.req.bRequest, request.req.bRequestType, request.req.wValue, @@ -1934,7 +1927,7 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, goto exit; } - if (rv && is_in) { + if (rv && (request.req.bRequestType & USB_DIR_IN)) { /* Read control data from device */ res = copy_to_user(request.data, buffer, rv); if (res) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index be4690bcf1302c1819392acd4b9cf589222a641b..a448277e27f088abb02b87e1bbc29a85ad01e86b 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1566,6 +1566,12 @@ static int dwc3_probe(struct platform_device *pdev) dwc3_get_properties(dwc); + if (!dwc->sysdev_is_parent) { + ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); + if (ret) + return ret; + } + dwc->reset = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(dwc->reset)) return PTR_ERR(dwc->reset); @@ -1712,11 +1718,6 @@ static int dwc3_remove(struct platform_device *pdev) return 0; } -static void dwc3_shutdown(struct platform_device *pdev) -{ - dwc3_remove(pdev); -} - #ifdef CONFIG_PM static int dwc3_core_init_for_resume(struct dwc3 *dwc) { @@ -2034,7 +2035,6 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); static struct platform_driver dwc3_driver = { .probe = dwc3_probe, .remove = dwc3_remove, - .shutdown = dwc3_shutdown, .driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 66a603f3327d66faab9347cf53f74fb0922d2f57..3510f6d39f0c3be9275a73efcc084c7cb2363945 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c @@ -931,6 +931,7 @@ static const struct file_operations acc_fops = { .read = acc_read, .write = acc_write, .unlocked_ioctl = acc_ioctl, + .compat_ioctl = acc_ioctl, .open = acc_open, .release = acc_release, }; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 73a28f8a38a7e1ea713e424949110b8c944bd05e..03db2d6b2dbae45834c8e9edfad75d022c93407a 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3446,6 +3446,7 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR("Michal Nazarewicz"); /************************* Module parameters *************************/ diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c index e2d7f69128a0e85b36088325dba484697280e9bf..8ffd477e79e11bca72b11e0540fbc9fe9c22610c 100644 --- a/drivers/usb/gadget/function/f_uac1_legacy.c +++ b/drivers/usb/gadget/function/f_uac1_legacy.c @@ -1015,4 +1015,5 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) DECLARE_USB_FUNCTION_INIT(uac1_legacy, f_audio_alloc_inst, f_audio_alloc); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR("Bryan Wu"); diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 4150de96b937a70cee0b52ddcdf6d3b5acfc0918..0f14c5291af0742af2b33695711912210297b490 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -640,7 +640,6 @@ static int rndis_set_response(struct rndis_params *params, BufLength = le32_to_cpu(buf->InformationBufferLength); BufOffset = le32_to_cpu(buf->InformationBufferOffset); if ((BufLength > RNDIS_MAX_TOTAL_SIZE) || - (BufOffset > RNDIS_MAX_TOTAL_SIZE) || (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE)) return -EINVAL; diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index f7e6c42558eb768e58ffcf37a9996e25802cdc36..2451e45ada6ede2753c995f747d87e99d093f145 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -520,3 +520,4 @@ ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, EXPORT_SYMBOL_GPL(fsg_store_inquiry_string); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index e1e243e52a2d5cd08b260a621c872a4adc5c9bc0..24d0ace3ed3c2ba81925beecae60f5e26d6571f2 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1437,6 +1437,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) usb_gadget_udc_stop(udc); udc->driver = NULL; + udc->dev.driver = NULL; udc->gadget->dev.driver = NULL; } @@ -1498,6 +1499,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri driver->function); udc->driver = driver; + udc->dev.driver = &driver->driver; udc->gadget->dev.driver = &driver->driver; usb_gadget_udc_set_speed(udc, driver->max_speed); @@ -1520,6 +1522,7 @@ err1: dev_err(&udc->dev, "failed to start %s: %d\n", udc->driver->function, ret); udc->driver = NULL; + udc->dev.driver = NULL; udc->gadget->dev.driver = NULL; return ret; } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 7ec04d4e664645143308770f04cb32c85fdf82fd..e0cd2825fcdcec662194248dfd42f1409007b775 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -681,7 +681,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci) } pm_runtime_allow(xhci_to_hcd(xhci)->self.controller); xhci->test_mode = 0; - return xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + return xhci_reset(xhci); } void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, @@ -1007,9 +1007,6 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status, if (link_state == XDEV_U2) *status |= USB_PORT_STAT_L1; if (link_state == XDEV_U0) { - if (bus_state->resume_done[portnum]) - usb_hcd_end_port_resume(&port->rhub->hcd->self, - portnum); bus_state->resume_done[portnum] = 0; clear_bit(portnum, &bus_state->resuming_ports); if (bus_state->suspended_ports & (1 << portnum)) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 644ddcb26e7632fc637956941feccd44427b8bc1..4324fd31b2c4589b0c49e14c5bacea51bec63e7b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2695,7 +2695,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) fail: xhci_halt(xhci); - xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + xhci_reset(xhci); xhci_mem_cleanup(xhci); return -ENOMEM; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index dfb3ab2afbceedfb461c017803cdd5d7aca30b3a..f39db28ef040ab1575bc9cc262bab9ee86091b4a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -65,7 +65,7 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) * handshake done). There are two failure modes: "usec" have passed (major * hardware flakeout), or the register reads as all-ones (hardware removed). */ -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us) +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; int ret; @@ -73,7 +73,7 @@ int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us) ret = readl_poll_timeout_atomic(ptr, result, (result & mask) == done || result == U32_MAX, - 1, timeout_us); + 1, usec); if (result == U32_MAX) /* card removed */ return -ENODEV; @@ -162,7 +162,7 @@ int xhci_start(struct xhci_hcd *xhci) * Transactions will be terminated immediately, and operational registers * will be set to their defaults. */ -int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) +int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; @@ -195,7 +195,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) if (xhci->quirks & XHCI_INTEL_HOST) udelay(1000); - ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us); + ret = xhci_handshake(&xhci->op_regs->command, + CMD_RESET, 0, 10 * 1000 * 1000); if (ret) return ret; @@ -208,7 +209,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us); + ret = xhci_handshake(&xhci->op_regs->status, + STS_CNR, 0, 10 * 1000 * 1000); xhci->usb2_rhub.bus_state.port_c_suspend = 0; xhci->usb2_rhub.bus_state.suspended_ports = 0; @@ -729,7 +731,7 @@ static void xhci_stop(struct usb_hcd *hcd) xhci->xhc_state |= XHCI_STATE_HALTED; xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; xhci_halt(xhci); - xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -782,7 +784,7 @@ void xhci_shutdown(struct usb_hcd *hcd) xhci_halt(xhci); /* Workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) - xhci_reset(xhci, XHCI_RESET_SHORT_USEC); + xhci_reset(xhci); spin_unlock_irq(&xhci->lock); xhci_cleanup_msix(xhci); @@ -1167,7 +1169,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_zero_64b_regs(xhci); - retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC); + retval = xhci_reset(xhci); spin_unlock_irq(&xhci->lock); if (retval) return retval; @@ -5278,7 +5280,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ - retval = xhci_reset(xhci, XHCI_RESET_LONG_USEC); + retval = xhci_reset(xhci); if (retval) return retval; xhci_dbg(xhci, "Reset complete\n"); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 111dc5ff3f0df3adddf2fc54206a3b06e2ffc546..2bba700a780594046be92e0488c0a28e0a52ac26 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -230,9 +230,6 @@ struct xhci_op_regs { #define CMD_ETE (1 << 14) /* bits 15:31 are reserved (and should be preserved on writes). */ -#define XHCI_RESET_LONG_USEC (10 * 1000 * 1000) -#define XHCI_RESET_SHORT_USEC (250 * 1000) - /* IMAN - Interrupt Management Register */ #define IMAN_IE (1 << 1) #define IMAN_IP (1 << 0) @@ -2100,11 +2097,11 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci, /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); -int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, u64 timeout_us); +int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec); void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); int xhci_start(struct xhci_hcd *xhci); -int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); +int xhci_reset(struct xhci_hcd *xhci); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); @@ -2532,8 +2529,6 @@ static inline const char *xhci_decode_ctrl_ctx(char *str, unsigned int bit; int ret = 0; - str[0] = '\0'; - if (drop) { ret = sprintf(str, "Drop:"); for_each_set_bit(bit, &drop, 32) @@ -2691,11 +2686,8 @@ static inline const char *xhci_decode_usbsts(char *str, u32 usbsts) { int ret = 0; - ret = sprintf(str, " 0x%08x", usbsts); - if (usbsts == ~(u32)0) - return str; - + return " 0xffffffff"; if (usbsts & STS_HALT) ret += sprintf(str + ret, " HCHalted"); if (usbsts & STS_FATAL) diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 169251ec8353e592b628840b3dd8d155aad2f65b..4007fa25a8ffae389570b32c470189ef716c8f4c 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -66,7 +66,6 @@ config USB_SERIAL_SIMPLE - Libtransistor USB console - a number of Motorola phones - Motorola Tetra devices - - Nokia mobile phones - Novatel Wireless GPS receivers - Siemens USB/MPI adapter. - ViVOtech ViVOpay USB device. diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index d736822e95e184485485fd057966a7c114027d64..1bbe18f3f9f11eb21c76da0740d4f17ef8f2b7ec 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -116,7 +116,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530GC_PRODUCT_ID) }, { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index c5406452b774ef9dc6cdc986f0aa4ce6ead1b866..6097ee8fccb25cdbf6feaa28d49f784c913ca492 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -35,9 +35,6 @@ #define ATEN_PRODUCT_UC232B 0x2022 #define ATEN_PRODUCT_ID2 0x2118 -#define IBM_VENDOR_ID 0x04b3 -#define IBM_PRODUCT_ID 0x4016 - #define IODATA_VENDOR_ID 0x04bb #define IODATA_PRODUCT_ID 0x0a03 #define IODATA_PRODUCT_ID_RSAQ5 0x0a0e diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 4c6747889a194664a04f90824e417bedec625b3f..bd23a7cb1be2bceaa8422e88bc3cdb5255dd566c 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -91,11 +91,6 @@ DEVICE(moto_modem, MOTO_IDS); { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); -/* Nokia mobile phone driver */ -#define NOKIA_IDS() \ - { USB_DEVICE(0x0421, 0x069a) } /* Nokia 130 (RM-1035) */ -DEVICE(nokia, NOKIA_IDS); - /* Novatel Wireless GPS driver */ #define NOVATEL_IDS() \ { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ @@ -128,7 +123,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &vivopay_device, &moto_modem_device, &motorola_tetra_device, - &nokia_device, &novatel_gps_device, &hp4x_device, &suunto_device, @@ -146,7 +140,6 @@ static const struct usb_device_id id_table[] = { VIVOPAY_IDS(), MOTO_IDS(), MOTOROLA_TETRA_IDS(), - NOKIA_IDS(), NOVATEL_IDS(), HP4X_IDS(), SUUNTO_IDS(), diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index c9ce1c25c80cc59b61701c868d0d8ff8206e993c..98c1aa594e6c4d58e568366b106746c4dbf81599 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -237,33 +237,36 @@ static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { #define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0)) -/* SD_STATUS bits */ -#define SD_Insert BIT(0) -#define SD_Ready BIT(1) -#define SD_MediaChange BIT(2) -#define SD_IsMMC BIT(3) -#define SD_HiCapacity BIT(4) -#define SD_HiSpeed BIT(5) -#define SD_WtP BIT(6) - /* Bit 7 reserved */ - -/* MS_STATUS bits */ -#define MS_Insert BIT(0) -#define MS_Ready BIT(1) -#define MS_MediaChange BIT(2) -#define MS_IsMSPro BIT(3) -#define MS_IsMSPHG BIT(4) - /* Bit 5 reserved */ -#define MS_WtP BIT(6) - /* Bit 7 reserved */ - -/* SM_STATUS bits */ -#define SM_Insert BIT(0) -#define SM_Ready BIT(1) -#define SM_MediaChange BIT(2) - /* Bits 3-5 reserved */ -#define SM_WtP BIT(6) -#define SM_IsMS BIT(7) +struct SD_STATUS { + u8 Insert:1; + u8 Ready:1; + u8 MediaChange:1; + u8 IsMMC:1; + u8 HiCapacity:1; + u8 HiSpeed:1; + u8 WtP:1; + u8 Reserved:1; +}; + +struct MS_STATUS { + u8 Insert:1; + u8 Ready:1; + u8 MediaChange:1; + u8 IsMSPro:1; + u8 IsMSPHG:1; + u8 Reserved1:1; + u8 WtP:1; + u8 Reserved2:1; +}; + +struct SM_STATUS { + u8 Insert:1; + u8 Ready:1; + u8 MediaChange:1; + u8 Reserved:3; + u8 WtP:1; + u8 IsMS:1; +}; struct ms_bootblock_cis { u8 bCistplDEVICE[6]; /* 0 */ @@ -434,9 +437,9 @@ struct ene_ub6250_info { u8 *bbuf; /* for 6250 code */ - u8 SD_Status; - u8 MS_Status; - u8 SM_Status; + struct SD_STATUS SD_Status; + struct MS_STATUS MS_Status; + struct SM_STATUS SM_Status; /* ----- SD Control Data ---------------- */ /*SD_REGISTER SD_Regs; */ @@ -599,7 +602,7 @@ static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) { struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) + if (info->SD_Status.Insert && info->SD_Status.Ready) return USB_STOR_TRANSPORT_GOOD; else { ene_sd_init(us); @@ -619,7 +622,7 @@ static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - if (info->SD_Status & SD_WtP) + if (info->SD_Status.WtP) usb_stor_set_xfer_buf(mediaWP, 12, srb); else usb_stor_set_xfer_buf(mediaNoWP, 12, srb); @@ -638,9 +641,9 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; usb_stor_dbg(us, "sd_scsi_read_capacity\n"); - if (info->SD_Status & SD_HiCapacity) { + if (info->SD_Status.HiCapacity) { bl_len = 0x200; - if (info->SD_Status & SD_IsMMC) + if (info->SD_Status.IsMMC) bl_num = info->HC_C_SIZE-1; else bl_num = (info->HC_C_SIZE + 1) * 1024 - 1; @@ -690,7 +693,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb) return USB_STOR_TRANSPORT_ERROR; } - if (info->SD_Status & SD_HiCapacity) + if (info->SD_Status.HiCapacity) bnByte = bn; /* set up the command wrapper */ @@ -730,7 +733,7 @@ static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) return USB_STOR_TRANSPORT_ERROR; } - if (info->SD_Status & SD_HiCapacity) + if (info->SD_Status.HiCapacity) bnByte = bn; /* set up the command wrapper */ @@ -1452,7 +1455,7 @@ static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */ - if ((info->MS_Status & MS_Insert) && (info->MS_Status & MS_Ready)) { + if (info->MS_Status.Insert && info->MS_Status.Ready) { return USB_STOR_TRANSPORT_GOOD; } else { ene_ms_init(us); @@ -1472,7 +1475,7 @@ static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - if (info->MS_Status & MS_WtP) + if (info->MS_Status.WtP) usb_stor_set_xfer_buf(mediaWP, 12, srb); else usb_stor_set_xfer_buf(mediaNoWP, 12, srb); @@ -1491,7 +1494,7 @@ static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) usb_stor_dbg(us, "ms_scsi_read_capacity\n"); bl_len = 0x200; - if (info->MS_Status & MS_IsMSPro) + if (info->MS_Status.IsMSPro) bl_num = info->MSP_TotalBlock - 1; else bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1; @@ -1646,7 +1649,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb) if (bn > info->bl_num) return USB_STOR_TRANSPORT_ERROR; - if (info->MS_Status & MS_IsMSPro) { + if (info->MS_Status.IsMSPro) { result = ene_load_bincode(us, MSP_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n"); @@ -1747,7 +1750,7 @@ static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb) if (bn > info->bl_num) return USB_STOR_TRANSPORT_ERROR; - if (info->MS_Status & MS_IsMSPro) { + if (info->MS_Status.IsMSPro) { result = ene_load_bincode(us, MSP_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { pr_info("Load MSP RW pattern Fail !!\n"); @@ -1855,12 +1858,12 @@ static int ene_get_card_status(struct us_data *us, u8 *buf) tmpreg = (u16) reg4b; reg4b = *(u32 *)(&buf[0x14]); - if ((info->SD_Status & SD_HiCapacity) && !(info->SD_Status & SD_IsMMC)) + if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC) info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff; info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22); info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07; - if ((info->SD_Status & SD_HiCapacity) && (info->SD_Status & SD_IsMMC)) + if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC) info->HC_C_SIZE = *(u32 *)(&buf[0x100]); if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) { @@ -2072,7 +2075,6 @@ static int ene_ms_init(struct us_data *us) u16 MSP_BlockSize, MSP_UserAreaBlocks; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; u8 *bbuf = info->bbuf; - unsigned int s; printk(KERN_INFO "transport --- ENE_MSInit\n"); @@ -2097,16 +2099,15 @@ static int ene_ms_init(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } /* the same part to test ENE */ - info->MS_Status = bbuf[0]; - - s = info->MS_Status; - if ((s & MS_Insert) && (s & MS_Ready)) { - printk(KERN_INFO "Insert = %x\n", !!(s & MS_Insert)); - printk(KERN_INFO "Ready = %x\n", !!(s & MS_Ready)); - printk(KERN_INFO "IsMSPro = %x\n", !!(s & MS_IsMSPro)); - printk(KERN_INFO "IsMSPHG = %x\n", !!(s & MS_IsMSPHG)); - printk(KERN_INFO "WtP= %x\n", !!(s & MS_WtP)); - if (s & MS_IsMSPro) { + info->MS_Status = *(struct MS_STATUS *) bbuf; + + if (info->MS_Status.Insert && info->MS_Status.Ready) { + printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert); + printk(KERN_INFO "Ready = %x\n", info->MS_Status.Ready); + printk(KERN_INFO "IsMSPro = %x\n", info->MS_Status.IsMSPro); + printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG); + printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP); + if (info->MS_Status.IsMSPro) { MSP_BlockSize = (bbuf[6] << 8) | bbuf[7]; MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11]; info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; @@ -2167,17 +2168,17 @@ static int ene_sd_init(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } - info->SD_Status = bbuf[0]; - if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) { - unsigned int s = info->SD_Status; + info->SD_Status = *(struct SD_STATUS *) bbuf; + if (info->SD_Status.Insert && info->SD_Status.Ready) { + struct SD_STATUS *s = &info->SD_Status; ene_get_card_status(us, bbuf); - usb_stor_dbg(us, "Insert = %x\n", !!(s & SD_Insert)); - usb_stor_dbg(us, "Ready = %x\n", !!(s & SD_Ready)); - usb_stor_dbg(us, "IsMMC = %x\n", !!(s & SD_IsMMC)); - usb_stor_dbg(us, "HiCapacity = %x\n", !!(s & SD_HiCapacity)); - usb_stor_dbg(us, "HiSpeed = %x\n", !!(s & SD_HiSpeed)); - usb_stor_dbg(us, "WtP = %x\n", !!(s & SD_WtP)); + usb_stor_dbg(us, "Insert = %x\n", s->Insert); + usb_stor_dbg(us, "Ready = %x\n", s->Ready); + usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC); + usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity); + usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed); + usb_stor_dbg(us, "WtP = %x\n", s->WtP); } else { usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]); return USB_STOR_TRANSPORT_ERROR; @@ -2199,14 +2200,14 @@ static int ene_init(struct us_data *us) misc_reg03 = bbuf[0]; if (misc_reg03 & 0x01) { - if (!(info->SD_Status & SD_Ready)) { + if (!info->SD_Status.Ready) { result = ene_sd_init(us); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } } if (misc_reg03 & 0x02) { - if (!(info->MS_Status & MS_Ready)) { + if (!info->MS_Status.Ready) { result = ene_ms_init(us); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -2305,14 +2306,14 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) /*US_DEBUG(usb_stor_show_command(us, srb)); */ scsi_set_resid(srb, 0); - if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready))) + if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) result = ene_init(us); if (result == USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; - if (info->SD_Status & SD_Ready) + if (info->SD_Status.Ready) result = sd_scsi_irp(us, srb); - if (info->MS_Status & MS_Ready) + if (info->MS_Status.Ready) result = ms_scsi_irp(us, srb); } return result; @@ -2376,6 +2377,7 @@ static int ene_ub6250_probe(struct usb_interface *intf, static int ene_ub6250_resume(struct usb_interface *iface) { + u8 tmp = 0; struct us_data *us = usb_get_intfdata(iface); struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); @@ -2387,16 +2389,17 @@ static int ene_ub6250_resume(struct usb_interface *iface) mutex_unlock(&us->dev_mutex); info->Power_IsResum = true; - /* info->SD_Status &= ~SD_Ready; */ - info->SD_Status = 0; - info->MS_Status = 0; - info->SM_Status = 0; + /*info->SD_Status.Ready = 0; */ + info->SD_Status = *(struct SD_STATUS *)&tmp; + info->MS_Status = *(struct MS_STATUS *)&tmp; + info->SM_Status = *(struct SM_STATUS *)&tmp; return 0; } static int ene_ub6250_reset_resume(struct usb_interface *iface) { + u8 tmp = 0; struct us_data *us = usb_get_intfdata(iface); struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); @@ -2408,10 +2411,10 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface) * the device */ info->Power_IsResum = true; - /* info->SD_Status &= ~SD_Ready; */ - info->SD_Status = 0; - info->MS_Status = 0; - info->SM_Status = 0; + /*info->SD_Status.Ready = 0; */ + info->SD_Status = *(struct SD_STATUS *)&tmp; + info->MS_Status = *(struct MS_STATUS *)&tmp; + info->SM_Status = *(struct SM_STATUS *)&tmp; return 0; } diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 0c423916d7bfa4e325243ea4b0e0b9ce8854a535..3789698d9d3c6431096f0320b280014b6ca4477b 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -365,7 +365,7 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len) buf = kmalloc(len, GFP_NOIO); if (buf == NULL) - return -ENOMEM; + return USB_STOR_TRANSPORT_ERROR; usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len); diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 577ff786f11b1295b2715685f82b5e4395da0dc4..65d6f8fd81e706a25e12937d5d81bfb78bdd2535 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1482,25 +1482,11 @@ static u64 mlx5_vdpa_get_features(struct vdpa_device *vdev) return ndev->mvdev.mlx_features; } -static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features) +static int verify_min_features(struct mlx5_vdpa_dev *mvdev, u64 features) { - /* Minimum features to expect */ if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) return -EOPNOTSUPP; - /* Double check features combination sent down by the driver. - * Fail invalid features due to absence of the depended feature. - * - * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit - * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ". - * By failing the invalid features sent down by untrusted drivers, - * we're assured the assumption made upon is_index_valid() and - * is_ctrl_vq_idx() will not be compromised. - */ - if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) == - BIT_ULL(VIRTIO_NET_F_MQ)) - return -EINVAL; - return 0; } @@ -1558,7 +1544,7 @@ static int mlx5_vdpa_set_features(struct vdpa_device *vdev, u64 features) print_features(mvdev, features, true); - err = verify_driver_features(mvdev, features); + err = verify_min_features(mvdev, features); if (err) return err; diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c index 3626c21501017e95163572fe8ee5cdb8a40bc75b..62c97aa21a79b10e12c340d2fea02890cbd74306 100644 --- a/drivers/vfio/platform/vfio_amba.c +++ b/drivers/vfio/platform/vfio_amba.c @@ -73,11 +73,13 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id) static void vfio_amba_remove(struct amba_device *adev) { - struct vfio_platform_device *vdev = - vfio_platform_remove_common(&adev->dev); + struct vfio_platform_device *vdev; - kfree(vdev->name); - kfree(vdev); + vdev = vfio_platform_remove_common(&adev->dev); + if (vdev) { + kfree(vdev->name); + kfree(vdev); + } } static const struct amba_id pl330_ids[] = { diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 5d2d6ce7ff41340f2d4ec7d07601d2b6f3fbea84..c282fc0d04bd1b96e76c2cb95929bb3ec7675bef 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -697,8 +697,7 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file) /* Iterating over all connections for all CIDs to find orphans is * inefficient. Room for improvement here. */ - vsock_for_each_connected_socket(&vhost_transport.transport, - vhost_vsock_reset_orphans); + vsock_for_each_connected_socket(vhost_vsock_reset_orphans); /* Don't check the owner, because we are in the release path, so we * need to stop the vsock device in any case. diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c index a7a1739cff1bd4fd78585b7548961983be20f093..f253daa05d9d3872777077692c51e0aa2d9fbcdb 100644 --- a/drivers/video/fbdev/atafb.c +++ b/drivers/video/fbdev/atafb.c @@ -1691,9 +1691,9 @@ static int falcon_setcolreg(unsigned int regno, unsigned int red, ((blue & 0xfc00) >> 8)); if (regno < 16) { shifter_tt.color_reg[regno] = - ((((red & 0xe000) >> 13) | ((red & 0x1000) >> 12)) << 8) | - ((((green & 0xe000) >> 13) | ((green & 0x1000) >> 12)) << 4) | - ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); + (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | + (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | + ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11)); @@ -1979,9 +1979,9 @@ static int stste_setcolreg(unsigned int regno, unsigned int red, green >>= 12; if (ATARIHW_PRESENT(EXTD_SHIFTER)) shifter_tt.color_reg[regno] = - ((((red & 0xe) >> 1) | ((red & 1) << 3)) << 8) | - ((((green & 0xe) >> 1) | ((green & 1) << 3)) << 4) | - ((blue & 0xe) >> 1) | ((blue & 1) << 3); + (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | + (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | + ((blue & 0xe) >> 1) | ((blue & 1) << 3); else shifter_tt.color_reg[regno] = ((red & 0xe) << 7) | diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 1fc8de4ecbebf9e5e2974c3c97cba94d536d73c4..355b6120dc4f0dcd77433ac4c8753ffa5561e8af 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -1062,16 +1062,15 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&info->modelist); - if (!pdev->dev.of_node) { + if (pdev->dev.of_node) { + ret = atmel_lcdfb_of_init(sinfo); + if (ret) + goto free_info; + } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; } - ret = atmel_lcdfb_of_init(sinfo); - if (ret) - goto free_info; - - ret = -ENODEV; if (!sinfo->config) goto free_info; diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index b4980bc2985e3c9cf971b2c1bb0516f84c77e5f2..15a9ee7cd734d3fa1147a9cacbe65cb06bf5b3e4 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -469,7 +469,7 @@ static int cirrusfb_check_mclk(struct fb_info *info, long freq) return 0; } -static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, +static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var, struct fb_info *info) { long freq; @@ -478,7 +478,9 @@ static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, unsigned maxclockidx = var->bits_per_pixel >> 3; /* convert from ps to kHz */ - freq = PICOS2KHZ(var->pixclock ? : 1); + freq = PICOS2KHZ(var->pixclock); + + dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; cinfo->multiplexing = 0; @@ -486,13 +488,11 @@ static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var, /* If the frequency is greater than we can support, we might be able * to use multiplexing for the video mode */ if (freq > maxclock) { - var->pixclock = KHZ2PICOS(maxclock); - - while ((freq = PICOS2KHZ(var->pixclock)) > maxclock) - var->pixclock++; + dev_err(info->device, + "Frequency greater than maxclock (%ld kHz)\n", + maxclock); + return -EINVAL; } - dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); - /* * Additional constraint: 8bpp uses DAC clock doubling to allow maximum * pixel clock diff --git a/drivers/video/fbdev/controlfb.c b/drivers/video/fbdev/controlfb.c index bd59e7b11ed5305d922b42d33d0dd01c98edb09f..2df56bd303d25d125c6a7813ed0bf2787abc1ec9 100644 --- a/drivers/video/fbdev/controlfb.c +++ b/drivers/video/fbdev/controlfb.c @@ -64,12 +64,10 @@ #undef in_le32 #undef out_le32 #define in_8(addr) 0 -#define out_8(addr, val) (void)(val) +#define out_8(addr, val) #define in_le32(addr) 0 -#define out_le32(addr, val) (void)(val) -#ifndef pgprot_cached_wthru +#define out_le32(addr, val) #define pgprot_cached_wthru(prot) (prot) -#endif #else static void invalid_vram_cache(void __force *addr) { diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c index 64843464c66135b4c5c083418c8c89ae237f052a..55d2bd0ce5c0229cddf48cb0960a59e31d604060 100644 --- a/drivers/video/fbdev/core/fbcvt.c +++ b/drivers/video/fbdev/core/fbcvt.c @@ -214,11 +214,9 @@ static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt) static void fb_cvt_print_name(struct fb_cvt_data *cvt) { u32 pixcount, pixcount_mod; - int size = 256; - int off = 0; - u8 *buf; + int cnt = 255, offset = 0, read = 0; + u8 *buf = kzalloc(256, GFP_KERNEL); - buf = kzalloc(size, GFP_KERNEL); if (!buf) return; @@ -226,30 +224,43 @@ static void fb_cvt_print_name(struct fb_cvt_data *cvt) pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000; pixcount_mod /= 1000; - off += scnprintf(buf + off, size - off, "fbcvt: %dx%d@%d: CVT Name - ", - cvt->xres, cvt->yres, cvt->refresh); + read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ", + cvt->xres, cvt->yres, cvt->refresh); + offset += read; + cnt -= read; - if (cvt->status) { - off += scnprintf(buf + off, size - off, - "Not a CVT standard - %d.%03d Mega Pixel Image\n", - pixcount, pixcount_mod); - } else { - if (pixcount) - off += scnprintf(buf + off, size - off, "%d", pixcount); + if (cvt->status) + snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega " + "Pixel Image\n", pixcount, pixcount_mod); + else { + if (pixcount) { + read = snprintf(buf+offset, cnt, "%d", pixcount); + cnt -= read; + offset += read; + } - off += scnprintf(buf + off, size - off, ".%03dM", pixcount_mod); + read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod); + cnt -= read; + offset += read; if (cvt->aspect_ratio == 0) - off += scnprintf(buf + off, size - off, "3"); + read = snprintf(buf+offset, cnt, "3"); else if (cvt->aspect_ratio == 3) - off += scnprintf(buf + off, size - off, "4"); + read = snprintf(buf+offset, cnt, "4"); else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4) - off += scnprintf(buf + off, size - off, "9"); + read = snprintf(buf+offset, cnt, "9"); else if (cvt->aspect_ratio == 2) - off += scnprintf(buf + off, size - off, "A"); - - if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) - off += scnprintf(buf + off, size - off, "-R"); + read = snprintf(buf+offset, cnt, "A"); + else + read = 0; + cnt -= read; + offset += read; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + read = snprintf(buf+offset, cnt, "-R"); + cnt -= read; + offset += read; + } } printk(KERN_INFO "%s\n", buf); diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index daaa99818d3b7532e8d31c8cce299907dcfd9dba..570439b326552a674e89a59cce9abce202f7856a 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -1377,7 +1377,7 @@ static struct video_board vbG200 = { .lowlevel = &matrox_G100 }; static struct video_board vbG200eW = { - .maxvram = 0x100000, + .maxvram = 0x800000, .maxdisplayable = 0x800000, .accelID = FB_ACCEL_MATROX_MGAG200, .lowlevel = &matrox_G100 diff --git a/drivers/video/fbdev/nvidia/nv_i2c.c b/drivers/video/fbdev/nvidia/nv_i2c.c index 0b48965a6420c2a2a27928a55a22aee3cc1d57e2..d7994a1732459d831775374d61f135ecaf5e06c5 100644 --- a/drivers/video/fbdev/nvidia/nv_i2c.c +++ b/drivers/video/fbdev/nvidia/nv_i2c.c @@ -86,7 +86,7 @@ static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name, { int rc; - strscpy(chan->adapter.name, name, sizeof(chan->adapter.name)); + strcpy(chan->adapter.name, name); chan->adapter.owner = THIS_MODULE; chan->adapter.class = i2c_class; chan->adapter.algo_data = &chan->algo; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c index 777f6d66c28c3d5ba69113740fad7723e6a53a07..b4a1aefff7661da1650c9ba230c4dcb5dd96dc89 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/connector-dvi.c @@ -251,7 +251,6 @@ static int dvic_probe_of(struct platform_device *pdev) adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { adapter = of_get_i2c_adapter_by_node(adapter_node); - of_node_put(adapter_node); if (adapter == NULL) { dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); omap_dss_put_device(ddata->in); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index a2c7c5cb1523460508b439dbfde2e0efa170d158..4b0793abdd84b4509afea88329230c56261e1d80 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -409,7 +409,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev, if (r) return r; - return sysfs_emit(buf, "%d\n", errors); + return snprintf(buf, PAGE_SIZE, "%d\n", errors); } static ssize_t dsicm_hw_revision_show(struct device *dev, @@ -439,7 +439,7 @@ static ssize_t dsicm_hw_revision_show(struct device *dev, if (r) return r; - return sysfs_emit(buf, "%02x.%02x.%02x\n", id1, id2, id3); + return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3); } static ssize_t dsicm_store_ulps(struct device *dev, @@ -487,7 +487,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, t = ddata->ulps_enabled; mutex_unlock(&ddata->lock); - return sysfs_emit(buf, "%u\n", t); + return snprintf(buf, PAGE_SIZE, "%u\n", t); } static ssize_t dsicm_store_ulps_timeout(struct device *dev, @@ -532,7 +532,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev, t = ddata->ulps_timeout; mutex_unlock(&ddata->lock); - return sysfs_emit(buf, "%u\n", t); + return snprintf(buf, PAGE_SIZE, "%u\n", t); } static DEVICE_ATTR(num_dsi_errors, S_IRUGO, dsicm_num_errors_show, NULL); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 0cbc5b9183f895c4a1d994cc2ca35731b8d364fe..1293515e4b1692e1917411c5eaf6159581454825 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -476,7 +476,7 @@ static ssize_t show_cabc_available_modes(struct device *dev, int i; if (!ddata->has_cabc) - return sysfs_emit(buf, "%s\n", cabc_modes[0]); + return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); for (i = 0, len = 0; len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c index 9f6ef9e04d9ce41a57b2e1791183390a008599a0..bb85b21f072487239f87005191f8c3fa117a38ac 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c @@ -169,7 +169,7 @@ static ssize_t tpo_td043_vmirror_show(struct device *dev, { struct panel_drv_data *ddata = dev_get_drvdata(dev); - return sysfs_emit(buf, "%d\n", ddata->vmirror); + return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror); } static ssize_t tpo_td043_vmirror_store(struct device *dev, @@ -199,7 +199,7 @@ static ssize_t tpo_td043_mode_show(struct device *dev, { struct panel_drv_data *ddata = dev_get_drvdata(dev); - return sysfs_emit(buf, "%d\n", ddata->mode); + return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode); } static ssize_t tpo_td043_mode_store(struct device *dev, diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index 092a1caa1208e191b016a0ec2097208e5e2d960f..0dbc6bf8268acf5fa0528f28f047372cbd4fd5e8 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -1047,7 +1047,7 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, if (count + p > total_size) count = total_size - p; - buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1059,14 +1059,25 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; dst = buffer; - for (i = (c + 3) >> 2; i--;) { - u32 val; - - val = fb_readl(src); - *dst = big_swap(val); - src++; + for (i = c >> 2; i--;) { + *dst = fb_readl(src++); + *dst = big_swap(*dst); dst++; } + if (c & 3) { + u8 *dst8 = (u8 *)dst; + u8 __iomem *src8 = (u8 __iomem *)src; + + for (i = c & 3; i--;) { + if (i & 1) { + *dst8++ = fb_readb(++src8); + } else { + *dst8++ = fb_readb(--src8); + src8 += 2; + } + } + src = (u32 __iomem *)src8; + } if (copy_to_user(buf, buffer, c)) { err = -EFAULT; @@ -1119,7 +1130,7 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, count = total_size - p; } - buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1137,11 +1148,24 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, break; } - for (i = (c + 3) >> 2; i--;) { - fb_writel(big_swap(*src), dst); - dst++; + for (i = c >> 2; i--;) { + fb_writel(big_swap(*src), dst++); src++; } + if (c & 3) { + u8 *src8 = (u8 *)src; + u8 __iomem *dst8 = (u8 __iomem *)dst; + + for (i = c & 3; i--;) { + if (i & 1) { + fb_writeb(*src8++, ++dst8); + } else { + fb_writeb(*src8++, --dst8); + dst8 += 2; + } + } + dst = (u32 __iomem *)dst8; + } *ppos += c; buf += c; diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 28768c272b73d3e57ff4212dfe44f9c81d4af56a..bfac3ee4a64228160adc5d11e85e66e7b7bcf9a8 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -1656,7 +1656,6 @@ static int ufx_usb_probe(struct usb_interface *interface, info->par = dev; info->pseudo_palette = dev->pseudo_palette; info->fbops = &ufx_ops; - INIT_LIST_HEAD(&info->modelist); retval = fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) { @@ -1667,6 +1666,8 @@ static int ufx_usb_probe(struct usb_interface *interface, INIT_DELAYED_WORK(&dev->free_framebuffer_work, ufx_free_framebuffer_work); + INIT_LIST_HEAD(&info->modelist); + retval = ufx_reg_read(dev, 0x3000, &id_rev); check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval); dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 90f48b71fd8f790c23a0f7d109a286a8e515b542..b9cdd02c100095d99ef929571115f82c28290f29 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1426,7 +1426,7 @@ static ssize_t metrics_bytes_rendered_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->bytes_rendered)); } @@ -1434,7 +1434,7 @@ static ssize_t metrics_bytes_identical_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->bytes_identical)); } @@ -1442,7 +1442,7 @@ static ssize_t metrics_bytes_sent_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->bytes_sent)); } @@ -1450,7 +1450,7 @@ static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev, struct device_attribute *a, char *buf) { struct fb_info *fb_info = dev_get_drvdata(fbdev); struct dlfb_data *dlfb = fb_info->par; - return sysfs_emit(buf, "%u\n", + return snprintf(buf, PAGE_SIZE, "%u\n", atomic_read(&dlfb->cpu_kcycles_used)); } diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c index 4e641a780726e784892110c72b71a379fd94637a..d96ab28f8ce4ae54b384c3a4d8f2b9bfa085187e 100644 --- a/drivers/video/fbdev/w100fb.c +++ b/drivers/video/fbdev/w100fb.c @@ -770,18 +770,12 @@ out: fb_dealloc_cmap(&info->cmap); kfree(info->pseudo_palette); } - if (remapped_fbuf != NULL) { + if (remapped_fbuf != NULL) iounmap(remapped_fbuf); - remapped_fbuf = NULL; - } - if (remapped_regs != NULL) { + if (remapped_regs != NULL) iounmap(remapped_regs); - remapped_regs = NULL; - } - if (remapped_base != NULL) { + if (remapped_base != NULL) iounmap(remapped_base); - remapped_base = NULL; - } if (info) framebuffer_release(info); return err; @@ -801,11 +795,8 @@ static int w100fb_remove(struct platform_device *pdev) fb_dealloc_cmap(&info->cmap); iounmap(remapped_base); - remapped_base = NULL; iounmap(remapped_regs); - remapped_regs = NULL; iounmap(remapped_fbuf); - remapped_fbuf = NULL; framebuffer_release(info); diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 1bce254a462a9d5d313d1dfdbd53b90b25905ff2..b35bb2d57f62c15b7a45a7a78e2322e0c2748c40 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -24,46 +24,17 @@ MODULE_PARM_DESC(force_legacy, "Force legacy mode for transitional virtio 1 devices"); #endif -/* disable irq handlers */ -void vp_disable_cbs(struct virtio_device *vdev) +/* wait for pending irq handlers */ +void vp_synchronize_vectors(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); int i; - if (vp_dev->intx_enabled) { - /* - * The below synchronize() guarantees that any - * interrupt for this line arriving after - * synchronize_irq() has completed is guaranteed to see - * intx_soft_enabled == false. - */ - WRITE_ONCE(vp_dev->intx_soft_enabled, false); + if (vp_dev->intx_enabled) synchronize_irq(vp_dev->pci_dev->irq); - } - - for (i = 0; i < vp_dev->msix_vectors; ++i) - disable_irq(pci_irq_vector(vp_dev->pci_dev, i)); -} - -/* enable irq handlers */ -void vp_enable_cbs(struct virtio_device *vdev) -{ - struct virtio_pci_device *vp_dev = to_vp_device(vdev); - int i; - - if (vp_dev->intx_enabled) { - disable_irq(vp_dev->pci_dev->irq); - /* - * The above disable_irq() provides TSO ordering and - * as such promotes the below store to store-release. - */ - WRITE_ONCE(vp_dev->intx_soft_enabled, true); - enable_irq(vp_dev->pci_dev->irq); - return; - } for (i = 0; i < vp_dev->msix_vectors; ++i) - enable_irq(pci_irq_vector(vp_dev->pci_dev, i)); + synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i)); } /* the notify function used when creating a virt queue */ @@ -113,9 +84,6 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) struct virtio_pci_device *vp_dev = opaque; u8 isr; - if (!READ_ONCE(vp_dev->intx_soft_enabled)) - return IRQ_NONE; - /* reading the ISR has the effect of also clearing it so it's very * important to save off the value. */ isr = ioread8(vp_dev->isr); @@ -173,8 +141,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-config", name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), - vp_config_changed, IRQF_NO_AUTOEN, - vp_dev->msix_names[v], + vp_config_changed, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; @@ -193,8 +160,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-virtqueues", name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), - vp_vring_interrupt, IRQF_NO_AUTOEN, - vp_dev->msix_names[v], + vp_vring_interrupt, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; @@ -371,7 +337,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, "%s-%s", dev_name(&vp_dev->vdev.dev), names[i]); err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), - vring_interrupt, IRQF_NO_AUTOEN, + vring_interrupt, 0, vp_dev->msix_names[msix_vec], vqs[i]); if (err) diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index 94cc3cb0f18f162db309a01c671d42716d1d91a4..b2f0eb4067cbfded05c5d9971767164af278c766 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -82,7 +82,6 @@ struct virtio_pci_device { /* MSI-X support */ int msix_enabled; int intx_enabled; - bool intx_soft_enabled; cpumask_var_t *msix_affinity_masks; /* Name strings for interrupts. This size should be enough, * and I'm too lazy to allocate each name separately. */ @@ -121,10 +120,8 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev) return container_of(vdev, struct virtio_pci_device, vdev); } -/* disable irq handlers */ -void vp_disable_cbs(struct virtio_device *vdev); -/* enable irq handlers */ -void vp_enable_cbs(struct virtio_device *vdev); +/* wait for pending irq handlers */ +void vp_synchronize_vectors(struct virtio_device *vdev); /* the notify function used when creating a virt queue */ bool vp_notify(struct virtqueue *vq); /* the config->del_vqs() implementation */ diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index d9c95d89cdd08ee8e43df74e51634ba93293637a..d62e9835aeeca2125e5f94db758427420808a039 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -97,8 +97,8 @@ static void vp_reset(struct virtio_device *vdev) /* Flush out the status write, and flush in device writes, * including MSi-X interrupts, if any. */ ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS); - /* Disable VQ/configuration callbacks. */ - vp_disable_cbs(vdev); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) @@ -194,7 +194,6 @@ static void del_vq(struct virtio_pci_vq_info *info) } static const struct virtio_config_ops virtio_pci_config_ops = { - .enable_cbs = vp_enable_cbs, .get = vp_get, .set = vp_set, .get_status = vp_get_status, diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index d30e00852318e532099862e190f50819517731b4..2158e16251334f1d8bd6048efc0657d8dbe40896 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -63,12 +63,13 @@ static void vp_iowrite64_twopart(u64 val, vp_iowrite32(val >> 32, hi); } -static void __iomem *map_capability(struct pci_dev *dev, int off, +static void __iomem *map_capability(struct virtio_pci_device *vp_dev, int off, size_t minlen, u32 align, u32 start, u32 size, size_t *len) { + struct pci_dev *dev = vp_dev->pci_dev; u8 bar; u32 offset, length; void __iomem *p; @@ -81,6 +82,13 @@ static void __iomem *map_capability(struct pci_dev *dev, int off, pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length), &length); + /* Check if the BAR may have changed since we requested the region. */ + if (bar >= PCI_STD_NUM_BARS || !(vp_dev->modern_bars & (1 << bar))) { + dev_err(&dev->dev, + "virtio_pci: bar unexpectedly changed to %u\n", bar); + return NULL; + } + if (length <= start) { dev_err(&dev->dev, "virtio_pci: bad capability len %u (>%u expected)\n", @@ -291,8 +299,8 @@ static void vp_reset(struct virtio_device *vdev) */ while (vp_ioread8(&vp_dev->common->device_status)) msleep(1); - /* Disable VQ/configuration callbacks. */ - vp_disable_cbs(vdev); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) @@ -370,7 +378,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, vq->priv = (void __force *)vp_dev->notify_base + off * vp_dev->notify_offset_multiplier; } else { - vq->priv = (void __force *)map_capability(vp_dev->pci_dev, + vq->priv = (void __force *)map_capability(vp_dev, vp_dev->notify_map_cap, 2, 2, off * vp_dev->notify_offset_multiplier, 2, NULL); @@ -451,7 +459,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); pos > 0; pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) { - u8 type, cap_len, id; + u8 type, cap_len, id, res_bar; u32 tmp32; u64 res_offset, res_length; @@ -473,9 +481,14 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, if (id != required_id) continue; - /* Type, and ID match, looks good */ pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap, - bar), bar); + bar), &res_bar); + if (res_bar >= PCI_STD_NUM_BARS) + continue; + + /* Type and ID match, and the BAR value isn't reserved. + * Looks good. + */ /* Read the lower 32bit of length and offset */ pci_read_config_dword(dev, pos + offsetof(struct virtio_pci_cap, @@ -495,6 +508,7 @@ static int virtio_pci_find_shm_cap(struct pci_dev *dev, u8 required_id, length_hi), &tmp32); res_length |= ((u64)tmp32) << 32; + *bar = res_bar; *offset = res_offset; *len = res_length; @@ -538,7 +552,6 @@ static bool vp_get_shm_region(struct virtio_device *vdev, } static const struct virtio_config_ops virtio_pci_config_nodev_ops = { - .enable_cbs = vp_enable_cbs, .get = NULL, .set = NULL, .generation = vp_generation, @@ -556,7 +569,6 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = { }; static const struct virtio_config_ops virtio_pci_config_ops = { - .enable_cbs = vp_enable_cbs, .get = vp_get, .set = vp_set, .generation = vp_generation, @@ -599,7 +611,7 @@ static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type, &bar); /* Ignore structures with reserved BAR values */ - if (bar > 0x5) + if (bar >= PCI_STD_NUM_BARS) continue; if (type == cfg_type) { @@ -745,13 +757,13 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) return err; err = -EINVAL; - vp_dev->common = map_capability(pci_dev, common, + vp_dev->common = map_capability(vp_dev, common, sizeof(struct virtio_pci_common_cfg), 4, 0, sizeof(struct virtio_pci_common_cfg), NULL); if (!vp_dev->common) goto err_map_common; - vp_dev->isr = map_capability(pci_dev, isr, sizeof(u8), 1, + vp_dev->isr = map_capability(vp_dev, isr, sizeof(u8), 1, 0, 1, NULL); if (!vp_dev->isr) @@ -778,7 +790,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) * Otherwise, map each VQ individually later. */ if ((u64)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) { - vp_dev->notify_base = map_capability(pci_dev, notify, 2, 2, + vp_dev->notify_base = map_capability(vp_dev, notify, 2, 2, 0, notify_length, &vp_dev->notify_len); if (!vp_dev->notify_base) @@ -791,7 +803,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) * is more than enough for all existing devices. */ if (device) { - vp_dev->device = map_capability(pci_dev, device, 0, 4, + vp_dev->device = map_capability(vp_dev, device, 0, 4, 0, PAGE_SIZE, &vp_dev->device_len); if (!vp_dev->device) diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index ae7f9357bb871aa44911609e60529116565c98d5..359302f71f7efef34ccc419842a0079be2e364b4 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -229,7 +229,6 @@ static int rti_wdt_probe(struct platform_device *pdev) ret = pm_runtime_get_sync(dev); if (ret) { pm_runtime_put_noidle(dev); - pm_runtime_disable(&pdev->dev); return dev_err_probe(dev, ret, "runtime pm failed\n"); } diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 39def020a074b7fab442f60216916ae3c3ac6a7b..6e3e65deb0b93eb1eb08587ca4df536b2d7986e4 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -738,3 +738,4 @@ MODULE_AUTHOR("Latchesar Ionkov "); MODULE_AUTHOR("Eric Van Hensbergen "); MODULE_AUTHOR("Ron Minnich "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/Makefile b/fs/Makefile index 5dca3480ee83b22ce0412ba81a0a0d73ee9a464f..359c63fefa1b88011bb610f24d53e46a2e7156ea 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -6,6 +6,8 @@ # Rewritten to use lists instead of if-statements. # +subdir-ccflags-y += -DANDROID_GKI_VFS_EXPORT_ONLY=VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver + obj-y := open.o read_write.o file_table.o super.o \ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o dcache.o inode.o \ diff --git a/fs/adfs/super.c b/fs/adfs/super.c index bdbd26e571ed37b0a3def3fb25ed70467f6350d1..57044e5372906fa52d59199f9fb2d7f0986274ec 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -492,3 +492,4 @@ static void __exit exit_adfs_fs(void) module_init(init_adfs_fs) module_exit(exit_adfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/affs/super.c b/fs/affs/super.c index c6c2a513ec92d1549feff40c2f606bd1c0225154..2d2797ef7cfafd3988870f207922d4e1ddaec97a 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -676,6 +676,7 @@ static void __exit exit_affs_fs(void) MODULE_DESCRIPTION("Amiga filesystem support for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_affs_fs) module_exit(exit_affs_fs) diff --git a/fs/afs/main.c b/fs/afs/main.c index 179004b15566d326d507403500486d7f4377234e..c6bd956454995906983460151a641cb13cffd9ed 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -18,6 +18,7 @@ MODULE_DESCRIPTION("AFS Client File System"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); unsigned afs_debug; module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO); diff --git a/fs/attr.c b/fs/attr.c index b4bbdbd4c8ca096e86451b0443e64bc2ca9e2b1d..d8c1f796d0e91f116b6fd6516a5b3f08f145b2af 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -114,7 +114,7 @@ kill_priv: return 0; } -EXPORT_SYMBOL(setattr_prepare); +EXPORT_SYMBOL_NS(setattr_prepare, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inode_newsize_ok - may this inode be truncated to a given size @@ -158,7 +158,7 @@ out_sig: out_big: return -EFBIG; } -EXPORT_SYMBOL(inode_newsize_ok); +EXPORT_SYMBOL_NS(inode_newsize_ok, ANDROID_GKI_VFS_EXPORT_ONLY); /** * setattr_copy - copy simple metadata updates into the generic inode @@ -345,4 +345,4 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de return error; } -EXPORT_SYMBOL(notify_change); +EXPORT_SYMBOL_NS(notify_change, ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/autofs/init.c b/fs/autofs/init.c index d3f55e87433890384b3a56695b4ca26a24656193..ba08261f4faa74fd498fbbc61324ac922727cbde 100644 --- a/fs/autofs/init.c +++ b/fs/autofs/init.c @@ -44,3 +44,4 @@ static void __exit exit_autofs_fs(void) module_init(init_autofs_fs) module_exit(exit_autofs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 54f0ce44427200ba32ba0db078faf120a9b5f172..b292859f5f85a41c782e7b020b5027a0a85ddc9d 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -207,7 +207,7 @@ void make_bad_inode(struct inode *inode) inode->i_opflags &= ~IOP_XATTR; inode->i_fop = &bad_file_ops; } -EXPORT_SYMBOL(make_bad_inode); +EXPORT_SYMBOL_NS(make_bad_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /* * This tests whether an inode has been flagged as bad. The test uses @@ -227,7 +227,7 @@ bool is_bad_inode(struct inode *inode) return (inode->i_op == &bad_inode_ops); } -EXPORT_SYMBOL(is_bad_inode); +EXPORT_SYMBOL_NS(is_bad_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /** * iget_failed - Mark an under-construction inode as dead and release it diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index c1ba13d19024e4beb625714dca473094d5092dcd..abb8f6bb7e395514fe1f8442f355143e87befc40 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -34,6 +34,7 @@ MODULE_DESCRIPTION("BeOS File System (BeFS) driver"); MODULE_AUTHOR("Will Dyson"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); /* The units the vfs expects inode->i_blocks to be in */ #define VFS_BLOCK_SIZE 512 diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index fd691e4815c56492ff593e30904c15ec3e0c7a6d..293223cd4b375b95ba0c5a61e8971adc5d92972f 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -22,6 +22,7 @@ MODULE_AUTHOR("Tigran Aivazian "); MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); #undef DEBUG diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 213864bc7e8c0f7394d5d065821c5e6cc92bf953..04c4aa7a1df2c59716abaa12aefdf29fd7d4630c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -170,8 +170,8 @@ static int padzero(unsigned long elf_bss) static int create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, - unsigned long interp_load_addr, - unsigned long e_entry, unsigned long phdr_addr) + unsigned long load_addr, unsigned long interp_load_addr, + unsigned long e_entry) { struct mm_struct *mm = current->mm; unsigned long p = bprm->p; @@ -256,7 +256,7 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); - NEW_AUX_ENT(AT_PHDR, phdr_addr); + NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); @@ -820,7 +820,7 @@ static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr, static int load_elf_binary(struct linux_binprm *bprm) { struct file *interpreter = NULL; /* to shut gcc up */ - unsigned long load_addr, load_bias = 0, phdr_addr = 0; + unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; @@ -1153,17 +1153,6 @@ out_free_interp: reloc_func_desc = load_bias; } } - - /* - * Figure out which segment in the file contains the Program - * Header table, and map to the associated memory address. - */ - if (elf_ppnt->p_offset <= elf_ex->e_phoff && - elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { - phdr_addr = elf_ex->e_phoff - elf_ppnt->p_offset + - elf_ppnt->p_vaddr; - } - k = elf_ppnt->p_vaddr; if ((elf_ppnt->p_flags & PF_X) && k < start_code) start_code = k; @@ -1199,7 +1188,6 @@ out_free_interp: } e_entry = elf_ex->e_entry + load_bias; - phdr_addr += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; @@ -1263,8 +1251,8 @@ out_free_interp: goto out; #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ - retval = create_elf_tables(bprm, elf_ex, interp_load_addr, - e_entry, phdr_addr); + retval = create_elf_tables(bprm, elf_ex, + load_addr, interp_load_addr, e_entry); if (retval < 0) goto out; @@ -1613,16 +1601,17 @@ static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, * long file_ofs * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... */ -static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm) +static int fill_files_note(struct memelfnote *note) { + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; unsigned count, size, names_ofs, remaining, n; user_long_t *data; user_long_t *start_end_ofs; char *name_base, *name_curpos; - int i; /* *Estimated* file count and total data size needed */ - count = cprm->vma_count; + count = mm->map_count; if (count > UINT_MAX / 64) return -EINVAL; size = count * 64; @@ -1644,12 +1633,11 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm name_base = name_curpos = ((char *)data) + names_ofs; remaining = size - names_ofs; count = 0; - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *m = &cprm->vma_meta[i]; + for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { struct file *file; const char *filename; - file = m->file; + file = vma->vm_file; if (!file) continue; filename = file_path(file, name_curpos, remaining); @@ -1669,9 +1657,9 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm memmove(name_curpos, filename, n); name_curpos += n; - *start_end_ofs++ = m->start; - *start_end_ofs++ = m->end; - *start_end_ofs++ = m->pgoff; + *start_end_ofs++ = vma->vm_start; + *start_end_ofs++ = vma->vm_end; + *start_end_ofs++ = vma->vm_pgoff; count++; } @@ -1682,7 +1670,7 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm * Count usually is less than mm->map_count, * we need to move filenames down. */ - n = cprm->vma_count - count; + n = mm->map_count - count; if (n != 0) { unsigned shift_bytes = n * 3 * sizeof(data[0]); memmove(name_base - shift_bytes, name_base, @@ -1797,7 +1785,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - struct coredump_params *cprm) + const kernel_siginfo_t *siginfo, struct pt_regs *regs) { struct task_struct *dump_task = current; const struct user_regset_view *view = task_user_regset_view(dump_task); @@ -1869,7 +1857,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, * Now fill in each thread's information. */ for (t = info->thread; t != NULL; t = t->next) - if (!fill_thread_core_info(t, view, cprm->siginfo->si_signo, &info->size)) + if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) return 0; /* @@ -1878,13 +1866,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); info->size += notesize(&info->psinfo); - fill_siginfo_note(&info->signote, &info->csigdata, cprm->siginfo); + fill_siginfo_note(&info->signote, &info->csigdata, siginfo); info->size += notesize(&info->signote); fill_auxv_note(&info->auxv, current->mm); info->size += notesize(&info->auxv); - if (fill_files_note(&info->files, cprm) == 0) + if (fill_files_note(&info->files) == 0) info->size += notesize(&info->files); return 1; @@ -2026,7 +2014,7 @@ static int elf_note_info_init(struct elf_note_info *info) static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - struct coredump_params *cprm) + const kernel_siginfo_t *siginfo, struct pt_regs *regs) { struct core_thread *ct; struct elf_thread_status *ets; @@ -2047,13 +2035,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, list_for_each_entry(ets, &info->thread_list, list) { int sz; - sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets); + sz = elf_dump_thread_status(siginfo->si_signo, ets); info->thread_status_size += sz; } /* now collect the dump for the current */ memset(info->prstatus, 0, sizeof(*info->prstatus)); - fill_prstatus(info->prstatus, current, cprm->siginfo->si_signo); - elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs); + fill_prstatus(info->prstatus, current, siginfo->si_signo); + elf_core_copy_regs(&info->prstatus->pr_reg, regs); /* Set up header */ fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); @@ -2069,18 +2057,18 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_note(info->notes + 1, "CORE", NT_PRPSINFO, sizeof(*info->psinfo), info->psinfo); - fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo); + fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); fill_auxv_note(info->notes + 3, current->mm); info->numnote = 4; - if (fill_files_note(info->notes + info->numnote, cprm) == 0) { + if (fill_files_note(info->notes + info->numnote) == 0) { info->notes_files = info->notes + info->numnote; info->numnote++; } /* Try to dump the FPU. */ - info->prstatus->pr_fpvalid = - elf_core_copy_task_fpregs(current, cprm->regs, info->fpu); + info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, + info->fpu); if (info->prstatus->pr_fpvalid) fill_note(info->notes + info->numnote++, "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu); @@ -2166,7 +2154,8 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, static int elf_core_dump(struct coredump_params *cprm) { int has_dumped = 0; - int segs, i; + int vma_count, segs, i; + size_t vma_data_size; struct elfhdr elf; loff_t offset = 0, dataoff; struct elf_note_info info = { }; @@ -2174,12 +2163,16 @@ static int elf_core_dump(struct coredump_params *cprm) struct elf_shdr *shdr4extnum = NULL; Elf_Half e_phnum; elf_addr_t e_shoff; + struct core_vma_metadata *vma_meta; + + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) + return 0; /* * The number of segs are recored into ELF header as 16bit value. * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. */ - segs = cprm->vma_count + elf_core_extra_phdrs(); + segs = vma_count + elf_core_extra_phdrs(); /* for notes section */ segs++; @@ -2193,7 +2186,7 @@ static int elf_core_dump(struct coredump_params *cprm) * Collect all the non-memory information about the process for the * notes. This also sets up the file header. */ - if (!fill_note_info(&elf, e_phnum, &info, cprm)) + if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs)) goto end_coredump; has_dumped = 1; @@ -2217,7 +2210,7 @@ static int elf_core_dump(struct coredump_params *cprm) dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); - offset += cprm->vma_data_size; + offset += vma_data_size; offset += elf_core_extra_data_size(); e_shoff = offset; @@ -2237,8 +2230,8 @@ static int elf_core_dump(struct coredump_params *cprm) goto end_coredump; /* Write program headers for segments dump */ - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *meta = cprm->vma_meta + i; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; struct elf_phdr phdr; phdr.p_type = PT_LOAD; @@ -2275,8 +2268,8 @@ static int elf_core_dump(struct coredump_params *cprm) if (!dump_skip(cprm, dataoff - cprm->pos)) goto end_coredump; - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *meta = cprm->vma_meta + i; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; if (!dump_user_range(cprm, meta->start, meta->dump_size)) goto end_coredump; @@ -2294,6 +2287,7 @@ static int elf_core_dump(struct coredump_params *cprm) end_coredump: free_note_info(&info); kfree(shdr4extnum); + kvfree(vma_meta); kfree(phdr4note); return has_dumped; } diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 5764295a3f0ff93d2e457b5667c6e08e8b9c2db8..be4062b8ba75eef23d71b19de1c52a9e65efd064 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1479,7 +1479,7 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm, static int elf_fdpic_core_dump(struct coredump_params *cprm) { int has_dumped = 0; - int segs; + int vma_count, segs; int i; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff; @@ -1494,6 +1494,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) elf_addr_t e_shoff; struct core_thread *ct; struct elf_thread_status *tmp; + struct core_vma_metadata *vma_meta = NULL; + size_t vma_data_size; /* alloc memory for large data structures: too large to be on stack */ elf = kmalloc(sizeof(*elf), GFP_KERNEL); @@ -1503,6 +1505,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) if (!psinfo) goto end_coredump; + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, &vma_data_size)) + goto end_coredump; + for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { tmp = elf_dump_thread_status(cprm->siginfo->si_signo, @@ -1522,7 +1527,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) tmp->next = thread_list; thread_list = tmp; - segs = cprm->vma_count + elf_core_extra_phdrs(); + segs = vma_count + elf_core_extra_phdrs(); /* for notes section */ segs++; @@ -1567,7 +1572,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); - offset += cprm->vma_data_size; + offset += vma_data_size; offset += elf_core_extra_data_size(); e_shoff = offset; @@ -1587,8 +1592,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; /* write program headers for segments dump */ - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *meta = cprm->vma_meta + i; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; struct elf_phdr phdr; size_t sz; @@ -1638,7 +1643,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) if (!dump_skip(cprm, dataoff - cprm->pos)) goto end_coredump; - if (!elf_fdpic_dump_segments(cprm, cprm->vma_meta, cprm->vma_count)) + if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count)) goto end_coredump; if (!elf_core_write_extra_data(cprm)) @@ -1662,6 +1667,7 @@ end_coredump: thread_list = thread_list->next; kfree(tmp); } + kvfree(vma_meta); kfree(phdr4note); kfree(elf); kfree(psinfo); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 11b5bf2419555b00fbfb540a4433fe4d8ea20806..3e4791efdf77b81a75e1216881a929874de18f68 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -832,3 +832,4 @@ static void __exit exit_misc_binfmt(void) core_initcall(init_misc_binfmt); module_exit(exit_misc_binfmt); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/block_dev.c b/fs/block_dev.c index 600ce43c1843eded80a8341be3c5d3e32d6e1f22..aa0766b7be4f3eac0b606d4be28f23a4972d54c1 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -186,7 +186,7 @@ int sb_set_blocksize(struct super_block *sb, int size) return sb->s_blocksize; } -EXPORT_SYMBOL(sb_set_blocksize); +EXPORT_SYMBOL_NS(sb_set_blocksize, ANDROID_GKI_VFS_EXPORT_ONLY); int sb_min_blocksize(struct super_block *sb, int size) { @@ -196,7 +196,7 @@ int sb_min_blocksize(struct super_block *sb, int size) return sb_set_blocksize(sb, size); } -EXPORT_SYMBOL(sb_min_blocksize); +EXPORT_SYMBOL_NS(sb_min_blocksize, ANDROID_GKI_VFS_EXPORT_ONLY); static int blkdev_get_block(struct inode *inode, sector_t iblock, diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 4b3ae0faf548e5df94ff2e38b3d483fd42b2d106..3a3102bc15a057291154e3a44c1e369fd822bda3 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -503,11 +503,8 @@ process_slot: */ ASSERT(key.offset == 0); ASSERT(datal <= fs_info->sectorsize); - if (WARN_ON(key.offset != 0) || - WARN_ON(datal > fs_info->sectorsize)) { - ret = -EUCLEAN; - goto out; - } + if (key.offset != 0 || datal > fs_info->sectorsize) + return -EUCLEAN; ret = clone_copy_inline_extent(inode, path, &new_key, drop_start, datal, size, diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2663485c17cb88a97b8f5a5e4a12b0d86e25a119..b5d2005d3415d76415786261efcd20a7cfddd448 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2597,6 +2597,7 @@ late_initcall(init_btrfs_fs); module_exit(exit_btrfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_SOFTDEP("pre: crc32c"); MODULE_SOFTDEP("pre: xxhash64"); MODULE_SOFTDEP("pre: sha256"); diff --git a/fs/buffer.c b/fs/buffer.c index 63afd6ddb85f7a8ff2fe639047c614b0d321932d..13dd0f71f7623d87e0155500ab55dfe686e7c8ab 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -173,7 +173,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate) unlock_buffer(bh); put_bh(bh); } -EXPORT_SYMBOL(end_buffer_write_sync); +EXPORT_SYMBOL_NS(end_buffer_write_sync, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Various filesystems appear to want __find_get_block to be non-blocking. @@ -419,7 +419,7 @@ void mark_buffer_async_write(struct buffer_head *bh) { mark_buffer_async_write_endio(bh, end_buffer_async_write); } -EXPORT_SYMBOL(mark_buffer_async_write); +EXPORT_SYMBOL_NS(mark_buffer_async_write, ANDROID_GKI_VFS_EXPORT_ONLY); /* @@ -674,7 +674,7 @@ int __set_page_dirty_buffers(struct page *page) return newly_dirty; } -EXPORT_SYMBOL(__set_page_dirty_buffers); +EXPORT_SYMBOL_NS(__set_page_dirty_buffers, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Write out and wait upon a list of buffers. @@ -1141,7 +1141,7 @@ void mark_buffer_dirty(struct buffer_head *bh) __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } } -EXPORT_SYMBOL(mark_buffer_dirty); +EXPORT_SYMBOL_NS(mark_buffer_dirty, ANDROID_GKI_VFS_EXPORT_ONLY); void mark_buffer_write_io_error(struct buffer_head *bh) { @@ -1159,7 +1159,7 @@ void mark_buffer_write_io_error(struct buffer_head *bh) errseq_set(&sb->s_wb_err, -EIO); rcu_read_unlock(); } -EXPORT_SYMBOL(mark_buffer_write_io_error); +EXPORT_SYMBOL_NS(mark_buffer_write_io_error, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Decrement a buffer_head's reference count. If all buffers against a page @@ -1176,7 +1176,7 @@ void __brelse(struct buffer_head * buf) } WARN(1, KERN_ERR "VFS: brelse: Trying to free free buffer\n"); } -EXPORT_SYMBOL(__brelse); +EXPORT_SYMBOL_NS(__brelse, ANDROID_GKI_VFS_EXPORT_ONLY); /* * bforget() is like brelse(), except it discards any @@ -1195,7 +1195,7 @@ void __bforget(struct buffer_head *bh) } __brelse(bh); } -EXPORT_SYMBOL(__bforget); +EXPORT_SYMBOL_NS(__bforget, ANDROID_GKI_VFS_EXPORT_ONLY); static struct buffer_head *__bread_slow(struct buffer_head *bh) { @@ -1376,7 +1376,7 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size) brelse(bh); } } -EXPORT_SYMBOL(__breadahead); +EXPORT_SYMBOL_NS(__breadahead, ANDROID_GKI_VFS_EXPORT_ONLY); void __breadahead_gfp(struct block_device *bdev, sector_t block, unsigned size, gfp_t gfp) @@ -1411,7 +1411,7 @@ __bread_gfp(struct block_device *bdev, sector_t block, bh = __bread_slow(bh); return bh; } -EXPORT_SYMBOL(__bread_gfp); +EXPORT_SYMBOL_NS(__bread_gfp, ANDROID_GKI_VFS_EXPORT_ONLY); static void __invalidate_bh_lrus(struct bh_lru *b) { @@ -1569,7 +1569,7 @@ void block_invalidatepage(struct page *page, unsigned int offset, out: return; } -EXPORT_SYMBOL(block_invalidatepage); +EXPORT_SYMBOL_NS(block_invalidatepage, ANDROID_GKI_VFS_EXPORT_ONLY); /* @@ -1605,7 +1605,7 @@ void create_empty_buffers(struct page *page, attach_page_private(page, head); spin_unlock(&page->mapping->private_lock); } -EXPORT_SYMBOL(create_empty_buffers); +EXPORT_SYMBOL_NS(create_empty_buffers, ANDROID_GKI_VFS_EXPORT_ONLY); /** * clean_bdev_aliases: clean a range of buffers in block device @@ -1679,7 +1679,7 @@ unlock_page: break; } } -EXPORT_SYMBOL(clean_bdev_aliases); +EXPORT_SYMBOL_NS(clean_bdev_aliases, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Size is a power-of-two in the range 512..PAGE_SIZE, @@ -1937,7 +1937,7 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) bh = bh->b_this_page; } while (bh != head); } -EXPORT_SYMBOL(page_zero_new_buffers); +EXPORT_SYMBOL_NS(page_zero_new_buffers, ANDROID_GKI_VFS_EXPORT_ONLY); static void iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh, @@ -2271,7 +2271,7 @@ int block_is_partially_uptodate(struct page *page, unsigned long from, return ret; } -EXPORT_SYMBOL(block_is_partially_uptodate); +EXPORT_SYMBOL_NS(block_is_partially_uptodate, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Generic "read page" function for block devices that have the normal @@ -3138,7 +3138,7 @@ void ll_rw_block(int op, int op_flags, int nr, struct buffer_head *bhs[]) unlock_buffer(bh); } } -EXPORT_SYMBOL(ll_rw_block); +EXPORT_SYMBOL_NS(ll_rw_block, ANDROID_GKI_VFS_EXPORT_ONLY); void write_dirty_buffer(struct buffer_head *bh, int op_flags) { @@ -3185,13 +3185,13 @@ int __sync_dirty_buffer(struct buffer_head *bh, int op_flags) } return ret; } -EXPORT_SYMBOL(__sync_dirty_buffer); +EXPORT_SYMBOL_NS(__sync_dirty_buffer, ANDROID_GKI_VFS_EXPORT_ONLY); int sync_dirty_buffer(struct buffer_head *bh) { return __sync_dirty_buffer(bh, REQ_SYNC); } -EXPORT_SYMBOL(sync_dirty_buffer); +EXPORT_SYMBOL_NS(sync_dirty_buffer, ANDROID_GKI_VFS_EXPORT_ONLY); /* * try_to_free_buffers() checks if all the buffers on this particular page diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c index ddf0cd58d60cce416b1c00b5bc2d69eca8dc79bb..0649e7e6013410d47e0b11ba3b90a4aff253f052 100644 --- a/fs/cachefiles/main.c +++ b/fs/cachefiles/main.c @@ -28,6 +28,7 @@ MODULE_PARM_DESC(cachefiles_debug, "CacheFiles debugging mask"); MODULE_DESCRIPTION("Mounted-filesystem based cache"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); struct kmem_cache *cachefiles_object_jar; diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 08c8d34c9809120426e9879be89f49968b7c92da..e0562c55384f6ed5c3d198d45f47a383a47807d4 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -1335,3 +1335,4 @@ MODULE_AUTHOR("Yehuda Sadeh "); MODULE_AUTHOR("Patience Warnick "); MODULE_DESCRIPTION("Ceph filesystem for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index aa5a4d759ca236a10df969bed3f0080cb48e582e..8563e7b78c02debc9e18be3b8a0fe289b9571c61 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1693,6 +1693,7 @@ exit_cifs(void) MODULE_AUTHOR("Steve French"); MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION ("VFS to access SMB3 servers e.g. Samba, Macs, Azure and Windows (and " "also older servers complying with the SNIA CIFS Specification)"); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 0e8f484031da981c64df21bfd720b7f109d83a69..fdb1d660bd136ed2587746c860926c1ad5dbe321 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1526,7 +1526,6 @@ smb2_ioctl_query_info(const unsigned int xid, unsigned int size[2]; void *data[2]; int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; - void (*free_req1_func)(struct smb_rqst *r); vars = kzalloc(sizeof(*vars), GFP_ATOMIC); if (vars == NULL) @@ -1536,29 +1535,27 @@ smb2_ioctl_query_info(const unsigned int xid, resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; - if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) { - rc = -EFAULT; - goto free_vars; - } + if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) + goto e_fault; + if (qi.output_buffer_length > 1024) { - rc = -EINVAL; - goto free_vars; + kfree(vars); + return -EINVAL; } if (!ses || !server) { - rc = -EIO; - goto free_vars; + kfree(vars); + return -EIO; } if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - if (qi.output_buffer_length) { - buffer = memdup_user(arg + sizeof(struct smb_query_info), qi.output_buffer_length); - if (IS_ERR(buffer)) { - rc = PTR_ERR(buffer); - goto free_vars; - } + buffer = memdup_user(arg + sizeof(struct smb_query_info), + qi.output_buffer_length); + if (IS_ERR(buffer)) { + kfree(vars); + return PTR_ERR(buffer); } /* Open */ @@ -1596,45 +1593,45 @@ smb2_ioctl_query_info(const unsigned int xid, rc = SMB2_open_init(tcon, server, &rqst[0], &oplock, &oparms, path); if (rc) - goto free_output_buffer; + goto iqinf_exit; smb2_set_next_command(tcon, &rqst[0]); /* Query */ if (qi.flags & PASSTHRU_FSCTL) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) rc = -EPERM; - goto free_open_req; + else { + rqst[1].rq_iov = &vars->io_iov[0]; + rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; + + rc = SMB2_ioctl_init(tcon, server, + &rqst[1], + COMPOUND_FID, COMPOUND_FID, + qi.info_type, true, buffer, + qi.output_buffer_length, + CIFSMaxBufSize - + MAX_SMB2_CREATE_RESPONSE_SIZE - + MAX_SMB2_CLOSE_RESPONSE_SIZE); } - rqst[1].rq_iov = &vars->io_iov[0]; - rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE; - - rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, - qi.info_type, true, buffer, qi.output_buffer_length, - CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE - - MAX_SMB2_CLOSE_RESPONSE_SIZE); - free_req1_func = SMB2_ioctl_free; } else if (qi.flags == PASSTHRU_SET_INFO) { /* Can eventually relax perm check since server enforces too */ - if (!capable(CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) rc = -EPERM; - goto free_open_req; - } - if (qi.output_buffer_length < 8) { - rc = -EINVAL; - goto free_open_req; - } - rqst[1].rq_iov = &vars->si_iov[0]; - rqst[1].rq_nvec = 1; - - /* MS-FSCC 2.4.13 FileEndOfFileInformation */ - size[0] = 8; - data[0] = buffer; - - rc = SMB2_set_info_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID, - current->tgid, FILE_END_OF_FILE_INFORMATION, + else { + rqst[1].rq_iov = &vars->si_iov[0]; + rqst[1].rq_nvec = 1; + + size[0] = 8; + data[0] = buffer; + + rc = SMB2_set_info_init(tcon, server, + &rqst[1], + COMPOUND_FID, COMPOUND_FID, + current->tgid, + FILE_END_OF_FILE_INFORMATION, SMB2_O_INFO_FILE, 0, data, size); - free_req1_func = SMB2_set_info_free; + } } else if (qi.flags == PASSTHRU_QUERY_INFO) { rqst[1].rq_iov = &vars->qi_iov[0]; rqst[1].rq_nvec = 1; @@ -1645,7 +1642,6 @@ smb2_ioctl_query_info(const unsigned int xid, qi.info_type, qi.additional_information, qi.input_buffer_length, qi.output_buffer_length, buffer); - free_req1_func = SMB2_query_info_free; } else { /* unknown flags */ cifs_tcon_dbg(VFS, "Invalid passthru query flags: 0x%x\n", qi.flags); @@ -1653,7 +1649,7 @@ smb2_ioctl_query_info(const unsigned int xid, } if (rc) - goto free_open_req; + goto iqinf_exit; smb2_set_next_command(tcon, &rqst[1]); smb2_set_related(&rqst[1]); @@ -1664,14 +1660,14 @@ smb2_ioctl_query_info(const unsigned int xid, rc = SMB2_close_init(tcon, server, &rqst[2], COMPOUND_FID, COMPOUND_FID, false); if (rc) - goto free_req_1; + goto iqinf_exit; smb2_set_related(&rqst[2]); rc = compound_send_recv(xid, ses, server, flags, 3, rqst, resp_buftype, rsp_iov); if (rc) - goto out; + goto iqinf_exit; /* No need to bump num_remote_opens since handle immediately closed */ if (qi.flags & PASSTHRU_FSCTL) { @@ -1681,22 +1677,18 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount); if (qi.input_buffer_length > 0 && le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length - > rsp_iov[1].iov_len) { - rc = -EFAULT; - goto out; - } + > rsp_iov[1].iov_len) + goto e_fault; if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) { - rc = -EFAULT; - goto out; - } + sizeof(qi.input_buffer_length))) + goto e_fault; if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info), (const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset), qi.input_buffer_length)) - rc = -EFAULT; + goto e_fault; } else { pqi = (struct smb_query_info __user *)arg; qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; @@ -1704,30 +1696,28 @@ smb2_ioctl_query_info(const unsigned int xid, qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength); if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, - sizeof(qi.input_buffer_length))) { - rc = -EFAULT; - goto out; - } + sizeof(qi.input_buffer_length))) + goto e_fault; if (copy_to_user(pqi + 1, qi_rsp->Buffer, qi.input_buffer_length)) - rc = -EFAULT; + goto e_fault; } -out: + iqinf_exit: + cifs_small_buf_release(rqst[0].rq_iov[0].iov_base); + cifs_small_buf_release(rqst[1].rq_iov[0].iov_base); + cifs_small_buf_release(rqst[2].rq_iov[0].iov_base); free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); - SMB2_close_free(&rqst[2]); -free_req_1: - free_req1_func(&rqst[1]); -free_open_req: - SMB2_open_free(&rqst[0]); -free_output_buffer: - kfree(buffer); -free_vars: kfree(vars); + kfree(buffer); return rc; + +e_fault: + rc = -EFAULT; + goto iqinf_exit; } static ssize_t diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 240669f51eac36d8d6c677170341f835bfc43a8a..897c7cb93f47c80efeb04492b7ef67f74e759c55 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -388,6 +388,7 @@ MODULE_AUTHOR("Jan Harkes, Peter J. Braam"); MODULE_DESCRIPTION("Coda Distributed File System VFS interface"); MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_VERSION("7.0"); static int __init init_coda(void) diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 0c6e8cf6195300c706bb04f2be4738a54f0d785f..c01eb7264b4d18c2c3ec1651084f9fa896951819 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -175,6 +175,7 @@ MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.0.2"); MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration."); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); core_initcall(configfs_init); module_exit(configfs_exit); diff --git a/fs/coredump.c b/fs/coredump.c index b08f8fcb57124fe5b1e523743fdaaa1915cdf800..c56a3bdce7cd4552168f6d9ac52b2cdb39221ed3 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -53,9 +52,6 @@ #include -static bool dump_vma_snapshot(struct coredump_params *cprm); -static void free_vma_snapshot(struct coredump_params *cprm); - int core_uses_pid; unsigned int core_pipe_limit; char core_pattern[CORENAME_MAX_SIZE] = "core"; @@ -605,7 +601,6 @@ void do_coredump(const kernel_siginfo_t *siginfo) * by any locks. */ .mm_flags = mm->flags, - .vma_meta = NULL, }; audit_core_dumps(siginfo->si_signo); @@ -811,13 +806,9 @@ void do_coredump(const kernel_siginfo_t *siginfo) pr_info("Core dump to |%s disabled\n", cn.corename); goto close_fail; } - if (!dump_vma_snapshot(&cprm)) - goto close_fail; - file_start_write(cprm.file); core_dumped = binfmt->core_dump(&cprm); file_end_write(cprm.file); - free_vma_snapshot(&cprm); } if (ispipe && core_pipe_limit) wait_for_dump_helpers(cprm.file); @@ -909,7 +900,7 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start, stop = !dump_emit(cprm, kaddr, PAGE_SIZE); kunmap(page); - put_user_page(page); + put_page(page); } else { stop = !dump_skip(cprm, PAGE_SIZE); } @@ -978,8 +969,6 @@ static bool always_dump_vma(struct vm_area_struct *vma) return false; } -#define DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER 1 - /* * Decide how much of @vma's contents should be included in a core dump. */ @@ -1039,20 +1028,9 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, * dump the first page to aid in determining what was mapped here. */ if (FILTER(ELF_HEADERS) && - vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { - if ((READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) != 0) - return PAGE_SIZE; - - /* - * ELF libraries aren't always executable. - * We'll want to check whether the mapping starts with the ELF - * magic, but not now - we're holding the mmap lock, - * so copy_from_user() doesn't work here. - * Use a placeholder instead, and fix it up later in - * dump_vma_snapshot(). - */ - return DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER; - } + vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ) && + (READ_ONCE(file_inode(vma->vm_file)->i_mode) & 0111) != 0) + return PAGE_SIZE; #undef FILTER @@ -1089,29 +1067,18 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, return gate_vma; } -static void free_vma_snapshot(struct coredump_params *cprm) -{ - if (cprm->vma_meta) { - int i; - for (i = 0; i < cprm->vma_count; i++) { - struct file *file = cprm->vma_meta[i].file; - if (file) - fput(file); - } - kvfree(cprm->vma_meta); - cprm->vma_meta = NULL; - } -} - /* * Under the mmap_lock, take a snapshot of relevant information about the task's * VMAs. */ -static bool dump_vma_snapshot(struct coredump_params *cprm) +int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, + struct core_vma_metadata **vma_meta, + size_t *vma_data_size_ptr) { struct vm_area_struct *vma, *gate_vma; struct mm_struct *mm = current->mm; int i; + size_t vma_data_size = 0; /* * Once the stack expansion code is fixed to not change VMA bounds @@ -1119,51 +1086,36 @@ static bool dump_vma_snapshot(struct coredump_params *cprm) * mmap_lock in read mode. */ if (mmap_write_lock_killable(mm)) - return false; + return -EINTR; - cprm->vma_data_size = 0; gate_vma = get_gate_vma(mm); - cprm->vma_count = mm->map_count + (gate_vma ? 1 : 0); + *vma_count = mm->map_count + (gate_vma ? 1 : 0); - cprm->vma_meta = kvmalloc_array(cprm->vma_count, sizeof(*cprm->vma_meta), GFP_KERNEL); - if (!cprm->vma_meta) { + *vma_meta = kvmalloc_array(*vma_count, sizeof(**vma_meta), GFP_KERNEL); + if (!*vma_meta) { mmap_write_unlock(mm); - return false; + return -ENOMEM; } for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; vma = next_vma(vma, gate_vma), i++) { - struct core_vma_metadata *m = cprm->vma_meta + i; + struct core_vma_metadata *m = (*vma_meta) + i; m->start = vma->vm_start; m->end = vma->vm_end; m->flags = vma->vm_flags; m->dump_size = vma_dump_size(vma, cprm->mm_flags); - m->pgoff = vma->vm_pgoff; - m->file = vma->vm_file; - if (m->file) - get_file(m->file); + vma_data_size += m->dump_size; } mmap_write_unlock(mm); - for (i = 0; i < cprm->vma_count; i++) { - struct core_vma_metadata *m = cprm->vma_meta + i; - - if (m->dump_size == DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) { - char elfmag[SELFMAG]; - - if (copy_from_user(elfmag, (void __user *)m->start, SELFMAG) || - memcmp(elfmag, ELFMAG, SELFMAG) != 0) { - m->dump_size = 0; - } else { - m->dump_size = PAGE_SIZE; - } - } - - cprm->vma_data_size += m->dump_size; + if (WARN_ON(i != *vma_count)) { + kvfree(*vma_meta); + return -EFAULT; } - return true; + *vma_data_size_ptr = vma_data_size; + return 0; } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 4b90cfd1ec36035e0ca24914fa35b0d8563a9b8b..6245470112a1d3e70362c86d48788d67ca69a998 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -1010,3 +1010,4 @@ static void __exit exit_cramfs_fs(void) module_init(init_cramfs_fs) module_exit(exit_cramfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index 652c7180ec6de942611ff550652548f05c6af666..d39077502e0620aec31111d6503901f5e4173bbc 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + fscrypto-y := crypto.o \ fname.o \ hkdf.o \ diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 7df5877fac9a9efbd899ac0be489bf78773268ce..68ab6830767a49dbbdc8cfac890b8617e78b4e6f 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -345,6 +345,10 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh); * * fscrypt_set_bio_crypt_ctx() must have already been called on the bio. * + * This function isn't required in cases where crypto-mergeability is ensured in + * another way, such as I/O targeting only a single file (and thus a single key) + * combined with fscrypt_limit_io_blocks() to ensure DUN contiguity. + * * This function also returns false if the next part of the I/O would need to * have a different value for the bi_skip_dm_default_key flag. * @@ -402,12 +406,15 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio, EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); /** - * fscrypt_dio_supported() - check whether a direct I/O request is unsupported - * due to encryption constraints + * fscrypt_dio_supported() - check whether a DIO (direct I/O) request is + * supported as far as encryption is concerned * @iocb: the file and position the I/O is targeting * @iter: the I/O data segment(s) * - * Return: true if direct I/O is supported + * Return: %true if there are no encryption constraints that prevent DIO from + * being supported; %false if DIO is unsupported. (Note that in the + * %true case, the filesystem might have other, non-encryption-related + * constraints that prevent DIO from actually being supported.) */ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) { @@ -418,13 +425,22 @@ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) if (!fscrypt_needs_contents_encryption(inode)) return true; - /* We only support direct I/O with inline crypto, not fs-layer crypto */ + /* We only support DIO with inline crypto, not fs-layer crypto. */ if (!fscrypt_inode_uses_inline_crypto(inode)) return false; /* - * Since the granularity of encryption is filesystem blocks, the I/O - * must be block aligned -- not just disk sector aligned. + * Since the granularity of encryption is filesystem blocks, the file + * position and total I/O length must be aligned to the filesystem block + * size -- not just to the block device's logical block size as is + * traditionally the case for DIO on many filesystems. + * + * We require that the user-provided memory buffers be filesystem block + * aligned too. It is simpler to have a single alignment value required + * for all properties of the I/O, as is normally the case for DIO. + * Also, allowing less aligned buffers would imply that data units could + * cross bvecs, which would greatly complicate the I/O stack, which + * assumes that bios can be split at any bvec boundary. */ if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize)) return false; @@ -437,24 +453,25 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported); * fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs * @inode: the file on which I/O is being done * @lblk: the block at which the I/O is being started from - * @nr_blocks: the number of blocks we want to submit starting at @pos + * @nr_blocks: the number of blocks we want to submit starting at @lblk * - * Determine the limit to the number of blocks that can be submitted in the bio - * targeting @pos without causing a data unit number (DUN) discontinuity. + * Determine the limit to the number of blocks that can be submitted in a bio + * targeting @lblk without causing a data unit number (DUN) discontiguity. * * This is normally just @nr_blocks, as normally the DUNs just increment along * with the logical blocks. (Or the file is not encrypted.) * * In rare cases, fscrypt can be using an IV generation method that allows the - * DUN to wrap around within logically continuous blocks, and that wraparound + * DUN to wrap around within logically contiguous blocks, and that wraparound * will occur. If this happens, a value less than @nr_blocks will be returned - * so that the wraparound doesn't occur in the middle of the bio. + * so that the wraparound doesn't occur in the middle of a bio, which would + * cause encryption/decryption to produce wrong results. * * Return: the actual number of blocks that can be submitted */ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) { - const struct fscrypt_info *ci = inode->i_crypt_info; + const struct fscrypt_info *ci; u32 dun; if (!fscrypt_inode_uses_inline_crypto(inode)) @@ -463,6 +480,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) if (nr_blocks <= 1) return nr_blocks; + ci = inode->i_crypt_info; if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; diff --git a/fs/dcache.c b/fs/dcache.c index ea0485861d9377311a858359ab1183a1bae4e042..cb588cee9669af0664ca8589076d73e598ea57be 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2110,7 +2110,7 @@ struct dentry *d_obtain_alias(struct inode *inode) { return __d_obtain_alias(inode, true); } -EXPORT_SYMBOL(d_obtain_alias); +EXPORT_SYMBOL_NS(d_obtain_alias, ANDROID_GKI_VFS_EXPORT_ONLY); /** * d_obtain_root - find or allocate a dentry for a given inode @@ -2184,7 +2184,7 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, } return found; } -EXPORT_SYMBOL(d_add_ci); +EXPORT_SYMBOL_NS(d_add_ci, ANDROID_GKI_VFS_EXPORT_ONLY); static inline bool d_same_name(const struct dentry *dentry, @@ -3065,7 +3065,7 @@ out: __d_add(dentry, inode); return NULL; } -EXPORT_SYMBOL(d_splice_alias); +EXPORT_SYMBOL_NS(d_splice_alias, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Test whether new_dentry is a subdirectory of old_dentry. diff --git a/fs/direct-io.c b/fs/direct-io.c index 4e9b306ca6beaa007625c6f579bf41af7ca84133..771017cf8fcc96a1f8b25f0db767d41824b43966 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1367,7 +1367,7 @@ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, end_io, submit_io, flags); } -EXPORT_SYMBOL(__blockdev_direct_IO); +EXPORT_SYMBOL_NS(__blockdev_direct_IO, ANDROID_GKI_VFS_EXPORT_ONLY); static __init int dio_init(void) { diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index b2f6a1937d2390953289b8f02ef8d9170c54c1c9..eb12d38d000dfb0235cd13d3d53efda17ef54bf7 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -891,6 +891,7 @@ MODULE_AUTHOR("Michael A. Halcrow "); MODULE_DESCRIPTION("eCryptfs"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(ecryptfs_init) module_exit(ecryptfs_exit) diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 15880a68faadc58ba34d1a3f68ac412416202f2e..b62aefe3b4b8296c5e72962141dd8499b01e1fbf 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -272,6 +272,7 @@ static __exit void efivarfs_exit(void) MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr"); MODULE_DESCRIPTION("EFI Variable Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_ALIAS_FS("efivarfs"); module_init(efivarfs_init); diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 89e73a6f0d361c890cd57c7db33888c4df6a37e9..8c0ecaa62de2b474e538e06e88ed91e82add9473 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -311,3 +311,4 @@ efs_block_t efs_map_block(struct inode *inode, efs_block_t block) { } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile index 756fe2d652725fb98ec47fd43592b06ef3c55072..8a3317e38e5a8a12ca6aeb07eb47123d1a074f47 100644 --- a/fs/erofs/Makefile +++ b/fs/erofs/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_EROFS_FS) += erofs.o -erofs-objs := super.o inode.o data.o namei.o dir.o utils.o pcpubuf.o +erofs-objs := super.o inode.o data.o namei.o dir.o utils.o pcpubuf.o sysfs.o erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o erofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o erofs-$(CONFIG_EROFS_FS_ZIP_LZMA) += decompressor_lzma.o diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index d5046bbbcaf1ee8cf1a1ad715b4fc3866cd1dba7..d75a45c6913468ff4d1cd179bca33ab583674d5b 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -134,6 +134,10 @@ struct erofs_sb_info { u8 volume_name[16]; /* volume name */ u32 feature_compat; u32 feature_incompat; + + /* sysfs support */ + struct kobject s_kobj; /* /sys/fs/erofs/ */ + struct completion s_kobj_unregister; }; #define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info) @@ -261,7 +265,9 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) +EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE) EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) +EROFS_FEATURE_FUNCS(compr_head2, incompat, INCOMPAT_COMPR_HEAD2) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) /* atomic flag definitions */ @@ -484,6 +490,12 @@ int erofs_pcpubuf_growsize(unsigned int nrpages); void erofs_pcpubuf_init(void); void erofs_pcpubuf_exit(void); +/* sysfs.c */ +int erofs_register_sysfs(struct super_block *sb); +void erofs_unregister_sysfs(struct super_block *sb); +int __init erofs_init_sysfs(void); +void erofs_exit_sysfs(void); + /* utils.c / zdata.c */ struct page *erofs_allocpage(struct page **pagepool, gfp_t gfp); static inline void erofs_pagepool_add(struct page **pagepool, diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 9862457b421a1a722b60cd853d53a260d1954d6e..46c80eab75274cfcdfe2705c80a654cea8cf110a 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -695,6 +695,10 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) if (err) return err; + err = erofs_register_sysfs(sb); + if (err) + return err; + erofs_info(sb, "mounted with root inode @ nid %llu.", ROOT_NID(sbi)); return 0; } @@ -808,6 +812,7 @@ static void erofs_put_super(struct super_block *sb) DBG_BUGON(!sbi); + erofs_unregister_sysfs(sb); erofs_shrinker_unregister(sb); #ifdef CONFIG_EROFS_FS_ZIP iput(sbi->managed_cache); @@ -852,6 +857,10 @@ static int __init erofs_module_init(void) if (err) goto zip_err; + err = erofs_init_sysfs(); + if (err) + goto sysfs_err; + err = register_filesystem(&erofs_fs_type); if (err) goto fs_err; @@ -859,6 +868,8 @@ static int __init erofs_module_init(void) return 0; fs_err: + erofs_exit_sysfs(); +sysfs_err: z_erofs_exit_zip_subsystem(); zip_err: z_erofs_lzma_exit(); @@ -877,6 +888,7 @@ static void __exit erofs_module_exit(void) /* Ensure all RCU free inodes / pclusters are safe to be destroyed. */ rcu_barrier(); + erofs_exit_sysfs(); z_erofs_exit_zip_subsystem(); z_erofs_lzma_exit(); erofs_exit_shrinker(); @@ -951,3 +963,4 @@ module_exit(erofs_module_exit); MODULE_DESCRIPTION("Enhanced ROM File System"); MODULE_AUTHOR("Gao Xiang, Chao Yu, Miao Xie, CONSUMER BG, HUAWEI Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c new file mode 100644 index 0000000000000000000000000000000000000000..33e15fa63c82d91bb7a1c0cc87d2ea1cb0094d2e --- /dev/null +++ b/fs/erofs/sysfs.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C), 2008-2021, OPPO Mobile Comm Corp., Ltd. + * https://www.oppo.com/ + */ +#include +#include + +#include "internal.h" + +enum { + attr_feature, + attr_pointer_ui, + attr_pointer_bool, +}; + +enum { + struct_erofs_sb_info, +}; + +struct erofs_attr { + struct attribute attr; + short attr_id; + int struct_type, offset; +}; + +#define EROFS_ATTR(_name, _mode, _id) \ +static struct erofs_attr erofs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr_id = attr_##_id, \ +} +#define EROFS_ATTR_FUNC(_name, _mode) EROFS_ATTR(_name, _mode, _name) +#define EROFS_ATTR_FEATURE(_name) EROFS_ATTR(_name, 0444, feature) + +#define EROFS_ATTR_OFFSET(_name, _mode, _id, _struct) \ +static struct erofs_attr erofs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr_id = attr_##_id, \ + .struct_type = struct_##_struct, \ + .offset = offsetof(struct _struct, _name),\ +} + +#define EROFS_ATTR_RW(_name, _id, _struct) \ + EROFS_ATTR_OFFSET(_name, 0644, _id, _struct) + +#define EROFS_RO_ATTR(_name, _id, _struct) \ + EROFS_ATTR_OFFSET(_name, 0444, _id, _struct) + +#define EROFS_ATTR_RW_UI(_name, _struct) \ + EROFS_ATTR_RW(_name, pointer_ui, _struct) + +#define EROFS_ATTR_RW_BOOL(_name, _struct) \ + EROFS_ATTR_RW(_name, pointer_bool, _struct) + +#define ATTR_LIST(name) (&erofs_attr_##name.attr) + +static struct attribute *erofs_attrs[] = { + NULL, +}; +ATTRIBUTE_GROUPS(erofs); + +/* Features this copy of erofs supports */ +EROFS_ATTR_FEATURE(zero_padding); +EROFS_ATTR_FEATURE(compr_cfgs); +EROFS_ATTR_FEATURE(big_pcluster); +EROFS_ATTR_FEATURE(chunked_file); +EROFS_ATTR_FEATURE(device_table); +EROFS_ATTR_FEATURE(compr_head2); +EROFS_ATTR_FEATURE(sb_chksum); + +static struct attribute *erofs_feat_attrs[] = { + ATTR_LIST(zero_padding), + ATTR_LIST(compr_cfgs), + ATTR_LIST(big_pcluster), + ATTR_LIST(chunked_file), + ATTR_LIST(device_table), + ATTR_LIST(compr_head2), + ATTR_LIST(sb_chksum), + NULL, +}; +ATTRIBUTE_GROUPS(erofs_feat); + +static unsigned char *__struct_ptr(struct erofs_sb_info *sbi, + int struct_type, int offset) +{ + if (struct_type == struct_erofs_sb_info) + return (unsigned char *)sbi + offset; + return NULL; +} + +static ssize_t erofs_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info, + s_kobj); + struct erofs_attr *a = container_of(attr, struct erofs_attr, attr); + unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset); + + switch (a->attr_id) { + case attr_feature: + return sysfs_emit(buf, "supported\n"); + case attr_pointer_ui: + if (!ptr) + return 0; + return sysfs_emit(buf, "%u\n", *(unsigned int *)ptr); + case attr_pointer_bool: + if (!ptr) + return 0; + return sysfs_emit(buf, "%d\n", *(bool *)ptr); + } + return 0; +} + +static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info, + s_kobj); + struct erofs_attr *a = container_of(attr, struct erofs_attr, attr); + unsigned char *ptr = __struct_ptr(sbi, a->struct_type, a->offset); + unsigned long t; + int ret; + + switch (a->attr_id) { + case attr_pointer_ui: + if (!ptr) + return 0; + ret = kstrtoul(skip_spaces(buf), 0, &t); + if (ret) + return ret; + if (t != (unsigned int)t) + return -ERANGE; + *(unsigned int *)ptr = t; + return len; + case attr_pointer_bool: + if (!ptr) + return 0; + ret = kstrtoul(skip_spaces(buf), 0, &t); + if (ret) + return ret; + if (t != 0 && t != 1) + return -EINVAL; + *(bool *)ptr = !!t; + return len; + } + return 0; +} + +static void erofs_sb_release(struct kobject *kobj) +{ + struct erofs_sb_info *sbi = container_of(kobj, struct erofs_sb_info, + s_kobj); + complete(&sbi->s_kobj_unregister); +} + +static const struct sysfs_ops erofs_attr_ops = { + .show = erofs_attr_show, + .store = erofs_attr_store, +}; + +static struct kobj_type erofs_sb_ktype = { + .default_groups = erofs_groups, + .sysfs_ops = &erofs_attr_ops, + .release = erofs_sb_release, +}; + +static struct kobj_type erofs_ktype = { + .sysfs_ops = &erofs_attr_ops, +}; + +static struct kset erofs_root = { + .kobj = {.ktype = &erofs_ktype}, +}; + +static struct kobj_type erofs_feat_ktype = { + .default_groups = erofs_feat_groups, + .sysfs_ops = &erofs_attr_ops, +}; + +static struct kobject erofs_feat = { + .kset = &erofs_root, +}; + +int erofs_register_sysfs(struct super_block *sb) +{ + struct erofs_sb_info *sbi = EROFS_SB(sb); + int err; + + sbi->s_kobj.kset = &erofs_root; + init_completion(&sbi->s_kobj_unregister); + err = kobject_init_and_add(&sbi->s_kobj, &erofs_sb_ktype, NULL, + "%s", sb->s_id); + if (err) + goto put_sb_kobj; + return 0; + +put_sb_kobj: + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); + return err; +} + +void erofs_unregister_sysfs(struct super_block *sb) +{ + struct erofs_sb_info *sbi = EROFS_SB(sb); + + kobject_del(&sbi->s_kobj); + kobject_put(&sbi->s_kobj); + wait_for_completion(&sbi->s_kobj_unregister); +} + +int __init erofs_init_sysfs(void) +{ + int ret; + + kobject_set_name(&erofs_root.kobj, "erofs"); + erofs_root.kobj.parent = fs_kobj; + ret = kset_register(&erofs_root); + if (ret) + goto root_err; + + ret = kobject_init_and_add(&erofs_feat, &erofs_feat_ktype, + NULL, "features"); + if (ret) + goto feat_err; + return ret; + +feat_err: + kobject_put(&erofs_feat); + kset_unregister(&erofs_root); +root_err: + return ret; +} + +void erofs_exit_sysfs(void) +{ + kobject_put(&erofs_feat); + kset_unregister(&erofs_root); +} diff --git a/fs/exec.c b/fs/exec.c index 43e7883c8606a0d5a74e3a412f4a5b80ab461739..5b45f14f67f9f9fc2252518f43c2a727d15f1f7e 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -235,7 +235,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, static void put_arg_page(struct page *page) { - put_user_page(page); + put_page(page); } static void free_arg_pages(struct linux_binprm *bprm) @@ -497,14 +497,8 @@ static int bprm_stack_limits(struct linux_binprm *bprm) * the stack. They aren't stored until much later when we can't * signal to the parent that the child has run out of stack space. * Instead, calculate it here so it's possible to fail gracefully. - * - * In the case of argc = 0, make sure there is space for adding a - * empty string (which will bump argc to 1), to ensure confused - * userspace programs don't start processing from argv[1], thinking - * argc can never be 0, to keep them from walking envp by accident. - * See do_execveat_common(). */ - ptr_size = (max(bprm->argc, 1) + bprm->envc) * sizeof(void *); + ptr_size = (bprm->argc + bprm->envc) * sizeof(void *); if (limit <= ptr_size) return -E2BIG; limit -= ptr_size; @@ -1016,6 +1010,7 @@ static int exec_mmap(struct mm_struct *mm) active_mm = tsk->active_mm; tsk->active_mm = mm; tsk->mm = mm; + lru_gen_add_mm(mm); /* * This prevents preemption while active_mm is being loaded and * it and mm are being updated, which could cause problems for @@ -1028,6 +1023,7 @@ static int exec_mmap(struct mm_struct *mm) activate_mm(active_mm, mm); if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) local_irq_enable(); + lru_gen_use_mm(mm); tsk->mm->vmacache_seqnum = 0; vmacache_flush(tsk); task_unlock(tsk); @@ -1896,9 +1892,6 @@ static int do_execveat_common(int fd, struct filename *filename, } retval = count(argv, MAX_ARG_STRINGS); - if (retval == 0) - pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n", - current->comm, bprm->filename); if (retval < 0) goto out_free; bprm->argc = retval; @@ -1925,19 +1918,6 @@ static int do_execveat_common(int fd, struct filename *filename, if (retval < 0) goto out_free; - /* - * When argv is empty, add an empty string ("") as argv[0] to - * ensure confused userspace programs that start processing - * from argv[1] won't end up walking envp. See also - * bprm_stack_limits(). - */ - if (bprm->argc == 0) { - retval = copy_string_kernel("", bprm); - if (retval < 0) - goto out_free; - bprm->argc = 1; - } - retval = bprm_execve(bprm, fd, filename, flags); out_free: free_bprm(bprm); @@ -1966,8 +1946,6 @@ int kernel_execve(const char *kernel_filename, } retval = count_strings_kernel(argv); - if (WARN_ON_ONCE(retval == 0)) - retval = -EINVAL; if (retval < 0) goto out_free; bprm->argc = retval; diff --git a/fs/exfat/super.c b/fs/exfat/super.c index ba70ed1c980490cf593232722fe1e579459e0e7d..d3bf120e31e1dad7a45ff709b204cb9570e722c3 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -690,7 +690,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) if (!sb->s_root) { exfat_err(sb, "failed to get the root dentry"); err = -ENOMEM; - goto free_table; + goto put_inode; } return 0; @@ -836,5 +836,6 @@ module_exit(exit_exfat_fs); MODULE_ALIAS_FS("exfat"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("exFAT filesystem support"); MODULE_AUTHOR("Samsung Electronics Co., Ltd."); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index b6314d3c6a87d907b714542323efc6a51c4ec07c..3b772568cccc72aaf46d061852bac3d543befd01 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -756,12 +756,8 @@ static loff_t ext2_max_size(int bits) res += 1LL << (bits-2); res += 1LL << (2*(bits-2)); res += 1LL << (3*(bits-2)); - /* Compute how many metadata blocks are needed */ - meta_blocks = 1; - meta_blocks += 1 + ppb; - meta_blocks += 1 + ppb + ppb * ppb; /* Does block tree limit file size? */ - if (res + meta_blocks <= upper_limit) + if (res < upper_limit) goto check_lfs; res = upper_limit; @@ -1654,5 +1650,6 @@ static void __exit exit_ext2_fs(void) MODULE_AUTHOR("Remy Card and others"); MODULE_DESCRIPTION("Second Extended Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_ext2_fs) module_exit(exit_ext2_fs) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index ff9d356932a6692145b226b0da55d397999f65fa..afc5f656c3e76fab26cf1d0defa50b185a7a30de 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1787,20 +1787,19 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) void *inline_pos; unsigned int offset; struct ext4_dir_entry_2 *de; - bool ret = false; + bool ret = true; err = ext4_get_inode_loc(dir, &iloc); if (err) { EXT4_ERROR_INODE_ERR(dir, -err, "error %d getting inode %lu block", err, dir->i_ino); - return false; + return true; } down_read(&EXT4_I(dir)->xattr_sem); if (!ext4_has_inline_data(dir)) { *has_inline_data = 0; - ret = true; goto out; } @@ -1809,6 +1808,7 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) ext4_warning(dir->i_sb, "bad inline directory (dir #%lu) - no `..'", dir->i_ino); + ret = true; goto out; } @@ -1827,15 +1827,16 @@ bool empty_inline_dir(struct inode *dir, int *has_inline_data) dir->i_ino, le32_to_cpu(de->inode), le16_to_cpu(de->rec_len), de->name_len, inline_size); + ret = true; goto out; } if (le32_to_cpu(de->inode)) { + ret = false; goto out; } offset += ext4_rec_len_from_disk(de->rec_len, inline_size); } - ret = true; out: up_read(&EXT4_I(dir)->xattr_sem); brelse(iloc.bh); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a6b3a5553fded1a0c8b09877cc02ceb520a87e91..04c51065c1c99d99f763681ec61c356e7206d638 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3542,10 +3542,9 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length, if (ret < 0) return ret; out: - /* * When inline encryption is enabled, sometimes I/O to an encrypted file - * has to be broken up to guarantee DUN contiguity. Handle this by + * has to be broken up to guarantee DUN contiguity. Handle this by * limiting the length of the mapping returned. */ map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 15223b5a3af97d1e01f89991dafa071227088cb4..110c25824a67fd1ead6c89dfdec1e614a2a07671 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3320,95 +3320,69 @@ void ext4_mb_mark_bb(struct super_block *sb, ext4_fsblk_t block, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_group_t group; ext4_grpblk_t blkoff; - int i, err; + int i, clen, err; int already; - unsigned int clen, clen_changed, thisgrp_len; - while (len > 0) { - ext4_get_group_no_and_offset(sb, block, &group, &blkoff); - - /* - * Check to see if we are freeing blocks across a group - * boundary. - * In case of flex_bg, this can happen that (block, len) may - * span across more than one group. In that case we need to - * get the corresponding group metadata to work with. - * For this we have goto again loop. - */ - thisgrp_len = min_t(unsigned int, (unsigned int)len, - EXT4_BLOCKS_PER_GROUP(sb) - EXT4_C2B(sbi, blkoff)); - clen = EXT4_NUM_B2C(sbi, thisgrp_len); + clen = EXT4_B2C(sbi, len); - bitmap_bh = ext4_read_block_bitmap(sb, group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - bitmap_bh = NULL; - break; - } - - err = -EIO; - gdp = ext4_get_group_desc(sb, group, &gdp_bh); - if (!gdp) - break; - - ext4_lock_group(sb, group); - already = 0; - for (i = 0; i < clen; i++) - if (!mb_test_bit(blkoff + i, bitmap_bh->b_data) == - !state) - already++; - - clen_changed = clen - already; - if (state) - ext4_set_bits(bitmap_bh->b_data, blkoff, clen); - else - mb_test_and_clear_bits(bitmap_bh->b_data, blkoff, clen); - if (ext4_has_group_desc_csum(sb) && - (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { - gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); - ext4_free_group_clusters_set(sb, gdp, - ext4_free_clusters_after_init(sb, group, gdp)); - } - if (state) - clen = ext4_free_group_clusters(sb, gdp) - clen_changed; - else - clen = ext4_free_group_clusters(sb, gdp) + clen_changed; + ext4_get_group_no_and_offset(sb, block, &group, &blkoff); + bitmap_bh = ext4_read_block_bitmap(sb, group); + if (IS_ERR(bitmap_bh)) { + err = PTR_ERR(bitmap_bh); + bitmap_bh = NULL; + goto out_err; + } - ext4_free_group_clusters_set(sb, gdp, clen); - ext4_block_bitmap_csum_set(sb, group, gdp, bitmap_bh); - ext4_group_desc_csum_set(sb, group, gdp); + err = -EIO; + gdp = ext4_get_group_desc(sb, group, &gdp_bh); + if (!gdp) + goto out_err; - ext4_unlock_group(sb, group); + ext4_lock_group(sb, group); + already = 0; + for (i = 0; i < clen; i++) + if (!mb_test_bit(blkoff + i, bitmap_bh->b_data) == !state) + already++; - if (sbi->s_log_groups_per_flex) { - ext4_group_t flex_group = ext4_flex_group(sbi, group); - struct flex_groups *fg = sbi_array_rcu_deref(sbi, - s_flex_groups, flex_group); + if (state) + ext4_set_bits(bitmap_bh->b_data, blkoff, clen); + else + mb_test_and_clear_bits(bitmap_bh->b_data, blkoff, clen); + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); + ext4_free_group_clusters_set(sb, gdp, + ext4_free_clusters_after_init(sb, + group, gdp)); + } + if (state) + clen = ext4_free_group_clusters(sb, gdp) - clen + already; + else + clen = ext4_free_group_clusters(sb, gdp) + clen - already; - if (state) - atomic64_sub(clen_changed, &fg->free_clusters); - else - atomic64_add(clen_changed, &fg->free_clusters); + ext4_free_group_clusters_set(sb, gdp, clen); + ext4_block_bitmap_csum_set(sb, group, gdp, bitmap_bh); + ext4_group_desc_csum_set(sb, group, gdp); - } + ext4_unlock_group(sb, group); - err = ext4_handle_dirty_metadata(NULL, NULL, bitmap_bh); - if (err) - break; - sync_dirty_buffer(bitmap_bh); - err = ext4_handle_dirty_metadata(NULL, NULL, gdp_bh); - sync_dirty_buffer(gdp_bh); - if (err) - break; + if (sbi->s_log_groups_per_flex) { + ext4_group_t flex_group = ext4_flex_group(sbi, group); - block += thisgrp_len; - len -= thisgrp_len; - brelse(bitmap_bh); - BUG_ON(len < 0); + atomic64_sub(len, + &sbi_array_rcu_deref(sbi, s_flex_groups, + flex_group)->free_clusters); } + err = ext4_handle_dirty_metadata(NULL, NULL, bitmap_bh); if (err) - brelse(bitmap_bh); + goto out_err; + sync_dirty_buffer(bitmap_bh); + err = ext4_handle_dirty_metadata(NULL, NULL, gdp_bh); + sync_dirty_buffer(gdp_bh); + +out_err: + brelse(bitmap_bh); } /* diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 1d508db10a68775d31b4e1638445fec8f82c4bfd..bcc72cf65ed9f6f3cd338c7df75e12de7e73154a 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2962,14 +2962,14 @@ bool ext4_empty_dir(struct inode *inode) if (inode->i_size < ext4_dir_rec_len(1, NULL) + ext4_dir_rec_len(2, NULL)) { EXT4_ERROR_INODE(inode, "invalid size"); - return false; + return true; } /* The first directory block must not be a hole, * so treat it as DIRENT_HTREE */ bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE); if (IS_ERR(bh)) - return false; + return true; de = (struct ext4_dir_entry_2 *) bh->b_data; if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size, @@ -2977,7 +2977,7 @@ bool ext4_empty_dir(struct inode *inode) le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) { ext4_warning_inode(inode, "directory missing '.'"); brelse(bh); - return false; + return true; } offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); de = ext4_next_entry(de, sb->s_blocksize); @@ -2986,7 +2986,7 @@ bool ext4_empty_dir(struct inode *inode) le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) { ext4_warning_inode(inode, "directory missing '..'"); brelse(bh); - return false; + return true; } offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); while (offset < inode->i_size) { @@ -3000,7 +3000,7 @@ bool ext4_empty_dir(struct inode *inode) continue; } if (IS_ERR(bh)) - return false; + return true; } de = (struct ext4_dir_entry_2 *) (bh->b_data + (offset & (sb->s_blocksize - 1))); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c3cdfec63fdf72f4dc395802b23de93c226e2a87..bccf4f403bf8b4f8d764f8da2a99993e704e6a4f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -6758,6 +6758,7 @@ static void __exit ext4_exit_fs(void) MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); MODULE_DESCRIPTION("Fourth Extended Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_SOFTDEP("pre: crc32c"); module_init(ext4_init_fs) module_exit(ext4_exit_fs) diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index f46a7339d6cf73fe93e20b5e3a32a1ad9639917f..03ef087537c7c48d251e936a6d4c029b9dcc0592 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -143,3 +143,10 @@ config F2FS_IOSTAT Support getting IO statistics through sysfs and printing out periodic IO statistics tracepoint events. You have to turn on "iostat_enable" sysfs node to enable this feature. + +config F2FS_UNFAIR_RWSEM + bool "F2FS unfair rw_semaphore" + depends on F2FS_FS && BLK_CGROUP + help + Use unfair rw_semaphore, if system configured IO priority by block + cgroup. diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 727eb49491eedbc7b04fa1b3892fa17fe64b5d5c..bd2a0f5854aaa048831b46ee1e6a6fea198d9c92 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -98,6 +98,13 @@ repeat: } if (unlikely(!PageUptodate(page))) { + if (page->index == sbi->metapage_eio_ofs && + sbi->metapage_eio_cnt++ == MAX_RETRY_META_PAGE_EIO) { + set_ckpt_flags(sbi, CP_ERROR_FLAG); + } else { + sbi->metapage_eio_ofs = page->index; + sbi->metapage_eio_cnt = 0; + } f2fs_put_page(page, 1); return ERR_PTR(-EIO); } @@ -282,18 +289,22 @@ out: return blkno - start; } -void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) +void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index, + unsigned int ra_blocks) { struct page *page; bool readahead = false; + if (ra_blocks == RECOVERY_MIN_RA_BLOCKS) + return; + page = find_get_page(META_MAPPING(sbi), index); if (!page || !PageUptodate(page)) readahead = true; f2fs_put_page(page, 0); if (readahead) - f2fs_ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); + f2fs_ra_meta_pages(sbi, index, ra_blocks, META_POR, true); } static int __f2fs_write_meta_page(struct page *page, @@ -1545,6 +1556,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* update user_block_counts */ sbi->last_valid_block_count = sbi->total_valid_block_count; percpu_counter_set(&sbi->alloc_valid_block_count, 0); + percpu_counter_set(&sbi->rf_node_block_count, 0); /* Here, we have one bio having CP pack except cp pack 2 page */ f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index cd5369de261d367499ea224b90c05b7ad9132d93..5c49817dbcc97899999c3568ad96422960761a82 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2488,6 +2488,9 @@ static inline bool check_inplace_update_policy(struct inode *inode, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); unsigned int policy = SM_I(sbi)->ipu_policy; + if (policy & (0x1 << F2FS_IPU_HONOR_OPU_WRITE) && + is_inode_flag_set(inode, FI_OPU_WRITE)) + return false; if (policy & (0x1 << F2FS_IPU_FORCE)) return true; if (policy & (0x1 << F2FS_IPU_SSR) && f2fs_need_SSR(sbi)) @@ -2558,6 +2561,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio) if (is_inode_flag_set(inode, FI_ALIGNED_WRITE)) return true; + if (is_inode_flag_set(inode, FI_OPU_WRITE)) + return true; + if (fio) { if (page_private_gcing(fio->page)) return true; @@ -3182,8 +3188,8 @@ static int __f2fs_write_data_pages(struct address_space *mapping, f2fs_available_free_memory(sbi, DIRTY_DENTS)) goto skip_write; - /* skip writing during file defragment */ - if (is_inode_flag_set(inode, FI_DO_DEFRAG)) + /* skip writing in file defragment preparing stage */ + if (is_inode_flag_set(inode, FI_SKIP_WRITES)) goto skip_write; trace_f2fs_writepages(mapping->host, wbc, DATA); @@ -3401,7 +3407,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, *fsdata = NULL; - if (len == PAGE_SIZE) + if (len == PAGE_SIZE && !(f2fs_is_atomic_file(inode))) goto repeat; ret = f2fs_prepare_compress_overwrite(inode, pagep, @@ -3774,6 +3780,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, f2fs_down_write(&F2FS_I(inode)->i_mmap_sem); set_inode_flag(inode, FI_ALIGNED_WRITE); + set_inode_flag(inode, FI_OPU_WRITE); for (; secidx < end_sec; secidx++) { f2fs_down_write(&sbi->pin_sem); @@ -3782,7 +3789,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); f2fs_unlock_op(sbi); - set_inode_flag(inode, FI_DO_DEFRAG); + set_inode_flag(inode, FI_SKIP_WRITES); for (blkofs = 0; blkofs < blk_per_sec; blkofs++) { struct page *page; @@ -3799,7 +3806,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, f2fs_put_page(page, 1); } - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); ret = filemap_fdatawrite(inode->i_mapping); @@ -3810,7 +3817,8 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, } done: - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); + clear_inode_flag(inode, FI_OPU_WRITE); clear_inode_flag(inode, FI_ALIGNED_WRITE); f2fs_up_write(&F2FS_I(inode)->i_mmap_sem); diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 8c50518475a99a32e7ac9c4f724a982c745ad46b..fcdf253cd211e1f6ff058418a4130366283d886b 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -21,7 +21,7 @@ #include "gc.h" static LIST_HEAD(f2fs_stat_list); -static DEFINE_MUTEX(f2fs_stat_mutex); +static DEFINE_RAW_SPINLOCK(f2fs_stat_lock); #ifdef CONFIG_DEBUG_FS static struct dentry *f2fs_debugfs_root; #endif @@ -338,14 +338,16 @@ static char *s_flag[] = { [SBI_QUOTA_SKIP_FLUSH] = " quota_skip_flush", [SBI_QUOTA_NEED_REPAIR] = " quota_need_repair", [SBI_IS_RESIZEFS] = " resizefs", + [SBI_IS_FREEZING] = " freezefs", }; static int stat_show(struct seq_file *s, void *v) { struct f2fs_stat_info *si; int i = 0, j = 0; + unsigned long flags; - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_for_each_entry(si, &f2fs_stat_list, stat_list) { update_general_status(si->sbi); @@ -474,12 +476,14 @@ static int stat_show(struct seq_file *s, void *v) si->node_segs, si->bg_node_segs); seq_printf(s, " - Reclaimed segs : Normal (%d), Idle CB (%d), " "Idle Greedy (%d), Idle AT (%d), " - "Urgent High (%d), Urgent Low (%d)\n", + "Urgent High (%d), Urgent Mid (%d), " + "Urgent Low (%d)\n", si->sbi->gc_reclaimed_segs[GC_NORMAL], si->sbi->gc_reclaimed_segs[GC_IDLE_CB], si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY], si->sbi->gc_reclaimed_segs[GC_IDLE_AT], si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH], + si->sbi->gc_reclaimed_segs[GC_URGENT_MID], si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]); seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks, si->bg_data_blks + si->bg_node_blks); @@ -532,6 +536,9 @@ static int stat_show(struct seq_file *s, void *v) si->ndirty_meta, si->meta_pages); seq_printf(s, " - imeta: %4d\n", si->ndirty_imeta); + seq_printf(s, " - fsync mark: %4lld\n", + percpu_counter_sum_positive( + &si->sbi->rf_node_block_count)); seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", si->dirty_nats, si->nats, si->dirty_sits, si->sits); seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n", @@ -573,7 +580,7 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, " - paged : %llu KB\n", si->page_mem >> 10); } - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); return 0; } @@ -584,6 +591,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_stat_info *si; + unsigned long flags; int i; si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL); @@ -619,9 +627,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) atomic_set(&sbi->max_aw_cnt, 0); atomic_set(&sbi->max_vw_cnt, 0); - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_add_tail(&si->stat_list, &f2fs_stat_list); - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); return 0; } @@ -629,10 +637,11 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { struct f2fs_stat_info *si = F2FS_STAT(sbi); + unsigned long flags; - mutex_lock(&f2fs_stat_mutex); + raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_del(&si->stat_list); - mutex_unlock(&f2fs_stat_mutex); + raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags); kfree(si); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c92962e8c0f1e87a9e57a0abf0514fc51ad81e74..6b5b3e293ae1f5dfd8b0159ba5f88a863846f50b 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -130,7 +130,9 @@ typedef u32 nid_t; struct f2fs_rwsem { struct rw_semaphore internal_rwsem; +#ifdef CONFIG_F2FS_UNFAIR_RWSEM wait_queue_head_t read_waiters; +#endif }; struct f2fs_mount_info { @@ -396,6 +398,10 @@ struct discard_cmd_control { struct mutex cmd_lock; unsigned int nr_discards; /* # of discards in the list */ unsigned int max_discards; /* max. discards to be issued */ + unsigned int max_discard_request; /* max. discard request per round */ + unsigned int min_discard_issue_time; /* min. interval between discard issue */ + unsigned int mid_discard_issue_time; /* mid. interval between discard issue */ + unsigned int max_discard_issue_time; /* max. interval between discard issue */ unsigned int discard_granularity; /* discard granularity */ unsigned int undiscard_blks; /* # of undiscard blocks */ unsigned int next_pos; /* next discard position */ @@ -571,6 +577,9 @@ enum { /* maximum retry quota flush count */ #define DEFAULT_RETRY_QUOTA_FLUSH_COUNT 8 +/* maximum retry of EIO'ed meta page */ +#define MAX_RETRY_META_PAGE_EIO 100 + #define F2FS_LINK_MAX 0xffffffff /* maximum link count per file */ #define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */ @@ -584,6 +593,9 @@ enum { /* number of extent info in extent cache we try to shrink */ #define EXTENT_CACHE_SHRINK_NUMBER 128 +#define RECOVERY_MAX_RA_BLOCKS BIO_MAX_PAGES +#define RECOVERY_MIN_RA_BLOCKS 1 + struct rb_entry { struct rb_node rb_node; /* rb node located in rb-tree */ union { @@ -731,7 +743,8 @@ enum { FI_DROP_CACHE, /* drop dirty page cache */ FI_DATA_EXIST, /* indicate data exists */ FI_INLINE_DOTS, /* indicate inline dot dentries */ - FI_DO_DEFRAG, /* indicate defragment is running */ + FI_SKIP_WRITES, /* should skip data page writeback */ + FI_OPU_WRITE, /* used for opu per file */ FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */ FI_PREALLOCATED_ALL, /* all blocks for write were preallocated */ FI_HOT_DATA, /* indicate file is hot */ @@ -908,6 +921,7 @@ struct f2fs_nm_info { nid_t max_nid; /* maximum possible node ids */ nid_t available_nids; /* # of available node ids */ nid_t next_scan_nid; /* the next nid to be scanned */ + nid_t max_rf_node_blocks; /* max # of nodes for recovery */ unsigned int ram_thresh; /* control the memory footprint */ unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */ unsigned int dirty_nats_ratio; /* control dirty nats ratio threshold */ @@ -1278,6 +1292,7 @@ enum { SBI_QUOTA_SKIP_FLUSH, /* skip flushing quota in current CP */ SBI_QUOTA_NEED_REPAIR, /* quota file may be corrupted */ SBI_IS_RESIZEFS, /* resizefs is in process */ + SBI_IS_FREEZING, /* freezefs is in process */ }; enum { @@ -1297,6 +1312,7 @@ enum { GC_IDLE_AT, GC_URGENT_HIGH, GC_URGENT_LOW, + GC_URGENT_MID, MAX_GC_MODE, }; @@ -1604,6 +1620,8 @@ struct f2fs_sb_info { /* keep migration IO order for LFS mode */ struct f2fs_rwsem io_order_lock; mempool_t *write_io_dummy; /* Dummy pages */ + pgoff_t metapage_eio_ofs; /* EIO page offset */ + int metapage_eio_cnt; /* EIO count */ /* for checkpoint */ struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ @@ -1679,6 +1697,8 @@ struct f2fs_sb_info { atomic_t nr_pages[NR_COUNT_TYPE]; /* # of allocated blocks */ struct percpu_counter alloc_valid_block_count; + /* # of node block writes as roll forward recovery */ + struct percpu_counter rf_node_block_count; /* writeback control */ atomic_t wb_sync_req[META]; /* count # of WB_SYNC threads */ @@ -2103,10 +2123,20 @@ static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f) spin_unlock_irqrestore(&sbi->cp_lock, flags); } -static inline void init_f2fs_rwsem(struct f2fs_rwsem *sem) +#define init_f2fs_rwsem(sem) \ +do { \ + static struct lock_class_key __key; \ + \ + __init_f2fs_rwsem((sem), #sem, &__key); \ +} while (0) + +static inline void __init_f2fs_rwsem(struct f2fs_rwsem *sem, + const char *sem_name, struct lock_class_key *key) { - init_rwsem(&sem->internal_rwsem); + __init_rwsem(&sem->internal_rwsem, sem_name, key); +#ifdef CONFIG_F2FS_UNFAIR_RWSEM init_waitqueue_head(&sem->read_waiters); +#endif } static inline int f2fs_rwsem_is_locked(struct f2fs_rwsem *sem) @@ -2121,7 +2151,11 @@ static inline int f2fs_rwsem_is_contended(struct f2fs_rwsem *sem) static inline void f2fs_down_read(struct f2fs_rwsem *sem) { +#ifdef CONFIG_F2FS_UNFAIR_RWSEM wait_event(sem->read_waiters, down_read_trylock(&sem->internal_rwsem)); +#else + down_read(&sem->internal_rwsem); +#endif } static inline int f2fs_down_read_trylock(struct f2fs_rwsem *sem) @@ -2156,7 +2190,9 @@ static inline int f2fs_down_write_trylock(struct f2fs_rwsem *sem) static inline void f2fs_up_write(struct f2fs_rwsem *sem) { up_write(&sem->internal_rwsem); +#ifdef CONFIG_F2FS_UNFAIR_RWSEM wake_up_all(&sem->read_waiters); +#endif } static inline void f2fs_lock_op(struct f2fs_sb_info *sbi) @@ -2748,6 +2784,9 @@ static inline bool is_idle(struct f2fs_sb_info *sbi, int type) if (is_inflight_io(sbi, type)) return false; + if (sbi->gc_mode == GC_URGENT_MID) + return true; + if (sbi->gc_mode == GC_URGENT_LOW && (type == DISCARD_TIME || type == GC_TIME)) return true; @@ -3642,7 +3681,8 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type); int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type, bool sync); -void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index); +void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index, + unsigned int ra_blocks); long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write, enum iostat_type io_type); void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 144e1d9d2b20108a47951c5bd128d4a314310329..387b653e1ad213c97b8bd3ecb9c2a3a1aada6620 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -818,7 +818,7 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, { struct inode *inode = d_inode(path->dentry); struct f2fs_inode_info *fi = F2FS_I(inode); - struct f2fs_inode *ri; + struct f2fs_inode *ri = NULL; unsigned int flags; if (f2fs_has_extra_attr(inode) && @@ -2621,10 +2621,6 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, bool fragmented = false; int err; - /* if in-place-update policy is enabled, don't waste time here */ - if (f2fs_should_update_inplace(inode, NULL)) - return -EINVAL; - pg_start = range->start >> PAGE_SHIFT; pg_end = (range->start + range->len) >> PAGE_SHIFT; @@ -2632,6 +2628,13 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, inode_lock(inode); + /* if in-place-update policy is enabled, don't waste time here */ + set_inode_flag(inode, FI_OPU_WRITE); + if (f2fs_should_update_inplace(inode, NULL)) { + err = -EINVAL; + goto out; + } + /* writeback all dirty pages in the range */ err = filemap_write_and_wait_range(inode->i_mapping, range->start, range->start + range->len - 1); @@ -2713,7 +2716,7 @@ do_map: goto check; } - set_inode_flag(inode, FI_DO_DEFRAG); + set_inode_flag(inode, FI_SKIP_WRITES); idx = map.m_lblk; while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) { @@ -2738,15 +2741,16 @@ check: if (map.m_lblk < pg_end && cnt < blk_per_seg) goto do_map; - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); err = filemap_fdatawrite(inode->i_mapping); if (err) goto out; } clear_out: - clear_inode_flag(inode, FI_DO_DEFRAG); + clear_inode_flag(inode, FI_SKIP_WRITES); out: + clear_inode_flag(inode, FI_OPU_WRITE); inode_unlock(inode); if (!err) range->len = (u64)total << PAGE_SHIFT; @@ -3053,7 +3057,7 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) struct inode *inode = file_inode(filp); struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct page *ipage; + struct f2fs_inode *ri = NULL; kprojid_t kprojid; int err; @@ -3077,17 +3081,8 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid) if (IS_NOQUOTA(inode)) return err; - ipage = f2fs_get_node_page(sbi, inode->i_ino); - if (IS_ERR(ipage)) - return PTR_ERR(ipage); - - if (!F2FS_FITS_IN_INODE(F2FS_INODE(ipage), fi->i_extra_isize, - i_projid)) { - err = -EOVERFLOW; - f2fs_put_page(ipage, 1); - return err; - } - f2fs_put_page(ipage, 1); + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid)) + return -EOVERFLOW; err = f2fs_dquot_initialize(inode); if (err) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 8ab4b40c12c574911a49ac8a592335d14b844acc..79dc38eacb1938435afb7f118d99789649b2a929 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -103,7 +103,10 @@ static int gc_thread_func(void *data) sbi->gc_urgent_high_remaining--; } spin_unlock(&sbi->gc_urgent_high_lock); + } + if (sbi->gc_mode == GC_URGENT_HIGH || + sbi->gc_mode == GC_URGENT_MID) { wait_ms = gc_th->urgent_sleep_time; f2fs_down_write(&sbi->gc_lock); goto do_gc; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 8507e92b95d9c3827f1047c1ab4a2b8306d86777..5fffc22689645c09d5f2d53fe4180b60aecc2d58 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -550,7 +550,8 @@ make_now: } f2fs_set_inode_flags(inode); - if (file_should_truncate(inode)) { + if (file_should_truncate(inode) && + !is_sbi_flag_set(sbi, SBI_POR_DOING)) { ret = f2fs_truncate(inode); if (ret) goto bad_inode; @@ -778,7 +779,8 @@ void f2fs_evict_inode(struct inode *inode) f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO); f2fs_remove_ino_entry(sbi, inode->i_ino, FLUSH_INO); - sb_start_intwrite(inode->i_sb); + if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) + sb_start_intwrite(inode->i_sb); set_inode_flag(inode, FI_NO_ALLOC); i_size_write(inode, 0); retry: @@ -809,7 +811,8 @@ retry: if (dquot_initialize_needed(inode)) set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); } - sb_end_intwrite(inode->i_sb); + if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) + sb_end_intwrite(inode->i_sb); no_delete: dquot_drop(inode); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index f978c0f91558dc1bf9758900f095ae465995267a..0de98abd72829053c6daa651e0311fc5c790afca 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1106,8 +1106,7 @@ out_dir: out_old: f2fs_put_page(old_page, 0); out: - if (whiteout) - iput(whiteout); + iput(whiteout); return err; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 56d310c1f15ec817a5a13cf5745ece569f306fc8..ba0766a56dfaabd3ec5434dfb3597bb53e3ef39c 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1782,6 +1782,7 @@ continue_unlock: if (!atomic || page == last_page) { set_fsync_mark(page, 1); + percpu_counter_inc(&sbi->rf_node_block_count); if (IS_INODE(page)) { if (is_inode_flag_set(inode, FI_DIRTY_INODE)) @@ -3222,6 +3223,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi) nm_i->ram_thresh = DEF_RAM_THRESHOLD; nm_i->ra_nid_pages = DEF_RA_NID_PAGES; nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD; + nm_i->max_rf_node_blocks = DEF_RF_NODE_BLOCKS; INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC); INIT_LIST_HEAD(&nm_i->free_nid_list); diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 18b98cf0465b843076a8e0b2dc531a55e05f0e97..4c1d34bfea7811e3bbb20dd5fc57d34d5802fcec 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -31,6 +31,9 @@ /* control total # of nats */ #define DEF_NAT_CACHE_THRESHOLD 100000 +/* control total # of node writes used for roll-fowrad recovery */ +#define DEF_RF_NODE_BLOCKS 0 + /* vector size for gang look-up from nat cache that consists of radix tree */ #define NATVEC_SIZE 64 #define SETVEC_SIZE 32 diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index be784f983b4a9779f6a717bb44d47e570d5f912c..329ae992ee0eb8b3a08ee071358e3b007ac356f5 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -55,6 +55,10 @@ bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi) if (sbi->last_valid_block_count + nalloc > sbi->user_block_count) return false; + if (NM_I(sbi)->max_rf_node_blocks && + percpu_counter_sum_positive(&sbi->rf_node_block_count) >= + NM_I(sbi)->max_rf_node_blocks) + return false; return true; } @@ -342,6 +346,19 @@ static int recover_inode(struct inode *inode, struct page *page) return 0; } +static unsigned int adjust_por_ra_blocks(struct f2fs_sb_info *sbi, + unsigned int ra_blocks, unsigned int blkaddr, + unsigned int next_blkaddr) +{ + if (blkaddr + 1 == next_blkaddr) + ra_blocks = min_t(unsigned int, RECOVERY_MAX_RA_BLOCKS, + ra_blocks * 2); + else if (next_blkaddr % sbi->blocks_per_seg) + ra_blocks = max_t(unsigned int, RECOVERY_MIN_RA_BLOCKS, + ra_blocks / 2); + return ra_blocks; +} + static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, bool check_only) { @@ -349,6 +366,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, struct page *page = NULL; block_t blkaddr; unsigned int loop_cnt = 0; + unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS; unsigned int free_blocks = MAIN_SEGS(sbi) * sbi->blocks_per_seg - valid_user_blocks(sbi); int err = 0; @@ -423,11 +441,14 @@ next: break; } + ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr, + next_blkaddr_of_node(page)); + /* check next segment */ blkaddr = next_blkaddr_of_node(page); f2fs_put_page(page, 1); - f2fs_ra_meta_pages_cond(sbi, blkaddr); + f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks); } return err; } @@ -704,6 +725,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, struct page *page = NULL; int err = 0; block_t blkaddr; + unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS; /* get node pages in the current segment */ curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); @@ -715,8 +737,6 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) break; - f2fs_ra_meta_pages_cond(sbi, blkaddr); - page = f2fs_get_tmp_page(sbi, blkaddr); if (IS_ERR(page)) { err = PTR_ERR(page); @@ -759,9 +779,14 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list, if (entry->blkaddr == blkaddr) list_move_tail(&entry->list, tmp_inode_list); next: + ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr, + next_blkaddr_of_node(page)); + /* check next segment */ blkaddr = next_blkaddr_of_node(page); f2fs_put_page(page, 1); + + f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks); } if (!err) f2fs_allocate_new_segments(sbi); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c11d39965cae6eac6f41fc888ca9ef067afa7857..e5e4956ead314b4a8e7b06e7523794393b1d6e31 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1159,14 +1159,14 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->ordered = false; dpolicy->granularity = granularity; - dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; + dpolicy->max_requests = dcc->max_discard_request; dpolicy->io_aware_gran = MAX_PLIST_NUM; dpolicy->timeout = false; if (discard_type == DPOLICY_BG) { - dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; - dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME; - dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; + dpolicy->min_interval = dcc->min_discard_issue_time; + dpolicy->mid_interval = dcc->mid_discard_issue_time; + dpolicy->max_interval = dcc->max_discard_issue_time; dpolicy->io_aware = true; dpolicy->sync = false; dpolicy->ordered = true; @@ -1174,12 +1174,12 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->granularity = 1; if (atomic_read(&dcc->discard_cmd_cnt)) dpolicy->max_interval = - DEF_MIN_DISCARD_ISSUE_TIME; + dcc->min_discard_issue_time; } } else if (discard_type == DPOLICY_FORCE) { - dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; - dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME; - dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; + dpolicy->min_interval = dcc->min_discard_issue_time; + dpolicy->mid_interval = dcc->mid_discard_issue_time; + dpolicy->max_interval = dcc->max_discard_issue_time; dpolicy->io_aware = false; } else if (discard_type == DPOLICY_FSTRIM) { dpolicy->io_aware = false; @@ -1784,7 +1784,7 @@ static int issue_discard_thread(void *data) struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; wait_queue_head_t *q = &dcc->discard_wait_queue; struct discard_policy dpolicy; - unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; + unsigned int wait_ms = dcc->min_discard_issue_time; int issued; set_freezable(); @@ -2183,6 +2183,10 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi) atomic_set(&dcc->discard_cmd_cnt, 0); dcc->nr_discards = 0; dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg; + dcc->max_discard_request = DEF_MAX_DISCARD_REQUEST; + dcc->min_discard_issue_time = DEF_MIN_DISCARD_ISSUE_TIME; + dcc->mid_discard_issue_time = DEF_MID_DISCARD_ISSUE_TIME; + dcc->max_discard_issue_time = DEF_MAX_DISCARD_ISSUE_TIME; dcc->undiscard_blks = 0; dcc->next_pos = 0; dcc->root = RB_ROOT_CACHED; diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 3c01315931f6141dce276513fdce68213b4b0c3e..aeb008f2377be13eb8878220a978fbe9d500dac9 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -651,7 +651,9 @@ static inline int utilization(struct f2fs_sb_info *sbi) * pages over min_fsync_blocks. (=default option) * F2FS_IPU_ASYNC - do IPU given by asynchronous write requests. * F2FS_IPU_NOCACHE - disable IPU bio cache. - * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode) + * F2FS_IPU_HONOR_OPU_WRITE - use OPU write prior to IPU write if inode has + * FI_OPU_WRITE flag. + * F2FS_IPU_DISABLE - disable IPU. (=default option in LFS mode) */ #define DEF_MIN_IPU_UTIL 70 #define DEF_MIN_FSYNC_BLOCKS 8 @@ -667,6 +669,7 @@ enum { F2FS_IPU_FSYNC, F2FS_IPU_ASYNC, F2FS_IPU_NOCACHE, + F2FS_IPU_HONOR_OPU_WRITE, }; static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ff6daa58387345906813079253bc9e487f1d3cd1..3d13fe053b308e1b8f1c51ef9357c569eb820e3d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1512,8 +1512,9 @@ static void f2fs_free_inode(struct inode *inode) static void destroy_percpu_info(struct f2fs_sb_info *sbi) { - percpu_counter_destroy(&sbi->alloc_valid_block_count); percpu_counter_destroy(&sbi->total_valid_inode_count); + percpu_counter_destroy(&sbi->rf_node_block_count); + percpu_counter_destroy(&sbi->alloc_valid_block_count); } static void destroy_device_list(struct f2fs_sb_info *sbi) @@ -1673,11 +1674,15 @@ static int f2fs_freeze(struct super_block *sb) /* ensure no checkpoint required */ if (!llist_empty(&F2FS_SB(sb)->cprc_info.issue_list)) return -EINVAL; + + /* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */ + set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); return 0; } static int f2fs_unfreeze(struct super_block *sb) { + clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); return 0; } @@ -2086,6 +2091,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) { unsigned int s_flags = sbi->sb->s_flags; struct cp_control cpc; + unsigned int gc_mode; int err = 0; int ret; block_t unusable; @@ -2098,6 +2104,9 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) f2fs_update_time(sbi, DISABLE_TIME); + gc_mode = sbi->gc_mode; + sbi->gc_mode = GC_URGENT_HIGH; + while (!f2fs_time_over(sbi, DISABLE_TIME)) { f2fs_down_write(&sbi->gc_lock); err = f2fs_gc(sbi, true, false, false, NULL_SEGNO); @@ -2135,6 +2144,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) out_unlock: f2fs_up_write(&sbi->gc_lock); restore_flag: + sbi->gc_mode = gc_mode; sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */ return err; } @@ -3586,6 +3596,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino); F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino); sbi->cur_victim_sec = NULL_SECNO; + sbi->gc_mode = GC_NORMAL; sbi->next_victim_seg[BG_GC] = NULL_SEGNO; sbi->next_victim_seg[FG_GC] = NULL_SEGNO; sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; @@ -3631,11 +3642,20 @@ static int init_percpu_info(struct f2fs_sb_info *sbi) if (err) return err; + err = percpu_counter_init(&sbi->rf_node_block_count, 0, GFP_KERNEL); + if (err) + goto err_valid_block; + err = percpu_counter_init(&sbi->total_valid_inode_count, 0, GFP_KERNEL); if (err) - percpu_counter_destroy(&sbi->alloc_valid_block_count); + goto err_node_block; + return 0; +err_node_block: + percpu_counter_destroy(&sbi->rf_node_block_count); +err_valid_block: + percpu_counter_destroy(&sbi->alloc_valid_block_count); return err; } @@ -3962,7 +3982,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; if (f2fs_block_unit_discard(sbi)) sm_i->dcc_info->discard_granularity = 1; - sm_i->ipu_policy = 1 << F2FS_IPU_FORCE; + sm_i->ipu_policy = 1 << F2FS_IPU_FORCE | + 1 << F2FS_IPU_HONOR_OPU_WRITE; } sbi->readdir_ra = 1; @@ -4685,5 +4706,6 @@ module_exit(exit_f2fs_fs) MODULE_AUTHOR("Samsung Electronics's Praesto Team"); MODULE_DESCRIPTION("Flash Friendly File System"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_SOFTDEP("pre: crc32"); diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 5a381d0fe4a470220a203a0283a40cacf96c7ad9..f240f55933940b1ed659c95e5c50656b7b5ef38f 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -41,6 +41,16 @@ enum { ATGC_INFO, /* struct atgc_management */ }; +static const char *gc_mode_names[MAX_GC_MODE] = { + "GC_NORMAL", + "GC_IDLE_CB", + "GC_IDLE_GREEDY", + "GC_IDLE_AT", + "GC_URGENT_HIGH", + "GC_URGENT_LOW", + "GC_URGENT_MID" +}; + struct f2fs_attr { struct attribute attr; ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); @@ -317,8 +327,13 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, return sysfs_emit(buf, "%u\n", sbi->compr_new_inode); #endif + if (!strcmp(a->attr.name, "gc_urgent")) + return sysfs_emit(buf, "%s\n", + gc_mode_names[sbi->gc_mode]); + if (!strcmp(a->attr.name, "gc_segment_mode")) - return sysfs_emit(buf, "%u\n", sbi->gc_segment_mode); + return sysfs_emit(buf, "%s\n", + gc_mode_names[sbi->gc_segment_mode]); if (!strcmp(a->attr.name, "gc_reclaimed_segments")) { return sysfs_emit(buf, "%u\n", @@ -469,6 +484,13 @@ out: } } else if (t == 2) { sbi->gc_mode = GC_URGENT_LOW; + } else if (t == 3) { + sbi->gc_mode = GC_URGENT_MID; + if (sbi->gc_thread) { + sbi->gc_thread->gc_wake = 1; + wake_up_interruptible_all( + &sbi->gc_thread->gc_wait_queue_head); + } } else { return -EINVAL; } @@ -717,6 +739,10 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_request, max_discard_request); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, min_discard_issue_time, min_discard_issue_time); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, mid_discard_issue_time, mid_discard_issue_time); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_issue_time, max_discard_issue_time); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity); F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); @@ -729,6 +755,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio); +F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, max_roll_forward_node_blocks, max_rf_node_blocks); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, migration_granularity, migration_granularity); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); @@ -833,6 +860,10 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(reclaim_segments), ATTR_LIST(main_blkaddr), ATTR_LIST(max_small_discards), + ATTR_LIST(max_discard_request), + ATTR_LIST(min_discard_issue_time), + ATTR_LIST(mid_discard_issue_time), + ATTR_LIST(max_discard_issue_time), ATTR_LIST(discard_granularity), ATTR_LIST(pending_discard), ATTR_LIST(batched_trim_sections), @@ -848,6 +879,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(ram_thresh), ATTR_LIST(ra_nid_pages), ATTR_LIST(dirty_nats_ratio), + ATTR_LIST(max_roll_forward_node_blocks), ATTR_LIST(cp_interval), ATTR_LIST(idle_interval), ATTR_LIST(discard_idle_interval), diff --git a/fs/fat/inode.c b/fs/fat/inode.c index bab9b202b496686b5f97447609db4b32f23cf900..577c73a55c68ddb3ff816ef57b1c1f9cd9f32399 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1979,3 +1979,4 @@ module_init(init_fat_fs) module_exit(exit_fat_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 9d062886fbc19d10dbb81cd2dc5f1cc19f5fbc24..8376577ba01495005d60e08c0fc7a4271ca7ceab 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -680,6 +680,7 @@ static void __exit exit_msdos_fs(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_AUTHOR("Werner Almesberger"); MODULE_DESCRIPTION("MS-DOS filesystem support"); diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 0cdd0fb9f742a09f9a32f0ada71dd25c888b72d4..01fab05dc7a1694c93a9cec8b2212377485e4fdd 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -1077,6 +1077,7 @@ static void __exit exit_vfat_fs(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("VFAT filesystem support"); MODULE_AUTHOR("Gordon Chaffee"); diff --git a/fs/file.c b/fs/file.c index 1f23ec78e722fbc005cc83d240dbefa0310b763e..dcb7918b13742e54d14f83cf6d51515e90c557cd 100644 --- a/fs/file.c +++ b/fs/file.c @@ -85,21 +85,6 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) copy_fd_bitmaps(nfdt, ofdt, ofdt->max_fds); } -/* - * Note how the fdtable bitmap allocations very much have to be a multiple of - * BITS_PER_LONG. This is not only because we walk those things in chunks of - * 'unsigned long' in some places, but simply because that is how the Linux - * kernel bitmaps are defined to work: they are not "bits in an array of bytes", - * they are very much "bits in an array of unsigned long". - * - * The ALIGN(nr, BITS_PER_LONG) here is for clarity: since we just multiplied - * by that "1024/sizeof(ptr)" before, we already know there are sufficient - * clear low bits. Clang seems to realize that, gcc ends up being confused. - * - * On a 128-bit machine, the ALIGN() would actually matter. In the meantime, - * let's consider it documentation (and maybe a test-case for gcc to improve - * its code generation ;) - */ static struct fdtable * alloc_fdtable(unsigned int nr) { struct fdtable *fdt; @@ -115,7 +100,6 @@ static struct fdtable * alloc_fdtable(unsigned int nr) nr /= (1024 / sizeof(struct file *)); nr = roundup_pow_of_two(nr + 1); nr *= (1024 / sizeof(struct file *)); - nr = ALIGN(nr, BITS_PER_LONG); /* * Note that this can drive nr *below* what we had passed if sysctl_nr_open * had been set lower between the check in expand_files() and here. Deal @@ -283,19 +267,6 @@ static unsigned int count_open_files(struct fdtable *fdt) return i; } -/* - * Note that a sane fdtable size always has to be a multiple of - * BITS_PER_LONG, since we have bitmaps that are sized by this. - * - * 'max_fds' will normally already be properly aligned, but it - * turns out that in the close_range() -> __close_range() -> - * unshare_fd() -> dup_fd() -> sane_fdtable_size() we can end - * up having a 'max_fds' value that isn't already aligned. - * - * Rather than make close_range() have to worry about this, - * just make that BITS_PER_LONG alignment be part of a sane - * fdtable size. Becuase that's really what it is. - */ static unsigned int sane_fdtable_size(struct fdtable *fdt, unsigned int max_fds) { unsigned int count; @@ -303,7 +274,7 @@ static unsigned int sane_fdtable_size(struct fdtable *fdt, unsigned int max_fds) count = count_open_files(fdt); if (max_fds < NR_OPEN_DEFAULT) max_fds = NR_OPEN_DEFAULT; - return ALIGN(min(count, max_fds), BITS_PER_LONG); + return min(count, max_fds); } /* @@ -699,7 +670,7 @@ int __close_fd(struct files_struct *files, unsigned fd) return filp_close(file, files); } -EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ +EXPORT_SYMBOL_NS(__close_fd, ANDROID_GKI_VFS_EXPORT_ONLY); /* for ksys_close() */ /** * last_fd - return last valid index into fd table diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 578a5062706ee9db9aaa43005276ccefd0680cbc..88fe3f4704097ca4ca4b0759cdad5271a2d471c8 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -52,6 +52,7 @@ MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski"); MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver"); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *vxfs_inode_cachep; diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index a0869194ab7390be901453abfc96b0df24c9c7e2..d51354221fe77c7543613b786123b573e39ee254 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2338,7 +2338,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) out_unlock_inode: spin_unlock(&inode->i_lock); } -EXPORT_SYMBOL(__mark_inode_dirty); +EXPORT_SYMBOL_NS(__mark_inode_dirty, ANDROID_GKI_VFS_EXPORT_ONLY); /* * The @s_sync_lock is used to serialise concurrent sync operations @@ -2504,7 +2504,7 @@ void try_to_writeback_inodes_sb(struct super_block *sb, enum wb_reason reason) __writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason, true); up_read(&sb->s_umount); } -EXPORT_SYMBOL(try_to_writeback_inodes_sb); +EXPORT_SYMBOL_NS(try_to_writeback_inodes_sb, ANDROID_GKI_VFS_EXPORT_ONLY); /** * sync_inodes_sb - sync sb inode pages @@ -2571,7 +2571,7 @@ int write_inode_now(struct inode *inode, int sync) might_sleep(); return writeback_single_inode(inode, &wbc); } -EXPORT_SYMBOL(write_inode_now); +EXPORT_SYMBOL_NS(write_inode_now, ANDROID_GKI_VFS_EXPORT_ONLY); /** * sync_inode - write an inode and its pages to disk. @@ -2608,4 +2608,4 @@ int sync_inode_metadata(struct inode *inode, int wait) return sync_inode(inode, &wbc); } -EXPORT_SYMBOL(sync_inode_metadata); +EXPORT_SYMBOL_NS(sync_inode_metadata, ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/fs_types.c b/fs/fs_types.c index 78365e5dc08caa3aac60b2c0e11b6fc4597cdd42..a11a1d8c7811f6782fd06c4c22de14223d8ed7d7 100644 --- a/fs/fs_types.c +++ b/fs/fs_types.c @@ -41,7 +41,7 @@ unsigned char fs_ftype_to_dtype(unsigned int filetype) return fs_dtype_by_ftype[filetype]; } -EXPORT_SYMBOL_GPL(fs_ftype_to_dtype); +EXPORT_SYMBOL_NS_GPL(fs_ftype_to_dtype, ANDROID_GKI_VFS_EXPORT_ONLY); /* * dirent file type to fs on-disk file type conversion diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile index 79e08e05ef84803437a4d1af3fa6589eba62a62b..9121382cf16da1e4d9a917ee1952a4ed58446924 100644 --- a/fs/fscache/Makefile +++ b/fs/fscache/Makefile @@ -3,6 +3,8 @@ # Makefile for general filesystem caching code # +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + fscache-y := \ cache.o \ cookie.o \ diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 118bd9d12945f2a382aa9f6f84165b01d94d21b2..b68f4f53497437bef982466563ef7d685bf8e9cc 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -17,9 +17,12 @@ struct fuse_bpf_aio_req { struct kiocb iocb; - struct kiocb *iocb_fuse; + refcount_t ref; + struct kiocb *iocb_orig; }; +static struct kmem_cache *fuse_bpf_aio_request_cachep; + static void fuse_file_accessed(struct file *dst_file, struct file *src_file) { struct inode *dst_inode; @@ -94,7 +97,7 @@ out: return bpf_prog; } -int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foio, +int fuse_open_initialize(struct fuse_bpf_args *fa, struct fuse_open_io *foio, struct inode *inode, struct file *file, bool isdir) { foio->foi = (struct fuse_open_in) { @@ -103,16 +106,16 @@ int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foio, foio->foo = (struct fuse_open_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, .opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN, .in_numargs = 1, .out_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(foio->foi), .value = &foio->foi, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(foio->foo), .value = &foio->foo, }, @@ -121,7 +124,7 @@ int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foio, return 0; } -int fuse_open_backing(struct fuse_args *fa, +int fuse_open_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir) { struct fuse_mount *fm = get_fuse_mount(inode); @@ -172,7 +175,7 @@ int fuse_open_backing(struct fuse_args *fa, return 0; } -void *fuse_open_finalize(struct fuse_args *fa, +void *fuse_open_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir) { struct fuse_file *ff = file->private_data; @@ -184,7 +187,7 @@ void *fuse_open_finalize(struct fuse_args *fa, } int fuse_create_open_initialize( - struct fuse_args *fa, struct fuse_create_open_io *fcoio, + struct fuse_bpf_args *fa, struct fuse_create_open_io *fcoio, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode) { @@ -196,24 +199,24 @@ int fuse_create_open_initialize( fcoio->feo = (struct fuse_entry_out) {0}; fcoio->foo = (struct fuse_open_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_CREATE, .in_numargs = 2, .out_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(fcoio->fci), .value = &fcoio->fci, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(fcoio->feo), .value = &fcoio->feo, }, - .out_args[1] = (struct fuse_arg) { + .out_args[1] = (struct fuse_bpf_arg) { .size = sizeof(fcoio->foo), .value = &fcoio->foo, }, @@ -248,7 +251,7 @@ static int fuse_open_file_backing(struct inode *inode, struct file *file) } int fuse_create_open_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode) { @@ -318,7 +321,7 @@ out: } void *fuse_create_open_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode) { @@ -334,7 +337,7 @@ void *fuse_create_open_finalize( return 0; } -int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, +int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file) { struct fuse_file *fuse_file = file->private_data; @@ -346,7 +349,7 @@ int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, .fh = ((struct fuse_file *)(file->private_data))->fh, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, .opcode = FUSE_RELEASE, .in_numargs = 1, @@ -357,7 +360,7 @@ int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, return 0; } -int fuse_releasedir_initialize(struct fuse_args *fa, +int fuse_releasedir_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file) { @@ -370,7 +373,7 @@ int fuse_releasedir_initialize(struct fuse_args *fa, .fh = ((struct fuse_file *)(file->private_data))->fh, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, .opcode = FUSE_RELEASEDIR, .in_numargs = 1, @@ -381,20 +384,20 @@ int fuse_releasedir_initialize(struct fuse_args *fa, return 0; } -int fuse_release_backing(struct fuse_args *fa, +int fuse_release_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file) { return 0; } -void *fuse_release_finalize(struct fuse_args *fa, +void *fuse_release_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file) { fuse_file_free(file->private_data); return NULL; } -int fuse_flush_initialize(struct fuse_args *fa, struct fuse_flush_in *ffi, +int fuse_flush_initialize(struct fuse_bpf_args *fa, struct fuse_flush_in *ffi, struct file *file, fl_owner_t id) { struct fuse_file *fuse_file = file->private_data; @@ -403,19 +406,19 @@ int fuse_flush_initialize(struct fuse_args *fa, struct fuse_flush_in *ffi, .fh = fuse_file->fh, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(file->f_inode), .opcode = FUSE_FLUSH, .in_numargs = 1, .in_args[0].size = sizeof(*ffi), .in_args[0].value = ffi, - .force = true, + .flags = FUSE_BPF_FORCE, }; return 0; } -int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id) +int fuse_flush_backing(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id) { struct fuse_file *fuse_file = file->private_data; struct file *backing_file = fuse_file->backing_file; @@ -425,12 +428,12 @@ int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id) return 0; } -void *fuse_flush_finalize(struct fuse_args *fa, struct file *file, fl_owner_t id) +void *fuse_flush_finalize(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id) { return NULL; } -int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio, +int fuse_lseek_initialize(struct fuse_bpf_args *fa, struct fuse_lseek_io *flio, struct file *file, loff_t offset, int whence) { struct fuse_file *fuse_file = file->private_data; @@ -441,7 +444,7 @@ int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio, .whence = whence, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(file->f_inode), .opcode = FUSE_LSEEK, .in_numargs = 1, @@ -455,7 +458,7 @@ int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio, return 0; } -int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, int whence) +int fuse_lseek_backing(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence) { const struct fuse_lseek_in *fli = fa->in_args[0].value; struct fuse_lseek_out *flo = fa->out_args[0].value; @@ -465,11 +468,15 @@ int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, i /* TODO: Handle changing of the file handle */ if (offset == 0) { - if (whence == SEEK_CUR) - return file->f_pos; + if (whence == SEEK_CUR) { + flo->offset = file->f_pos; + return flo->offset; + } - if (whence == SEEK_SET) - return vfs_setpos(file, 0, 0); + if (whence == SEEK_SET) { + flo->offset = vfs_setpos(file, 0, 0); + return flo->offset; + } } inode_lock(file->f_inode); @@ -480,7 +487,7 @@ int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, i return ret; } -void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset, int whence) +void *fuse_lseek_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence) { struct fuse_lseek_out *flo = fa->out_args[0].value; @@ -489,7 +496,7 @@ void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset return ERR_PTR(flo->offset); } -int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_range_io *fcf, +int fuse_copy_file_range_initialize(struct fuse_bpf_args *fa, struct fuse_copy_file_range_io *fcf, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags) { @@ -507,7 +514,7 @@ int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_ .flags = flags, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(file_in->f_inode), .opcode = FUSE_COPY_FILE_RANGE, .in_numargs = 1, @@ -521,7 +528,7 @@ int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_ return 0; } -int fuse_copy_file_range_backing(struct fuse_args *fa, struct file *file_in, loff_t pos_in, +int fuse_copy_file_range_backing(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags) { @@ -540,14 +547,14 @@ int fuse_copy_file_range_backing(struct fuse_args *fa, struct file *file_in, lof flags); } -void *fuse_copy_file_range_finalize(struct fuse_args *fa, struct file *file_in, loff_t pos_in, +void *fuse_copy_file_range_finalize(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags) { return NULL; } -int fuse_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync) { struct fuse_file *fuse_file = file->private_data; @@ -557,19 +564,19 @@ int fuse_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(file->f_inode)->nodeid, .opcode = FUSE_FSYNC, .in_numargs = 1, .in_args[0].size = sizeof(*ffi), .in_args[0].value = ffi, - .force = true, + .flags = FUSE_BPF_FORCE, }; return 0; } -int fuse_fsync_backing(struct fuse_args *fa, +int fuse_fsync_backing(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync) { struct fuse_file *fuse_file = file->private_data; @@ -580,13 +587,13 @@ int fuse_fsync_backing(struct fuse_args *fa, return vfs_fsync(backing_file, new_datasync); } -void *fuse_fsync_finalize(struct fuse_args *fa, +void *fuse_fsync_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync) { return NULL; } -int fuse_dir_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_dir_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync) { struct fuse_file *fuse_file = file->private_data; @@ -596,19 +603,19 @@ int fuse_dir_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(file->f_inode)->nodeid, .opcode = FUSE_FSYNCDIR, .in_numargs = 1, .in_args[0].size = sizeof(*ffi), .in_args[0].value = ffi, - .force = true, + .flags = FUSE_BPF_FORCE, }; return 0; } -int fuse_getxattr_initialize(struct fuse_args *fa, +int fuse_getxattr_initialize(struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, const char *name, void *value, size_t size) @@ -617,35 +624,34 @@ int fuse_getxattr_initialize(struct fuse_args *fa, .fgi.size = size, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_GETXATTR, .in_numargs = 2, .out_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(fgio->fgi), .value = &fgio->fgi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = strlen(name) + 1, .value = name, }, - .out_argvar = size ? true : false, + .flags = size ? FUSE_BPF_OUT_ARGVAR : 0, .out_args[0].size = size ? size : sizeof(fgio->fgo), .out_args[0].value = size ? value : &fgio->fgo, }; - return 0; } -int fuse_getxattr_backing(struct fuse_args *fa, +int fuse_getxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size) { ssize_t ret = vfs_getxattr(get_fuse_dentry(dentry)->backing_path.dentry, fa->in_args[1].value, value, size); - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) fa->out_args[0].size = ret; else ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret; @@ -653,13 +659,13 @@ int fuse_getxattr_backing(struct fuse_args *fa, return 0; } -void *fuse_getxattr_finalize(struct fuse_args *fa, +void *fuse_getxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size) { struct fuse_getxattr_out *fgo; - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) return ERR_PTR(fa->out_args[0].size); fgo = fa->out_args[0].value; @@ -668,7 +674,7 @@ void *fuse_getxattr_finalize(struct fuse_args *fa, } -int fuse_listxattr_initialize(struct fuse_args *fa, +int fuse_listxattr_initialize(struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, char *list, size_t size) { @@ -676,17 +682,17 @@ int fuse_listxattr_initialize(struct fuse_args *fa, .fgi.size = size, }; - *fa = (struct fuse_args){ + *fa = (struct fuse_bpf_args){ .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_LISTXATTR, .in_numargs = 1, .out_numargs = 1, .in_args[0] = - (struct fuse_in_arg){ + (struct fuse_bpf_in_arg){ .size = sizeof(fgio->fgi), .value = &fgio->fgi, }, - .out_argvar = size ? true : false, + .flags = size ? FUSE_BPF_OUT_ARGVAR : 0, .out_args[0].size = size ? size : sizeof(fgio->fgo), .out_args[0].value = size ? (void *)list : &fgio->fgo, }; @@ -694,7 +700,7 @@ int fuse_listxattr_initialize(struct fuse_args *fa, return 0; } -int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_listxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size) { ssize_t ret = @@ -704,7 +710,7 @@ int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, if (ret < 0) return ret; - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) fa->out_args[0].size = ret; else ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret; @@ -712,7 +718,7 @@ int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, return ret; } -void *fuse_listxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_listxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size) { struct fuse_getxattr_out *fgo; @@ -720,14 +726,14 @@ void *fuse_listxattr_finalize(struct fuse_args *fa, struct dentry *dentry, if (fa->error_in) return NULL; - if (fa->out_argvar) + if (fa->flags & FUSE_BPF_OUT_ARGVAR) return ERR_PTR(fa->out_args[0].size); fgo = fa->out_args[0].value; return ERR_PTR(fgo->size); } -int fuse_setxattr_initialize(struct fuse_args *fa, +int fuse_setxattr_initialize(struct fuse_bpf_args *fa, struct fuse_setxattr_in *fsxi, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) @@ -737,19 +743,19 @@ int fuse_setxattr_initialize(struct fuse_args *fa, .flags = flags, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_SETXATTR, .in_numargs = 3, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fsxi), .value = fsxi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = strlen(name) + 1, .value = name, }, - .in_args[2] = (struct fuse_in_arg) { + .in_args[2] = (struct fuse_bpf_in_arg) { .size = size, .value = value, }, @@ -758,7 +764,7 @@ int fuse_setxattr_initialize(struct fuse_args *fa, return 0; } -int fuse_setxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_setxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { @@ -766,22 +772,22 @@ int fuse_setxattr_backing(struct fuse_args *fa, struct dentry *dentry, value, size, flags); } -void *fuse_setxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_setxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { return NULL; } -int fuse_removexattr_initialize(struct fuse_args *fa, +int fuse_removexattr_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct dentry *dentry, const char *name) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dentry->d_inode)->nodeid, .opcode = FUSE_REMOVEXATTR, .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = strlen(name) + 1, .value = name, }, @@ -790,7 +796,7 @@ int fuse_removexattr_initialize(struct fuse_args *fa, return 0; } -int fuse_removexattr_backing(struct fuse_args *fa, +int fuse_removexattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name) { struct path *backing_path = @@ -800,63 +806,72 @@ int fuse_removexattr_backing(struct fuse_args *fa, return vfs_removexattr(backing_path->dentry, name); } -void *fuse_removexattr_finalize(struct fuse_args *fa, +void *fuse_removexattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name) { return NULL; } +static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req) +{ + if (refcount_dec_and_test(&aio_req->ref)) + kmem_cache_free(fuse_bpf_aio_request_cachep, aio_req); +} + static void fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req *aio_req) { struct kiocb *iocb = &aio_req->iocb; - struct kiocb *iocb_fuse = aio_req->iocb_fuse; + struct kiocb *iocb_orig = aio_req->iocb_orig; if (iocb->ki_flags & IOCB_WRITE) { __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, SB_FREEZE_WRITE); file_end_write(iocb->ki_filp); - fuse_copyattr(iocb_fuse->ki_filp, iocb->ki_filp); + fuse_copyattr(iocb_orig->ki_filp, iocb->ki_filp); } - - iocb_fuse->ki_pos = iocb->ki_pos; - kfree(aio_req); + iocb_orig->ki_pos = iocb->ki_pos; + fuse_bpf_aio_put(aio_req); } static void fuse_bpf_aio_rw_complete(struct kiocb *iocb, long res, long res2) { struct fuse_bpf_aio_req *aio_req = container_of(iocb, struct fuse_bpf_aio_req, iocb); - struct kiocb *iocb_fuse = aio_req->iocb_fuse; + struct kiocb *iocb_orig = aio_req->iocb_orig; fuse_bpf_aio_cleanup_handler(aio_req); - iocb_fuse->ki_complete(iocb_fuse, res, res2); + iocb_orig->ki_complete(iocb_orig, res, res2); } int fuse_file_read_iter_initialize( - struct fuse_args *fa, struct fuse_read_in *fri, + struct fuse_bpf_args *fa, struct fuse_file_read_iter_io *fri, struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; - *fri = (struct fuse_read_in) { + fri->fri = (struct fuse_read_in) { .fh = ff->fh, .offset = iocb->ki_pos, .size = to->count, }; + fri->frio = (struct fuse_read_iter_out) { + .ret = fri->fri.size, + }; + /* TODO we can't assume 'to' is a kvec */ /* TODO we also can't assume the vector has only one component */ - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_READ, .nodeid = ff->nodeid, .in_numargs = 1, - .in_args[0].size = sizeof(*fri), - .in_args[0].value = fri, + .in_args[0].size = sizeof(fri->fri), + .in_args[0].value = &fri->fri, .out_numargs = 1, - .out_args[0].size = fri->size, - .out_args[0].value = to->kvec->iov_base, + .out_args[0].size = sizeof(fri->frio), + .out_args[0].value = &fri->frio, /* * TODO Design this properly. * Possible approach: do not pass buf to bpf @@ -869,9 +884,10 @@ int fuse_file_read_iter_initialize( return 0; } -int fuse_file_read_iter_backing(struct fuse_args *fa, +int fuse_file_read_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to) { + struct fuse_read_iter_out *frio = fa->out_args[0].value; struct file *file = iocb->ki_filp; struct fuse_file *ff = file->private_data; ssize_t ret; @@ -892,19 +908,21 @@ int fuse_file_read_iter_backing(struct fuse_args *fa, struct fuse_bpf_aio_req *aio_req; ret = -ENOMEM; - aio_req = kzalloc(sizeof(struct fuse_bpf_aio_req), GFP_KERNEL); + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); if (!aio_req) goto out; - aio_req->iocb_fuse = iocb; + + aio_req->iocb_orig = iocb; kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); ret = vfs_iocb_iter_read(ff->backing_file, &aio_req->iocb, to); + fuse_bpf_aio_put(aio_req); if (ret != -EIOCBQUEUED) fuse_bpf_aio_cleanup_handler(aio_req); } - if (ret >= 0) - fa->out_args[0].size = ret; + frio->ret = ret; /* TODO Need to point value at the buffer for post-modification */ @@ -914,14 +932,16 @@ out: return ret; } -void *fuse_file_read_iter_finalize(struct fuse_args *fa, +void *fuse_file_read_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to) { - return ERR_PTR(fa->out_args[0].size); + struct fuse_read_iter_out *frio = fa->out_args[0].value; + + return ERR_PTR(frio->ret); } int fuse_file_write_iter_initialize( - struct fuse_args *fa, struct fuse_file_write_iter_io *fwio, + struct fuse_bpf_args *fa, struct fuse_file_write_iter_io *fwio, struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; @@ -934,7 +954,7 @@ int fuse_file_write_iter_initialize( }; /* TODO we can't assume 'from' is a kvec */ - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_WRITE, .nodeid = ff->nodeid, .in_numargs = 2, @@ -950,7 +970,7 @@ int fuse_file_write_iter_initialize( return 0; } -int fuse_file_write_iter_backing(struct fuse_args *fa, +int fuse_file_write_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; @@ -980,17 +1000,18 @@ int fuse_file_write_iter_backing(struct fuse_args *fa, struct fuse_bpf_aio_req *aio_req; ret = -ENOMEM; - /* TODO get this from a cache? */ - aio_req = kzalloc(sizeof(struct fuse_bpf_aio_req), GFP_KERNEL); + aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL); if (!aio_req) goto out; file_start_write(ff->backing_file); __sb_writers_release(file_inode(ff->backing_file)->i_sb, SB_FREEZE_WRITE); - aio_req->iocb_fuse = iocb; + aio_req->iocb_orig = iocb; kiocb_clone(&aio_req->iocb, iocb, ff->backing_file); aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete; + refcount_set(&aio_req->ref, 2); ret = vfs_iocb_iter_write(ff->backing_file, &aio_req->iocb, from); + fuse_bpf_aio_put(aio_req); if (ret != -EIOCBQUEUED) fuse_bpf_aio_cleanup_handler(aio_req); } @@ -1003,7 +1024,7 @@ out: return 0; } -void *fuse_file_write_iter_finalize(struct fuse_args *fa, +void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from) { struct fuse_write_iter_out *fwio = fa->out_args[0].value; @@ -1049,7 +1070,7 @@ ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma) return ret; } -int fuse_file_fallocate_initialize(struct fuse_args *fa, +int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa, struct fuse_fallocate_in *ffi, struct file *file, int mode, loff_t offset, loff_t length) { @@ -1062,7 +1083,7 @@ int fuse_file_fallocate_initialize(struct fuse_args *fa, .mode = mode }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_FALLOCATE, .nodeid = ff->nodeid, .in_numargs = 1, @@ -1073,7 +1094,7 @@ int fuse_file_fallocate_initialize(struct fuse_args *fa, return 0; } -int fuse_file_fallocate_backing(struct fuse_args *fa, +int fuse_file_fallocate_backing(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length) { const struct fuse_fallocate_in *ffi = fa->in_args[0].value; @@ -1083,7 +1104,7 @@ int fuse_file_fallocate_backing(struct fuse_args *fa, ffi->length); } -void *fuse_file_fallocate_finalize(struct fuse_args *fa, +void *fuse_file_fallocate_finalize(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length) { return NULL; @@ -1093,24 +1114,24 @@ void *fuse_file_fallocate_finalize(struct fuse_args *fa, * Directory operations after here * ******************************************************************************/ -int fuse_lookup_initialize(struct fuse_args *fa, struct fuse_lookup_io *fli, +int fuse_lookup_initialize(struct fuse_bpf_args *fa, struct fuse_lookup_io *fli, struct inode *dir, struct dentry *entry, unsigned int flags) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(dir)->nodeid, .opcode = FUSE_LOOKUP, .in_numargs = 1, .out_numargs = 2, - .out_argvar = 1, - .in_args[0] = (struct fuse_in_arg) { + .flags = FUSE_BPF_OUT_ARGVAR, + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(fli->feo), .value = &fli->feo, }, - .out_args[1] = (struct fuse_arg) { + .out_args[1] = (struct fuse_bpf_arg) { .size = sizeof(fli->feb.out), .value = &fli->feb.out, }, @@ -1119,7 +1140,7 @@ int fuse_lookup_initialize(struct fuse_args *fa, struct fuse_lookup_io *fli, return 0; } -int fuse_lookup_backing(struct fuse_args *fa, struct inode *dir, +int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { struct fuse_dentry *fuse_entry = get_fuse_dentry(entry); @@ -1146,7 +1167,7 @@ int fuse_lookup_backing(struct fuse_args *fa, struct inode *dir, return 0; } -struct dentry *fuse_lookup_finalize(struct fuse_args *fa, struct inode *dir, +struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { struct fuse_dentry *fd; @@ -1249,7 +1270,7 @@ struct dentry *fuse_lookup_finalize(struct fuse_args *fa, struct inode *dir, return d_splice_alias(inode, entry); } -int fuse_revalidate_backing(struct fuse_args *fa, struct inode *dir, +int fuse_revalidate_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry); @@ -1267,13 +1288,13 @@ int fuse_revalidate_backing(struct fuse_args *fa, struct inode *dir, return 1; } -void *fuse_revalidate_finalize(struct fuse_args *fa, struct inode *dir, +void *fuse_revalidate_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags) { return 0; } -int fuse_canonical_path_initialize(struct fuse_args *fa, +int fuse_canonical_path_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *fdi, const struct path *path, struct path *canonical_path) @@ -1282,14 +1303,14 @@ int fuse_canonical_path_initialize(struct fuse_args *fa, return 0; } -int fuse_canonical_path_backing(struct fuse_args *fa, const struct path *path, +int fuse_canonical_path_backing(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path) { get_fuse_backing_path(path->dentry, canonical_path); return 0; } -void *fuse_canonical_path_finalize(struct fuse_args *fa, +void *fuse_canonical_path_finalize(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path) { @@ -1297,7 +1318,7 @@ void *fuse_canonical_path_finalize(struct fuse_args *fa, } int fuse_mknod_initialize( - struct fuse_args *fa, struct fuse_mknod_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mknod_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { *fmi = (struct fuse_mknod_in) { @@ -1305,15 +1326,15 @@ int fuse_mknod_initialize( .rdev = new_encode_dev(rdev), .umask = current_umask(), }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_MKNOD, .in_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fmi), .value = fmi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1323,7 +1344,7 @@ int fuse_mknod_initialize( } int fuse_mknod_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { int err = 0; @@ -1367,29 +1388,29 @@ out: } void *fuse_mknod_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev) { return NULL; } int fuse_mkdir_initialize( - struct fuse_args *fa, struct fuse_mkdir_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mkdir_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode) { *fmi = (struct fuse_mkdir_in) { .mode = mode, .umask = current_umask(), }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_MKDIR, .in_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fmi), .value = fmi, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1399,7 +1420,7 @@ int fuse_mkdir_initialize( } int fuse_mkdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode) { int err = 0; @@ -1445,21 +1466,21 @@ out: } void *fuse_mkdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode) { return NULL; } int fuse_rmdir_initialize( - struct fuse_args *fa, struct fuse_dummy_io *dummy, + struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy, struct inode *dir, struct dentry *entry) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_RMDIR, .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1469,7 +1490,7 @@ int fuse_rmdir_initialize( } int fuse_rmdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { int err = 0; @@ -1498,7 +1519,7 @@ int fuse_rmdir_backing( } void *fuse_rmdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { return NULL; @@ -1561,7 +1582,7 @@ static int fuse_rename_backing_common( if (target_inode) fsstack_copy_attr_all(target_inode, get_fuse_inode(target_inode)->backing_inode); - fsstack_copy_attr_all(newdir, d_inode(new_backing_dir_dentry)); + fsstack_copy_attr_all(d_inode(oldent), d_inode(old_backing_dentry)); unlock: unlock_rename(old_backing_dir_dentry, new_backing_dir_dentry); put_parents: @@ -1574,7 +1595,7 @@ put_old_path: return err; } -int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, +int fuse_rename2_initialize(struct fuse_bpf_args *fa, struct fuse_rename2_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags) @@ -1583,19 +1604,19 @@ int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, .newdir = get_node_id(newdir), .flags = flags, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(olddir), .opcode = FUSE_RENAME2, .in_numargs = 3, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fri), .value = fri, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = oldent->d_name.len + 1, .value = oldent->d_name.name, }, - .in_args[2] = (struct fuse_in_arg) { + .in_args[2] = (struct fuse_bpf_in_arg) { .size = newent->d_name.len + 1, .value = newent->d_name.name, }, @@ -1604,7 +1625,7 @@ int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, return 0; } -int fuse_rename2_backing(struct fuse_args *fa, +int fuse_rename2_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags) @@ -1615,7 +1636,7 @@ int fuse_rename2_backing(struct fuse_args *fa, return fuse_rename_backing_common(olddir, oldent, newdir, newent, fri->flags); } -void *fuse_rename2_finalize(struct fuse_args *fa, +void *fuse_rename2_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags) @@ -1623,26 +1644,26 @@ void *fuse_rename2_finalize(struct fuse_args *fa, return NULL; } -int fuse_rename_initialize(struct fuse_args *fa, struct fuse_rename_in *fri, +int fuse_rename_initialize(struct fuse_bpf_args *fa, struct fuse_rename_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { *fri = (struct fuse_rename_in) { .newdir = get_node_id(newdir), }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(olddir), .opcode = FUSE_RENAME, .in_numargs = 3, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(*fri), .value = fri, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = oldent->d_name.len + 1, .value = oldent->d_name.name, }, - .in_args[2] = (struct fuse_in_arg) { + .in_args[2] = (struct fuse_bpf_in_arg) { .size = newent->d_name.len + 1, .value = newent->d_name.name, }, @@ -1651,7 +1672,7 @@ int fuse_rename_initialize(struct fuse_args *fa, struct fuse_rename_in *fri, return 0; } -int fuse_rename_backing(struct fuse_args *fa, +int fuse_rename_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { @@ -1659,7 +1680,7 @@ int fuse_rename_backing(struct fuse_args *fa, return fuse_rename_backing_common(olddir, oldent, newdir, newent, 0); } -void *fuse_rename_finalize(struct fuse_args *fa, +void *fuse_rename_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { @@ -1667,14 +1688,14 @@ void *fuse_rename_finalize(struct fuse_args *fa, } int fuse_unlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *dummy, + struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy, struct inode *dir, struct dentry *entry) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_UNLINK, .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, @@ -1684,7 +1705,7 @@ int fuse_unlink_initialize( } int fuse_unlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { int err = 0; @@ -1713,13 +1734,13 @@ int fuse_unlink_backing( } void *fuse_unlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry) { return NULL; } -int fuse_link_initialize(struct fuse_args *fa, struct fuse_link_in *fli, +int fuse_link_initialize(struct fuse_bpf_args *fa, struct fuse_link_in *fli, struct dentry *entry, struct inode *dir, struct dentry *newent) { @@ -1739,7 +1760,7 @@ int fuse_link_initialize(struct fuse_args *fa, struct fuse_link_in *fli, return 0; } -int fuse_link_backing(struct fuse_args *fa, struct dentry *entry, +int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent) { int err = 0; @@ -1793,13 +1814,13 @@ err_dst_path: return err; } -void *fuse_link_finalize(struct fuse_args *fa, struct dentry *entry, +void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent) { return NULL; } -int fuse_getattr_initialize(struct fuse_args *fa, struct fuse_getattr_io *fgio, +int fuse_getattr_initialize(struct fuse_bpf_args *fa, struct fuse_getattr_io *fgio, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1810,16 +1831,16 @@ int fuse_getattr_initialize(struct fuse_args *fa, struct fuse_getattr_io *fgio, fgio->fao = (struct fuse_attr_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(entry->d_inode), .opcode = FUSE_GETATTR, .in_numargs = 1, .out_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(fgio->fgi), .value = &fgio->fgi, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(fgio->fao), .value = &fgio->fao, }, @@ -1864,7 +1885,7 @@ static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode, attr->blksize = 1 << blkbits; } -int fuse_getattr_backing(struct fuse_args *fa, +int fuse_getattr_backing(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1887,7 +1908,7 @@ int fuse_getattr_backing(struct fuse_args *fa, return err; } -void *fuse_getattr_finalize(struct fuse_args *fa, +void *fuse_getattr_finalize(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags) { @@ -1942,7 +1963,7 @@ static void fattr_to_iattr(struct fuse_conn *fc, } } -int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsio, +int fuse_setattr_initialize(struct fuse_bpf_args *fa, struct fuse_setattr_io *fsio, struct dentry *dentry, struct iattr *attr, struct file *file) { struct fuse_conn *fc = get_fuse_conn(dentry->d_inode); @@ -1950,7 +1971,7 @@ int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsio, *fsio = (struct fuse_setattr_io) {0}; iattr_to_fattr(fc, attr, &fsio->fsi, true); - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_SETATTR, .nodeid = get_node_id(dentry->d_inode), .in_numargs = 1, @@ -1964,7 +1985,7 @@ int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsio, return 0; } -int fuse_setattr_backing(struct fuse_args *fa, +int fuse_setattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file) { struct fuse_conn *fc = get_fuse_conn(dentry->d_inode); @@ -1991,18 +2012,18 @@ int fuse_setattr_backing(struct fuse_args *fa, return res; } -void *fuse_setattr_finalize(struct fuse_args *fa, +void *fuse_setattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file) { return NULL; } int fuse_statfs_initialize( - struct fuse_args *fa, struct fuse_statfs_out *fso, + struct fuse_bpf_args *fa, struct fuse_statfs_out *fso, struct dentry *dentry, struct kstatfs *buf) { *fso = (struct fuse_statfs_out) {0}; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(d_inode(dentry)), .opcode = FUSE_STATFS, .out_numargs = 1, @@ -2015,7 +2036,7 @@ int fuse_statfs_initialize( } int fuse_statfs_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf) { int err = 0; @@ -2037,7 +2058,7 @@ int fuse_statfs_backing( } void *fuse_statfs_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf) { struct fuse_statfs_out *fso = fa->out_args[0].value; @@ -2047,7 +2068,7 @@ void *fuse_statfs_finalize( return NULL; } -int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused, +int fuse_get_link_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out) { @@ -2063,11 +2084,11 @@ int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused, * We ought to only make that buffer if it's been requested, so leaving * this unimplemented for the moment */ - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_READLINK, .nodeid = get_node_id(inode), .in_numargs = 1, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = dentry->d_name.len + 1, .value = dentry->d_name.name, }, @@ -2082,7 +2103,7 @@ int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *unused, return 0; } -int fuse_get_link_backing(struct fuse_args *fa, +int fuse_get_link_backing(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out) { @@ -2109,7 +2130,7 @@ int fuse_get_link_backing(struct fuse_args *fa, return 0; } -void *fuse_get_link_finalize(struct fuse_args *fa, +void *fuse_get_link_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out) { @@ -2117,18 +2138,18 @@ void *fuse_get_link_finalize(struct fuse_args *fa, } int fuse_symlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *unused, + struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct inode *dir, struct dentry *entry, const char *link, int len) { - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = get_node_id(dir), .opcode = FUSE_SYMLINK, .in_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = entry->d_name.len + 1, .value = entry->d_name.name, }, - .in_args[1] = (struct fuse_in_arg) { + .in_args[1] = (struct fuse_bpf_in_arg) { .size = len, .value = link, }, @@ -2138,7 +2159,7 @@ int fuse_symlink_initialize( } int fuse_symlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len) { int err = 0; @@ -2177,15 +2198,15 @@ out: } void *fuse_symlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len) { return NULL; } -int fuse_readdir_initialize(struct fuse_args *fa, struct fuse_read_io *frio, +int fuse_readdir_initialize(struct fuse_bpf_args *fa, struct fuse_read_io *frio, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force) + bool *force_again, bool *allow_force, bool is_continued) { struct fuse_file *ff = file->private_data; u8 *page = (u8 *)__get_free_page(GFP_KERNEL); @@ -2193,21 +2214,21 @@ int fuse_readdir_initialize(struct fuse_args *fa, struct fuse_read_io *frio, if (!page) return -ENOMEM; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .nodeid = ff->nodeid, .opcode = FUSE_READDIR, .in_numargs = 1, - .out_argvar = true, + .flags = FUSE_BPF_OUT_ARGVAR, .out_numargs = 2, - .in_args[0] = (struct fuse_in_arg) { + .in_args[0] = (struct fuse_bpf_in_arg) { .size = sizeof(frio->fri), .value = &frio->fri, }, - .out_args[0] = (struct fuse_arg) { + .out_args[0] = (struct fuse_bpf_arg) { .size = sizeof(frio->fro), .value = &frio->fro, }, - .out_args[1] = (struct fuse_arg) { + .out_args[1] = (struct fuse_bpf_arg) { .size = PAGE_SIZE, .value = page, }, @@ -2255,9 +2276,35 @@ static int filldir(struct dir_context *ctx, const char *name, int namelen, return 0; } -int fuse_readdir_backing(struct fuse_args *fa, +static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx) +{ + while (nbytes >= FUSE_NAME_OFFSET) { + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + size_t reclen = FUSE_DIRENT_SIZE(dirent); + + if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) + return -EIO; + if (reclen > nbytes) + break; + if (memchr(dirent->name, '/', dirent->namelen) != NULL) + return -EIO; + + ctx->pos = dirent->off; + if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino, + dirent->type)) + break; + + buf += reclen; + nbytes -= reclen; + } + + return 0; +} + + +int fuse_readdir_backing(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force) + bool *force_again, bool *allow_force, bool is_continued) { struct fuse_file *ff = file->private_data; struct file *backing_dir = ff->backing_file; @@ -2274,6 +2321,9 @@ int fuse_readdir_backing(struct fuse_args *fa, if (!ec.addr) return -ENOMEM; + if (!is_continued) + backing_dir->f_pos = file->f_pos; + err = iterate_dir(backing_dir, &ec.ctx); if (ec.offset == 0) *allow_force = false; @@ -2284,34 +2334,35 @@ int fuse_readdir_backing(struct fuse_args *fa, return err; } -void *fuse_readdir_finalize(struct fuse_args *fa, +void *fuse_readdir_finalize(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force) + bool *force_again, bool *allow_force, bool is_continued) { - int err = 0; + struct fuse_read_out *fro = fa->out_args[0].value; struct fuse_file *ff = file->private_data; struct file *backing_dir = ff->backing_file; - struct fuse_read_out *fro = fa->out_args[0].value; + int err = 0; - err = fuse_parse_dirfile(fa->out_args[1].value, - fa->out_args[1].size, file, ctx); + err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx); *force_again = !!fro->again; if (*force_again && !*allow_force) err = -EINVAL; + + ctx->pos = fro->offset; backing_dir->f_pos = fro->offset; free_page((unsigned long) fa->out_args[1].value); return ERR_PTR(err); } -int fuse_access_initialize(struct fuse_args *fa, struct fuse_access_in *fai, +int fuse_access_initialize(struct fuse_bpf_args *fa, struct fuse_access_in *fai, struct inode *inode, int mask) { *fai = (struct fuse_access_in) { .mask = mask, }; - *fa = (struct fuse_args) { + *fa = (struct fuse_bpf_args) { .opcode = FUSE_ACCESS, .nodeid = get_node_id(inode), .in_numargs = 1, @@ -2322,7 +2373,7 @@ int fuse_access_initialize(struct fuse_args *fa, struct fuse_access_in *fai, return 0; } -int fuse_access_backing(struct fuse_args *fa, struct inode *inode, int mask) +int fuse_access_backing(struct fuse_bpf_args *fa, struct inode *inode, int mask) { struct fuse_inode *fi = get_fuse_inode(inode); const struct fuse_access_in *fai = fa->in_args[0].value; @@ -2331,7 +2382,74 @@ int fuse_access_backing(struct fuse_args *fa, struct inode *inode, int mask) fi->backing_inode, fai->mask); } -void *fuse_access_finalize(struct fuse_args *fa, struct inode *inode, int mask) +void *fuse_access_finalize(struct fuse_bpf_args *fa, struct inode *inode, int mask) { return NULL; } + +int __init fuse_bpf_init(void) +{ + fuse_bpf_aio_request_cachep = kmem_cache_create("fuse_bpf_aio_req", + sizeof(struct fuse_bpf_aio_req), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!fuse_bpf_aio_request_cachep) + return -ENOMEM; + + return 0; +} + +void __exit fuse_bpf_cleanup(void) +{ + kmem_cache_destroy(fuse_bpf_aio_request_cachep); +} + +ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *bpf_args) +{ + int i; + ssize_t res; + struct fuse_args args = { + .nodeid = bpf_args->nodeid, + .opcode = bpf_args->opcode, + .error_in = bpf_args->error_in, + .in_numargs = bpf_args->in_numargs, + .out_numargs = bpf_args->out_numargs, + .force = !!(bpf_args->flags & FUSE_BPF_FORCE), + .out_argvar = !!(bpf_args->flags & FUSE_BPF_OUT_ARGVAR), + }; + + for (i = 0; i < args.in_numargs; ++i) + args.in_args[i] = (struct fuse_in_arg) { + .size = bpf_args->in_args[i].size, + .value = bpf_args->in_args[i].value, + }; + for (i = 0; i < args.out_numargs; ++i) + args.out_args[i] = (struct fuse_arg) { + .size = bpf_args->out_args[i].size, + .value = bpf_args->out_args[i].value, + }; + + res = fuse_simple_request(fm, &args); + + *bpf_args = (struct fuse_bpf_args) { + .nodeid = args.nodeid, + .opcode = args.opcode, + .error_in = args.error_in, + .in_numargs = args.in_numargs, + .out_numargs = args.out_numargs, + }; + if (args.force) + bpf_args->flags |= FUSE_BPF_FORCE; + if (args.out_argvar) + bpf_args->flags |= FUSE_BPF_OUT_ARGVAR; + for (i = 0; i < args.in_numargs; ++i) + bpf_args->in_args[i] = (struct fuse_bpf_in_arg) { + .size = args.in_args[i].size, + .value = args.in_args[i].value, + }; + for (i = 0; i < args.out_numargs; ++i) + bpf_args->out_args[i] = (struct fuse_bpf_arg) { + .size = args.out_args[i].size, + .value = args.out_args[i].value, + }; + return res; +} diff --git a/fs/fuse/control.c b/fs/fuse/control.c index cc7e94d73c6cca0883166b12d2a0f90972ebf6a9..a4b16bc59f7a31903ac6abbdf8a8b9cfce14ba9a 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -395,7 +395,7 @@ int __init fuse_ctl_init(void) return register_filesystem(&fuse_ctl_fs_type); } -void __exit fuse_ctl_cleanup(void) +void fuse_ctl_cleanup(void) { unregister_filesystem(&fuse_ctl_fs_type); } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index b8ef63c4fc27c24f5b6927df662830965a51aaa5..c13be2fa891f5fa894b783bb4616fb5bf4fd9439 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -208,10 +208,13 @@ static unsigned int fuse_req_hash(u64 unique) /** * A new request is available, wake fiq->waitq */ -static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq) +static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock) { - wake_up(&fiq->waitq); + if (sync) + wake_up_sync(&fiq->waitq); + else + wake_up(&fiq->waitq); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); spin_unlock(&fiq->lock); } @@ -224,14 +227,14 @@ const struct fuse_iqueue_ops fuse_dev_fiq_ops = { EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops); static void queue_request_and_unlock(struct fuse_iqueue *fiq, - struct fuse_req *req) + struct fuse_req *req, bool sync) __releases(fiq->lock) { req->in.h.len = sizeof(struct fuse_in_header) + fuse_len_args(req->args->in_numargs, (struct fuse_arg *) req->args->in_args); list_add_tail(&req->list, &fiq->pending); - fiq->ops->wake_pending_and_unlock(fiq); + fiq->ops->wake_pending_and_unlock(fiq, sync); } void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, @@ -251,7 +254,7 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, if (fiq->connected) { fiq->forget_list_tail->next = forget; fiq->forget_list_tail = forget; - fiq->ops->wake_forget_and_unlock(fiq); + fiq->ops->wake_forget_and_unlock(fiq, false); } else { kfree(forget); spin_unlock(&fiq->lock); @@ -271,7 +274,7 @@ static void flush_bg_queue(struct fuse_conn *fc) fc->active_background++; spin_lock(&fiq->lock); req->in.h.unique = fuse_get_unique(fiq); - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, false); } } @@ -364,7 +367,7 @@ static int queue_interrupt(struct fuse_req *req) spin_unlock(&fiq->lock); return 0; } - fiq->ops->wake_interrupt_and_unlock(fiq); + fiq->ops->wake_interrupt_and_unlock(fiq, false); } else { spin_unlock(&fiq->lock); } @@ -431,7 +434,7 @@ static void __fuse_request_send(struct fuse_req *req) /* acquire extra reference, since request is still needed after fuse_request_end() */ __fuse_get_request(req); - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, true); request_wait_answer(req); /* Pairs with smp_wmb() in fuse_request_end() */ @@ -607,7 +610,7 @@ static int fuse_simple_notify_reply(struct fuse_mount *fm, spin_lock(&fiq->lock); if (fiq->connected) { - queue_request_and_unlock(fiq, req); + queue_request_and_unlock(fiq, req, false); } else { err = -ENODEV; spin_unlock(&fiq->lock); @@ -690,11 +693,7 @@ static void fuse_copy_finish(struct fuse_copy_state *cs) flush_dcache_page(cs->pg); set_page_dirty_lock(cs->pg); } - /* - * The page could be GUP page(see iov_iter_get_pages in - * fuse_copy_fill) so use put_user_page to release it. - */ - put_user_page(cs->pg); + put_page(cs->pg); } cs->pg = NULL; } @@ -796,7 +795,8 @@ static int fuse_check_page(struct page *page) 1 << PG_active | 1 << PG_workingset | 1 << PG_reclaim | - 1 << PG_waiters))) { + 1 << PG_waiters | + LRU_GEN_MASK | LRU_REFS_MASK))) { dump_page(page, "fuse: trying to steal weird page"); return 1; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a8070719881c96b7ff0233f17a2b6cdfacc8c5a3..d492898b33f52454fbaed380200c45ce29572ab0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1643,7 +1643,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct fuse_err_ret fer; - fer = fuse_bpf_backing(inode, struct fuse_read_in, + fer = fuse_bpf_backing(inode, struct fuse_file_read_iter_io, fuse_file_read_iter_initialize, fuse_file_read_iter_backing, fuse_file_read_iter_finalize, diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 87f2f2e5c5a89710d6093f2bf8fbeb9d2f35d056..00e0c53242e760dca2a31b01fd3334d8e091c4d5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -308,12 +308,48 @@ struct fuse_file { bool flock:1; }; +/** One input argument of a request */ +struct fuse_in_arg { + unsigned size; + const void *value; +}; + +/** One output argument of a request */ +struct fuse_arg { + unsigned size; + void *value; +}; + /** FUSE page descriptor */ struct fuse_page_desc { unsigned int length; unsigned int offset; }; +struct fuse_args { + uint64_t nodeid; + uint32_t opcode; + uint32_t error_in; + unsigned short in_numargs; + unsigned short out_numargs; + int force:1; + int noreply:1; + int nocreds:1; + int in_pages:1; + int out_pages:1; + int user_pages:1; + int out_argvar:1; + int page_zeroing:1; + int page_replace:1; + int may_block:1; + struct fuse_in_arg in_args[FUSE_MAX_IN_ARGS]; + struct fuse_arg out_args[FUSE_MAX_OUT_ARGS]; + void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); + + /* Path used for completing d_canonical_path */ + struct path *canonical_path; +}; + struct fuse_args_pages { struct fuse_args args; struct page **pages; @@ -436,19 +472,19 @@ struct fuse_iqueue_ops { /** * Signal that a forget has been queued */ - void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** * Signal that an INTERRUPT request has been queued */ - void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** * Signal that a request has been queued */ - void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq) + void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock); /** @@ -987,10 +1023,6 @@ struct fuse_io_args { void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos, size_t count, int opcode); - -int fuse_parse_dirfile(char *buf, size_t nbytes, struct file *file, - struct dir_context *ctx); - /** * Send OPEN or OPENDIR request */ @@ -1059,7 +1091,7 @@ int fuse_dev_init(void); void fuse_dev_cleanup(void); int fuse_ctl_init(void); -void __exit fuse_ctl_cleanup(void); +void fuse_ctl_cleanup(void); /** * Simple request sending that does request allocation and freeing @@ -1320,11 +1352,11 @@ struct fuse_open_io { struct fuse_open_out foo; }; -int fuse_open_initialize(struct fuse_args *fa, struct fuse_open_io *foi, +int fuse_open_initialize(struct fuse_bpf_args *fa, struct fuse_open_io *foi, struct inode *inode, struct file *file, bool isdir); -int fuse_open_backing(struct fuse_args *fa, +int fuse_open_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir); -void *fuse_open_finalize(struct fuse_args *fa, +void *fuse_open_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file, bool isdir); struct fuse_create_open_io { @@ -1334,103 +1366,103 @@ struct fuse_create_open_io { }; int fuse_create_open_initialize( - struct fuse_args *fa, struct fuse_create_open_io *fcoi, + struct fuse_bpf_args *fa, struct fuse_create_open_io *fcoi, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); int fuse_create_open_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); void *fuse_create_open_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, struct file *file, unsigned int flags, umode_t mode); int fuse_mknod_initialize( - struct fuse_args *fa, struct fuse_mknod_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mknod_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); int fuse_mknod_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); void *fuse_mknod_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev); int fuse_mkdir_initialize( - struct fuse_args *fa, struct fuse_mkdir_in *fmi, + struct fuse_bpf_args *fa, struct fuse_mkdir_in *fmi, struct inode *dir, struct dentry *entry, umode_t mode); int fuse_mkdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode); void *fuse_mkdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, umode_t mode); int fuse_rmdir_initialize( - struct fuse_args *fa, struct fuse_dummy_io *fmi, + struct fuse_bpf_args *fa, struct fuse_dummy_io *fmi, struct inode *dir, struct dentry *entry); int fuse_rmdir_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); void *fuse_rmdir_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); -int fuse_rename2_initialize(struct fuse_args *fa, struct fuse_rename2_in *fri, +int fuse_rename2_initialize(struct fuse_bpf_args *fa, struct fuse_rename2_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags); -int fuse_rename2_backing(struct fuse_args *fa, +int fuse_rename2_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags); -void *fuse_rename2_finalize(struct fuse_args *fa, +void *fuse_rename2_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent, unsigned int flags); -int fuse_rename_initialize(struct fuse_args *fa, struct fuse_rename_in *fri, +int fuse_rename_initialize(struct fuse_bpf_args *fa, struct fuse_rename_in *fri, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); -int fuse_rename_backing(struct fuse_args *fa, +int fuse_rename_backing(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); -void *fuse_rename_finalize(struct fuse_args *fa, +void *fuse_rename_finalize(struct fuse_bpf_args *fa, struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent); int fuse_unlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *fmi, + struct fuse_bpf_args *fa, struct fuse_dummy_io *fmi, struct inode *dir, struct dentry *entry); int fuse_unlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); void *fuse_unlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry); -int fuse_link_initialize(struct fuse_args *fa, struct fuse_link_in *fli, +int fuse_link_initialize(struct fuse_bpf_args *fa, struct fuse_link_in *fli, struct dentry *entry, struct inode *dir, struct dentry *newent); -int fuse_link_backing(struct fuse_args *fa, struct dentry *entry, +int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent); -void *fuse_link_finalize(struct fuse_args *fa, struct dentry *entry, +void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent); -int fuse_release_initialize(struct fuse_args *fa, struct fuse_release_in *fri, +int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file); -int fuse_releasedir_initialize(struct fuse_args *fa, +int fuse_releasedir_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, struct inode *inode, struct file *file); -int fuse_release_backing(struct fuse_args *fa, +int fuse_release_backing(struct fuse_bpf_args *fa, struct inode *inode, struct file *file); -void *fuse_release_finalize(struct fuse_args *fa, +void *fuse_release_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct file *file); -int fuse_flush_initialize(struct fuse_args *fa, struct fuse_flush_in *ffi, +int fuse_flush_initialize(struct fuse_bpf_args *fa, struct fuse_flush_in *ffi, struct file *file, fl_owner_t id); -int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id); -void *fuse_flush_finalize(struct fuse_args *fa, +int fuse_flush_backing(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id); +void *fuse_flush_finalize(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id); struct fuse_lseek_io { @@ -1438,37 +1470,37 @@ struct fuse_lseek_io { struct fuse_lseek_out flo; }; -int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *fli, +int fuse_lseek_initialize(struct fuse_bpf_args *fa, struct fuse_lseek_io *fli, struct file *file, loff_t offset, int whence); -int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, int whence); -void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset, int whence); +int fuse_lseek_backing(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence); +void *fuse_lseek_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence); struct fuse_copy_file_range_io { struct fuse_copy_file_range_in fci; struct fuse_write_out fwo; }; -int fuse_copy_file_range_initialize(struct fuse_args *fa, +int fuse_copy_file_range_initialize(struct fuse_bpf_args *fa, struct fuse_copy_file_range_io *fcf, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags); -int fuse_copy_file_range_backing(struct fuse_args *fa, +int fuse_copy_file_range_backing(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags); -void *fuse_copy_file_range_finalize(struct fuse_args *fa, +void *fuse_copy_file_range_finalize(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t len, unsigned int flags); -int fuse_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync); -int fuse_fsync_backing(struct fuse_args *fa, +int fuse_fsync_backing(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync); -void *fuse_fsync_finalize(struct fuse_args *fa, +void *fuse_fsync_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t start, loff_t end, int datasync); -int fuse_dir_fsync_initialize(struct fuse_args *fa, struct fuse_fsync_in *ffi, +int fuse_dir_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi, struct file *file, loff_t start, loff_t end, int datasync); struct fuse_getxattr_io { @@ -1477,51 +1509,59 @@ struct fuse_getxattr_io { }; int fuse_getxattr_initialize( - struct fuse_args *fa, struct fuse_getxattr_io *fgio, + struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, const char *name, void *value, size_t size); int fuse_getxattr_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size); void *fuse_getxattr_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, void *value, size_t size); -int fuse_listxattr_initialize(struct fuse_args *fa, +int fuse_listxattr_initialize(struct fuse_bpf_args *fa, struct fuse_getxattr_io *fgio, struct dentry *dentry, char *list, size_t size); -int fuse_listxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_listxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size); -void *fuse_listxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_listxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, char *list, size_t size); -int fuse_setxattr_initialize(struct fuse_args *fa, +int fuse_setxattr_initialize(struct fuse_bpf_args *fa, struct fuse_setxattr_in *fsxi, struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -int fuse_setxattr_backing(struct fuse_args *fa, struct dentry *dentry, +int fuse_setxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -void *fuse_setxattr_finalize(struct fuse_args *fa, struct dentry *dentry, +void *fuse_setxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -int fuse_removexattr_initialize(struct fuse_args *fa, +int fuse_removexattr_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct dentry *dentry, const char *name); -int fuse_removexattr_backing(struct fuse_args *fa, +int fuse_removexattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name); -void *fuse_removexattr_finalize(struct fuse_args *fa, +void *fuse_removexattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, const char *name); +struct fuse_read_iter_out { + uint64_t ret; +}; +struct fuse_file_read_iter_io { + struct fuse_read_in fri; + struct fuse_read_iter_out frio; +}; + int fuse_file_read_iter_initialize( - struct fuse_args *fa, struct fuse_read_in *fri, + struct fuse_bpf_args *fa, struct fuse_file_read_iter_io *fri, struct kiocb *iocb, struct iov_iter *to); -int fuse_file_read_iter_backing(struct fuse_args *fa, +int fuse_file_read_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to); -void *fuse_file_read_iter_finalize(struct fuse_args *fa, +void *fuse_file_read_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *to); struct fuse_write_iter_out { @@ -1534,21 +1574,21 @@ struct fuse_file_write_iter_io { }; int fuse_file_write_iter_initialize( - struct fuse_args *fa, struct fuse_file_write_iter_io *fwio, + struct fuse_bpf_args *fa, struct fuse_file_write_iter_io *fwio, struct kiocb *iocb, struct iov_iter *from); -int fuse_file_write_iter_backing(struct fuse_args *fa, +int fuse_file_write_iter_backing(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from); -void *fuse_file_write_iter_finalize(struct fuse_args *fa, +void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa, struct kiocb *iocb, struct iov_iter *from); ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma); -int fuse_file_fallocate_initialize(struct fuse_args *fa, +int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa, struct fuse_fallocate_in *ffi, struct file *file, int mode, loff_t offset, loff_t length); -int fuse_file_fallocate_backing(struct fuse_args *fa, +int fuse_file_fallocate_backing(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length); -void *fuse_file_fallocate_finalize(struct fuse_args *fa, +void *fuse_file_fallocate_finalize(struct fuse_bpf_args *fa, struct file *file, int mode, loff_t offset, loff_t length); struct fuse_lookup_io { @@ -1556,24 +1596,24 @@ struct fuse_lookup_io { struct fuse_entry_bpf feb; }; -int fuse_lookup_initialize(struct fuse_args *fa, struct fuse_lookup_io *feo, +int fuse_lookup_initialize(struct fuse_bpf_args *fa, struct fuse_lookup_io *feo, struct inode *dir, struct dentry *entry, unsigned int flags); -int fuse_lookup_backing(struct fuse_args *fa, struct inode *dir, +int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -struct dentry *fuse_lookup_finalize(struct fuse_args *fa, struct inode *dir, +struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -int fuse_revalidate_backing(struct fuse_args *fa, struct inode *dir, +int fuse_revalidate_backing(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -void *fuse_revalidate_finalize(struct fuse_args *fa, struct inode *dir, +void *fuse_revalidate_finalize(struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, unsigned int flags); -int fuse_canonical_path_initialize(struct fuse_args *fa, +int fuse_canonical_path_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *fdi, const struct path *path, struct path *canonical_path); -int fuse_canonical_path_backing(struct fuse_args *fa, const struct path *path, +int fuse_canonical_path_backing(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path); -void *fuse_canonical_path_finalize(struct fuse_args *fa, +void *fuse_canonical_path_finalize(struct fuse_bpf_args *fa, const struct path *path, struct path *canonical_path); @@ -1581,13 +1621,13 @@ struct fuse_getattr_io { struct fuse_getattr_in fgi; struct fuse_attr_out fao; }; -int fuse_getattr_initialize(struct fuse_args *fa, struct fuse_getattr_io *fgio, +int fuse_getattr_initialize(struct fuse_bpf_args *fa, struct fuse_getattr_io *fgio, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags); -int fuse_getattr_backing(struct fuse_args *fa, +int fuse_getattr_backing(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags); -void *fuse_getattr_finalize(struct fuse_args *fa, +void *fuse_getattr_finalize(struct fuse_bpf_args *fa, const struct dentry *entry, struct kstat *stat, u32 request_mask, unsigned int flags); @@ -1596,38 +1636,38 @@ struct fuse_setattr_io { struct fuse_attr_out fao; }; -int fuse_setattr_initialize(struct fuse_args *fa, struct fuse_setattr_io *fsi, +int fuse_setattr_initialize(struct fuse_bpf_args *fa, struct fuse_setattr_io *fsi, struct dentry *dentry, struct iattr *attr, struct file *file); -int fuse_setattr_backing(struct fuse_args *fa, +int fuse_setattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file); -void *fuse_setattr_finalize(struct fuse_args *fa, +void *fuse_setattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, struct iattr *attr, struct file *file); -int fuse_statfs_initialize(struct fuse_args *fa, struct fuse_statfs_out *fso, +int fuse_statfs_initialize(struct fuse_bpf_args *fa, struct fuse_statfs_out *fso, struct dentry *dentry, struct kstatfs *buf); -int fuse_statfs_backing(struct fuse_args *fa, +int fuse_statfs_backing(struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf); -void *fuse_statfs_finalize(struct fuse_args *fa, +void *fuse_statfs_finalize(struct fuse_bpf_args *fa, struct dentry *dentry, struct kstatfs *buf); -int fuse_get_link_initialize(struct fuse_args *fa, struct fuse_dummy_io *dummy, +int fuse_get_link_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out); -int fuse_get_link_backing(struct fuse_args *fa, +int fuse_get_link_backing(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out); -void *fuse_get_link_finalize(struct fuse_args *fa, +void *fuse_get_link_finalize(struct fuse_bpf_args *fa, struct inode *inode, struct dentry *dentry, struct delayed_call *callback, const char **out); int fuse_symlink_initialize( - struct fuse_args *fa, struct fuse_dummy_io *unused, + struct fuse_bpf_args *fa, struct fuse_dummy_io *unused, struct inode *dir, struct dentry *entry, const char *link, int len); int fuse_symlink_backing( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len); void *fuse_symlink_finalize( - struct fuse_args *fa, + struct fuse_bpf_args *fa, struct inode *dir, struct dentry *entry, const char *link, int len); struct fuse_read_io { @@ -1635,20 +1675,20 @@ struct fuse_read_io { struct fuse_read_out fro; }; -int fuse_readdir_initialize(struct fuse_args *fa, struct fuse_read_io *frio, +int fuse_readdir_initialize(struct fuse_bpf_args *fa, struct fuse_read_io *frio, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force); -int fuse_readdir_backing(struct fuse_args *fa, + bool *force_again, bool *allow_force, bool is_continued); +int fuse_readdir_backing(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force); -void *fuse_readdir_finalize(struct fuse_args *fa, + bool *force_again, bool *allow_force, bool is_continued); +void *fuse_readdir_finalize(struct fuse_bpf_args *fa, struct file *file, struct dir_context *ctx, - bool *force_again, bool *allow_force); + bool *force_again, bool *allow_force, bool is_continued); -int fuse_access_initialize(struct fuse_args *fa, struct fuse_access_in *fai, +int fuse_access_initialize(struct fuse_bpf_args *fa, struct fuse_access_in *fai, struct inode *inode, int mask); -int fuse_access_backing(struct fuse_args *fa, struct inode *inode, int mask); -void *fuse_access_finalize(struct fuse_args *fa, struct inode *inode, int mask); +int fuse_access_backing(struct fuse_bpf_args *fa, struct inode *inode, int mask); +void *fuse_access_finalize(struct fuse_bpf_args *fa, struct inode *inode, int mask); /* * FUSE caches dentries and attributes with separate timeout. The @@ -1784,16 +1824,21 @@ struct fuse_err_ret { bool ret; }; +int __init fuse_bpf_init(void); +void __exit fuse_bpf_cleanup(void); + +ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *args); + /* * expression statement to wrap the backing filter logic * struct inode *inode: inode with bpf and backing inode * typedef io: (typically complex) type whose components fuse_args can point to. * An instance of this type is created locally and passed to initialize - * void initialize(struct fuse_args *fa, io *in_out, args...): function that sets + * void initialize(struct fuse_bpf_args *fa, io *in_out, args...): function that sets * up fa and io based on args - * int backing(struct fuse_args *fa, args...): function that actually performs + * int backing(struct fuse_bpf_args *fa, args...): function that actually performs * the backing io operation - * void *finalize(struct fuse_args *, args...): function that performs any final + * void *finalize(struct fuse_bpf_args *, args...): function that performs any final * work needed to commit the backing io */ #define fuse_bpf_backing(inode, io, initialize, backing, finalize, \ @@ -1804,7 +1849,7 @@ struct fuse_err_ret { struct fuse_inode *fuse_inode = get_fuse_inode(inode); \ struct fuse_mount *fm = get_fuse_mount(inode); \ io feo = {0}; \ - struct fuse_args fa = {0}, fa_backup = {0}; \ + struct fuse_bpf_args fa = {0}, fa_backup = {0}; \ bool locked; \ ssize_t res; \ void *err; \ @@ -1828,7 +1873,7 @@ struct fuse_err_ret { fa_backup = fa; \ fa.opcode |= FUSE_PREFILTER; \ for (i = 0; i < fa.in_numargs; ++i) \ - fa.out_args[i] = (struct fuse_arg) { \ + fa.out_args[i] = (struct fuse_bpf_arg) { \ .size = fa.in_args[i].size, \ .value = (void *)fa.in_args[i].value, \ }; \ @@ -1847,7 +1892,7 @@ struct fuse_err_ret { \ if (ext_flags & FUSE_BPF_USER_FILTER) { \ locked = fuse_lock_inode(inode); \ - res = fuse_simple_request(fm, &fa); \ + res = fuse_bpf_simple_request(fm, &fa); \ fuse_unlock_inode(inode, locked); \ if (res < 0) { \ fer = (struct fuse_err_ret) { \ @@ -1863,12 +1908,12 @@ struct fuse_err_ret { \ fa.opcode &= ~FUSE_PREFILTER; \ for (i = 0; i < fa.in_numargs; ++i) \ - fa.in_args[i] = (struct fuse_in_arg) { \ + fa.in_args[i] = (struct fuse_bpf_in_arg) { \ .size = fa.out_args[i].size, \ .value = fa.out_args[i].value, \ }; \ - for (i = 0; i < fa.out_numargs; ++i) \ - fa.out_args[i] = (struct fuse_arg) { \ + for (i = 0; i < fa_backup.out_numargs; ++i) \ + fa.out_args[i] = (struct fuse_bpf_arg) { \ .size = fa_backup.out_args[i].size, \ .value = fa_backup.out_args[i].value, \ }; \ @@ -1886,7 +1931,7 @@ struct fuse_err_ret { fa.opcode |= FUSE_POSTFILTER; \ for (i = 0; i < fa.out_numargs; ++i) \ fa.in_args[fa.in_numargs++] = \ - (struct fuse_in_arg) { \ + (struct fuse_bpf_in_arg) { \ .size = fa.out_args[i].size, \ .value = fa.out_args[i].value, \ }; \ @@ -1905,7 +1950,7 @@ struct fuse_err_ret { fa.out_args[1].size = fa_backup.out_args[1].size; \ fa.out_numargs = fa_backup.out_numargs; \ locked = fuse_lock_inode(inode); \ - res = fuse_simple_request(fm, &fa); \ + res = fuse_bpf_simple_request(fm, &fa); \ fuse_unlock_inode(inode, locked); \ if (res < 0) { \ fer.result = ERR_PTR(res); \ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ee18e23215935a879c84ad3e22e8c3cfd575a0eb..fa692f9e4ef344d723971a9c00a277c160e7837e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -27,6 +27,7 @@ MODULE_AUTHOR("Miklos Szeredi "); MODULE_DESCRIPTION("Filesystem in Userspace"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *fuse_inode_cachep; struct list_head fuse_conn_list; @@ -1902,11 +1903,21 @@ static int __init fuse_init(void) if (res) goto err_sysfs_cleanup; +#ifdef CONFIG_FUSE_BPF + res = fuse_bpf_init(); + if (res) + goto err_ctl_cleanup; +#endif + sanitize_global_limit(&max_user_bgreq); sanitize_global_limit(&max_user_congthresh); return 0; +#ifdef CONFIG_FUSE_BPF + err_ctl_cleanup: + fuse_ctl_cleanup(); +#endif err_sysfs_cleanup: fuse_sysfs_cleanup(); err_dev_cleanup: @@ -1924,6 +1935,9 @@ static void __exit fuse_exit(void) fuse_ctl_cleanup(); fuse_sysfs_cleanup(); fuse_fs_cleanup(); +#ifdef CONFIG_FUSE_BPF + fuse_bpf_cleanup(); +#endif fuse_dev_cleanup(); } diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index 4a8a3d5425b3ed2b94cba1ded86b276822ab8850..e802426d42a9d48c68bb7777a4e3910c4d445e42 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -121,7 +121,7 @@ static bool fuse_emit(struct file *file, struct dir_context *ctx, dirent->type); } -int fuse_parse_dirfile(char *buf, size_t nbytes, struct file *file, +static int parse_dirfile(char *buf, size_t nbytes, struct file *file, struct dir_context *ctx) { while (nbytes >= FUSE_NAME_OFFSET) { @@ -360,7 +360,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) res = parse_dirplusfile(page_address(page), res, file, ctx, attr_version); } else { - res = fuse_parse_dirfile(page_address(page), res, file, + res = parse_dirfile(page_address(page), res, file, ctx); } } @@ -574,13 +574,17 @@ int fuse_readdir(struct file *file, struct dir_context *ctx) #ifdef CONFIG_FUSE_BPF struct fuse_err_ret fer; bool force_again, allow_force; + bool is_continued = false; + again: fer = fuse_bpf_backing(inode, struct fuse_read_io, fuse_readdir_initialize, fuse_readdir_backing, fuse_readdir_finalize, - file, ctx, &force_again, &allow_force); - if (force_again && !IS_ERR(fer.result)) + file, ctx, &force_again, &allow_force, is_continued); + if (force_again && !IS_ERR(fer.result)) { + is_continued = true; goto again; + } if (fer.ret) return PTR_ERR(fer.result); diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index b9cfb1165ff422c36e22e9c1c2e5e9595c65c02f..90a574ba92cf99aeff71c0e8e791cd805eb2aaba 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -971,7 +971,7 @@ static struct virtio_driver virtio_fs_driver = { #endif }; -static void virtio_fs_wake_forget_and_unlock(struct fuse_iqueue *fiq) +static void virtio_fs_wake_forget_and_unlock(struct fuse_iqueue *fiq, bool sync) __releases(fiq->lock) { struct fuse_forget_link *link; @@ -1006,7 +1006,8 @@ __releases(fiq->lock) kfree(link); } -static void virtio_fs_wake_interrupt_and_unlock(struct fuse_iqueue *fiq) +static void virtio_fs_wake_interrupt_and_unlock(struct fuse_iqueue *fiq, + bool sync) __releases(fiq->lock) { /* @@ -1221,7 +1222,8 @@ out: return ret; } -static void virtio_fs_wake_pending_and_unlock(struct fuse_iqueue *fiq) +static void virtio_fs_wake_pending_and_unlock(struct fuse_iqueue *fiq, + bool sync) __releases(fiq->lock) { unsigned int queue_id = VQ_REQUEST; /* TODO multiqueue */ diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c7393ee9cf68369f588a52f5bea3e62290b6921c..81925fd2985fd5e24bfdeef163f3f9ab04ee067c 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -260,6 +260,7 @@ static void __exit exit_gfs2_fs(void) MODULE_DESCRIPTION("Global File System"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_gfs2_fs); module_exit(exit_gfs2_fs); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index eb775e93de97c336b14d84b17f59a78c2d91f4c4..5e8eef9990e326428d9c5e44ee19a5233029425f 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1389,8 +1389,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp) start = r.start >> bs_shift; end = start + (r.len >> bs_shift); - minlen = max_t(u64, r.minlen, sdp->sd_sb.sb_bsize); - minlen = max_t(u64, minlen, + minlen = max_t(u64, r.minlen, q->limits.discard_granularity) >> bs_shift; if (end <= start || minlen > sdp->sd_max_rg_data) diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 12d9bae393631c5f41938c1a8b0cf1653fe92376..6432d65a08727a5214b0207d6579c9ef92d50c81 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -29,6 +29,7 @@ static struct kmem_cache *hfs_inode_cachep; MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static int hfs_sync_fs(struct super_block *sb, int wait) { diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 807119ae5adf7370622c033dcd714608eea318f1..2b0031c6daeab0e305d46784ea92b8f295fe47a0 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -617,6 +617,7 @@ out: MODULE_AUTHOR("Brad Boyer"); MODULE_DESCRIPTION("Extended Macintosh Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *hfsplus_inode_cachep; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index a7dbfc89202270e205c5fa1ee13a83c4d0e6824e..d7598d70f329c708ab269616b59d61d7fdf83328 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -791,3 +791,4 @@ static void __exit exit_hpfs_fs(void) module_init(init_hpfs_fs) module_exit(exit_hpfs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h index 84db0382765db96afb6a8560ba0c03421d1909ea..2227913674a4ff0547243b3add36f51cc9f4c983 100644 --- a/fs/incfs/data_mgmt.h +++ b/fs/incfs/data_mgmt.h @@ -131,8 +131,14 @@ struct mount_info { struct path mi_backing_dir_path; struct dentry *mi_index_dir; + /* For stacking mounts, if true, this indicates if the index dir needs + * to be freed for this SB otherwise it was created by lower level SB */ + bool mi_index_free; struct dentry *mi_incomplete_dir; + /* For stacking mounts, if true, this indicates if the incomplete dir + * needs to be freed for this SB. Similar to mi_index_free */ + bool mi_incomplete_free; const struct cred *mi_owner; diff --git a/fs/incfs/main.c b/fs/incfs/main.c index 23347acac8bf7da179bfd0735b2c6d6fd640b4ac..213faa5e911761d7d917458b0906f75692e856ed 100644 --- a/fs/incfs/main.c +++ b/fs/incfs/main.c @@ -44,5 +44,6 @@ module_init(init_incfs_module); module_exit(cleanup_incfs_module); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_AUTHOR("Eugene Zemtsov "); MODULE_DESCRIPTION("Incremental File System"); diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 8d21f6decaee0878a60c68df7d6c386f3648507e..e97b843a4da53c13bc9bb3f2acc243fb7c34d680 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -437,7 +437,8 @@ static int incfs_init_dentry(struct dentry *dentry, struct path *path) } static struct dentry *open_or_create_special_dir(struct dentry *backing_dir, - const char *name) + const char *name, + bool *created) { struct dentry *index_dentry; struct inode *backing_inode = d_inode(backing_dir); @@ -450,6 +451,7 @@ static struct dentry *open_or_create_special_dir(struct dentry *backing_dir, return index_dentry; } else if (d_really_is_positive(index_dentry)) { /* Index already exists. */ + *created = false; return index_dentry; } @@ -469,6 +471,7 @@ static struct dentry *open_or_create_special_dir(struct dentry *backing_dir, return ERR_PTR(-EINVAL); } + *created = true; return index_dentry; } @@ -1747,6 +1750,7 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, struct super_block *src_fs_sb = NULL; struct inode *root_inode = NULL; struct super_block *sb = sget(type, NULL, set_anon_super, flags, NULL); + bool dir_created = false; int error = 0; if (IS_ERR(sb)) @@ -1763,17 +1767,23 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, BUILD_BUG_ON(PAGE_SIZE != INCFS_DATA_FILE_BLOCK_SIZE); + if (!dev_name) { + pr_err("incfs: Backing dir is not set, filesystem can't be mounted.\n"); + error = -ENOENT; + goto err_deactivate; + } + error = parse_options(&options, (char *)data); if (error != 0) { pr_err("incfs: Options parsing error. %d\n", error); - goto err; + goto err_deactivate; } sb->s_bdi->ra_pages = options.readahead_pages; if (!dev_name) { pr_err("incfs: Backing dir is not set, filesystem can't be mounted.\n"); error = -ENOENT; - goto err; + goto err_free_opts; } error = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, @@ -1782,57 +1792,66 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, !d_really_is_positive(backing_dir_path.dentry)) { pr_err("incfs: Error accessing: %s.\n", dev_name); - goto err; + goto err_free_opts; } src_fs_sb = backing_dir_path.dentry->d_sb; sb->s_maxbytes = src_fs_sb->s_maxbytes; + sb->s_stack_depth = src_fs_sb->s_stack_depth + 1; - mi = incfs_alloc_mount_info(sb, &options, &backing_dir_path); + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + error = -EINVAL; + goto err_put_path; + } + mi = incfs_alloc_mount_info(sb, &options, &backing_dir_path); if (IS_ERR_OR_NULL(mi)) { error = PTR_ERR(mi); pr_err("incfs: Error allocating mount info. %d\n", error); - mi = NULL; - goto err; + goto err_put_path; } + sb->s_fs_info = mi; + mi->mi_backing_dir_path = backing_dir_path; index_dir = open_or_create_special_dir(backing_dir_path.dentry, - INCFS_INDEX_NAME); + INCFS_INDEX_NAME, &dir_created); if (IS_ERR_OR_NULL(index_dir)) { error = PTR_ERR(index_dir); pr_err("incfs: Can't find or create .index dir in %s\n", dev_name); /* No need to null index_dir since we don't put it */ - goto err; + goto err_put_path; } + mi->mi_index_dir = index_dir; + mi->mi_index_free = dir_created; incomplete_dir = open_or_create_special_dir(backing_dir_path.dentry, - INCFS_INCOMPLETE_NAME); + INCFS_INCOMPLETE_NAME, + &dir_created); if (IS_ERR_OR_NULL(incomplete_dir)) { error = PTR_ERR(incomplete_dir); pr_err("incfs: Can't find or create .incomplete dir in %s\n", dev_name); /* No need to null incomplete_dir since we don't put it */ - goto err; + goto err_put_path; } mi->mi_incomplete_dir = incomplete_dir; + mi->mi_incomplete_free = dir_created; - sb->s_fs_info = mi; root_inode = fetch_regular_inode(sb, backing_dir_path.dentry); if (IS_ERR(root_inode)) { error = PTR_ERR(root_inode); - goto err; + goto err_put_path; } sb->s_root = d_make_root(root_inode); if (!sb->s_root) { error = -ENOMEM; - goto err; + goto err_put_path; } error = incfs_init_dentry(sb->s_root, &backing_dir_path); if (error) - goto err; + goto err_put_path; mi->mi_backing_dir_path = backing_dir_path; sb->s_flags |= SB_ACTIVE; @@ -1840,12 +1859,14 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, pr_debug("incfs: mount\n"); free_options(&options); return dget(sb->s_root); -err: - sb->s_fs_info = NULL; + +err_put_path: path_put(&backing_dir_path); - incfs_free_mount_info(mi); - deactivate_locked_super(sb); +err_free_opts: free_options(&options); +err_deactivate: + deactivate_locked_super(sb); + pr_err("incfs: mount failed %d\n", error); return ERR_PTR(error); } @@ -1880,14 +1901,26 @@ out: void incfs_kill_sb(struct super_block *sb) { struct mount_info *mi = sb->s_fs_info; - struct inode *dinode = d_inode(mi->mi_backing_dir_path.dentry); + struct inode *dinode = NULL; pr_debug("incfs: unmount\n"); - vfs_rmdir(dinode, mi->mi_index_dir); - vfs_rmdir(dinode, mi->mi_incomplete_dir); + if (mi) { + if (mi->mi_backing_dir_path.dentry) + dinode = d_inode(mi->mi_backing_dir_path.dentry); + + if (dinode) { + if (mi->mi_index_dir && mi->mi_index_free) + vfs_rmdir(dinode, mi->mi_index_dir); + + if (mi->mi_incomplete_dir && mi->mi_incomplete_free) + vfs_rmdir(dinode, mi->mi_incomplete_dir); + } + + incfs_free_mount_info(mi); + sb->s_fs_info = NULL; + } kill_anon_super(sb); - incfs_free_mount_info(mi); } static int show_options(struct seq_file *m, struct dentry *root) diff --git a/fs/inode.c b/fs/inode.c index 638d5d5bf42df341b0b021ea6abfb47f45992a84..9246236bcdcafba83c4413d81cbcafca0c39dd57 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -307,7 +307,7 @@ void drop_nlink(struct inode *inode) if (!inode->i_nlink) atomic_long_inc(&inode->i_sb->s_remove_count); } -EXPORT_SYMBOL(drop_nlink); +EXPORT_SYMBOL_NS(drop_nlink, ANDROID_GKI_VFS_EXPORT_ONLY); /** * clear_nlink - directly zero an inode's link count @@ -346,7 +346,7 @@ void set_nlink(struct inode *inode, unsigned int nlink) inode->__i_nlink = nlink; } } -EXPORT_SYMBOL(set_nlink); +EXPORT_SYMBOL_NS(set_nlink, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inc_nlink - directly increment an inode's link count @@ -399,7 +399,7 @@ void inode_init_once(struct inode *inode) __address_space_init_once(&inode->i_data); i_size_ordered_init(inode); } -EXPORT_SYMBOL(inode_init_once); +EXPORT_SYMBOL_NS(inode_init_once, ANDROID_GKI_VFS_EXPORT_ONLY); static void init_once(void *foo) { @@ -423,7 +423,7 @@ void ihold(struct inode *inode) { WARN_ON(atomic_inc_return(&inode->i_count) < 2); } -EXPORT_SYMBOL(ihold); +EXPORT_SYMBOL_NS(ihold, ANDROID_GKI_VFS_EXPORT_ONLY); static void inode_lru_list_add(struct inode *inode) { @@ -503,7 +503,7 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval) spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); } -EXPORT_SYMBOL(__insert_inode_hash); +EXPORT_SYMBOL_NS(__insert_inode_hash, ANDROID_GKI_VFS_EXPORT_ONLY); /** * __remove_inode_hash - remove an inode from the hash @@ -519,7 +519,7 @@ void __remove_inode_hash(struct inode *inode) spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); } -EXPORT_SYMBOL(__remove_inode_hash); +EXPORT_SYMBOL_NS(__remove_inode_hash, ANDROID_GKI_VFS_EXPORT_ONLY); void clear_inode(struct inode *inode) { @@ -539,7 +539,7 @@ void clear_inode(struct inode *inode) /* don't need i_lock here, no concurrent mods to i_state */ inode->i_state = I_FREEING | I_CLEAR; } -EXPORT_SYMBOL(clear_inode); +EXPORT_SYMBOL_NS(clear_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Free the inode passed in, removing it from the lists it is still connected @@ -1001,7 +1001,7 @@ void unlock_new_inode(struct inode *inode) wake_up_bit(&inode->i_state, __I_NEW); spin_unlock(&inode->i_lock); } -EXPORT_SYMBOL(unlock_new_inode); +EXPORT_SYMBOL_NS(unlock_new_inode, ANDROID_GKI_VFS_EXPORT_ONLY); void discard_new_inode(struct inode *inode) { @@ -1158,7 +1158,7 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, } return inode; } -EXPORT_SYMBOL(iget5_locked); +EXPORT_SYMBOL_NS(iget5_locked, ANDROID_GKI_VFS_EXPORT_ONLY); /** * iget_locked - obtain an inode from a mounted file system @@ -1290,7 +1290,7 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved) return res; } -EXPORT_SYMBOL(iunique); +EXPORT_SYMBOL_NS(iunique, ANDROID_GKI_VFS_EXPORT_ONLY); struct inode *igrab(struct inode *inode) { @@ -1373,7 +1373,7 @@ again: } return inode; } -EXPORT_SYMBOL(ilookup5); +EXPORT_SYMBOL_NS(ilookup5, ANDROID_GKI_VFS_EXPORT_ONLY); /** * ilookup - search for an inode in the inode cache @@ -1853,7 +1853,7 @@ void touch_atime(const struct path *path) skip_update: sb_end_write(inode->i_sb); } -EXPORT_SYMBOL(touch_atime); +EXPORT_SYMBOL_NS(touch_atime, ANDROID_GKI_VFS_EXPORT_ONLY); /* * The logic we want is @@ -1949,7 +1949,7 @@ int file_remove_privs(struct file *file) return error; } -EXPORT_SYMBOL(file_remove_privs); +EXPORT_SYMBOL_NS(file_remove_privs, ANDROID_GKI_VFS_EXPORT_ONLY); /** * file_update_time - update mtime and ctime time @@ -2130,7 +2130,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) " inode %s:%lu\n", mode, inode->i_sb->s_id, inode->i_ino); } -EXPORT_SYMBOL(init_special_inode); +EXPORT_SYMBOL_NS(init_special_inode, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inode_init_owner - Init uid,gid,mode for new inode according to posix standards @@ -2156,7 +2156,7 @@ void inode_init_owner(struct inode *inode, const struct inode *dir, inode->i_gid = current_fsgid(); inode->i_mode = mode; } -EXPORT_SYMBOL(inode_init_owner); +EXPORT_SYMBOL_NS(inode_init_owner, ANDROID_GKI_VFS_EXPORT_ONLY); /** * inode_owner_or_capable - check current task permissions to inode @@ -2210,7 +2210,7 @@ void inode_dio_wait(struct inode *inode) if (atomic_read(&inode->i_dio_count)) __inode_dio_wait(inode); } -EXPORT_SYMBOL(inode_dio_wait); +EXPORT_SYMBOL_NS(inode_dio_wait, ANDROID_GKI_VFS_EXPORT_ONLY); /* * inode_set_flags - atomically set some inode flags @@ -2234,7 +2234,7 @@ void inode_set_flags(struct inode *inode, unsigned int flags, WARN_ON_ONCE(flags & ~mask); set_mask_bits(&inode->i_flags, mask, flags); } -EXPORT_SYMBOL(inode_set_flags); +EXPORT_SYMBOL_NS(inode_set_flags, ANDROID_GKI_VFS_EXPORT_ONLY); void inode_nohighmem(struct inode *inode) { @@ -2271,7 +2271,7 @@ struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode) WARN(1, "invalid file time granularity: %u", gran); return t; } -EXPORT_SYMBOL(timestamp_truncate); +EXPORT_SYMBOL_NS(timestamp_truncate, ANDROID_GKI_VFS_EXPORT_ONLY); /** * current_time - Return FS time diff --git a/fs/io_uring.c b/fs/io_uring.c index 5959b0359524cd56ae641b44e2aea18d42332ce6..fd188b97215119183b7fac8268f0f644b3cf5095 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -3220,15 +3220,13 @@ static ssize_t loop_rw_iter(int rw, struct io_kiocb *req, struct iov_iter *iter) ret = nr; break; } - ret += nr; if (!iov_iter_is_bvec(iter)) { iov_iter_advance(iter, nr); } else { - req->rw.addr += nr; req->rw.len -= nr; - if (!req->rw.len) - break; + req->rw.addr += nr; } + ret += nr; if (nr != iovec.iov_len) break; } @@ -7350,7 +7348,6 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx, int nr, int offset) fput(fpl->fp[i]); } else { kfree_skb(skb); - free_uid(fpl->user); kfree(fpl); } diff --git a/fs/ioctl.c b/fs/ioctl.c index 4e6cc0a7d69c9f27e3b900b2dad72f7904cc90c4..32d8bd3f958b6cd50988f17ce602b064a00488c3 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -146,7 +146,7 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, return 1; return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; } -EXPORT_SYMBOL(fiemap_fill_next_extent); +EXPORT_SYMBOL_NS(fiemap_fill_next_extent, ANDROID_GKI_VFS_EXPORT_ONLY); /** * fiemap_prep - check validity of requested flags for fiemap @@ -191,7 +191,7 @@ int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo, ret = filemap_write_and_wait(inode->i_mapping); return ret; } -EXPORT_SYMBOL(fiemap_prep); +EXPORT_SYMBOL_NS(fiemap_prep, ANDROID_GKI_VFS_EXPORT_ONLY); static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) { diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index f62b5a501566841dc64b776e6b49d6fdad3d083a..ecbc8ef0da176c2f611afae1d73a58b4a7f8e11c 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1612,3 +1612,4 @@ static void __exit exit_iso9660_fs(void) module_init(init_iso9660_fs) module_exit(exit_iso9660_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile index 126b4da6c7de875be834cc96b63179a26ac0214c..b64f93331643ba4fd25be7e89ccfc71e0c0eacfa 100644 --- a/fs/jbd2/Makefile +++ b/fs/jbd2/Makefile @@ -3,6 +3,8 @@ # Makefile for the linux journaling routines. # +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + obj-$(CONFIG_JBD2) += jbd2.o jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index b748329bb0bab13b8145874d6a70f18e9537c581..099e4319851d8067cf27c0de2a8bb40b268fc2b2 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -3014,6 +3014,7 @@ static void __exit journal_exit(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(journal_init); module_exit(journal_exit); diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 837cd55fd4c5e534b0b0c802b1dc1669c9b7a5c2..b288c8ae1236b0f81f271e0fcfcaf5ee246b2933 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -415,15 +415,13 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); ret = -EIO; - goto out_sum_exit; + goto out_free; } jffs2_calc_trigger_levels(c); return 0; - out_sum_exit: - jffs2_sum_exit(c); out_free: kvfree(c->blocks); diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 7170de78cd2601d423fbfdea168ea5d87029a8b4..78858f6e95839cb03859fd36d67dfd85d7c6ba74 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -602,8 +602,8 @@ out_root: jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); kvfree(c->blocks); - jffs2_clear_xattr_subsystem(c); out_inohash: + jffs2_clear_xattr_subsystem(c); kfree(c->inocache_list); out_wbuf: jffs2_flash_cleanup(c); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 29671e33a1714c8ca5c1e272ac58821e00078ef1..b676056826beb69a05aca4ce7028720d2eeea5cf 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -136,7 +136,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) if (!s) { JFFS2_WARNING("Can't allocate memory for summary\n"); ret = -ENOMEM; - goto out_buf; + goto out; } } @@ -275,15 +275,13 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } ret = 0; out: - jffs2_sum_reset_collected(s); - kfree(s); - out_buf: if (buf_size) kfree(flashbuf); #ifndef __ECOS else mtd_unpoint(c->mtd, 0, c->mtd->size); #endif + kfree(s); return ret; } diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 81ca58c10b728cc6a7c4e132a80c503c0dde1df3..16dcc359fd35934e7135c0114dcbdfda38ca94bb 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -439,3 +439,4 @@ MODULE_DESCRIPTION("The Journalling Flash File System, v2"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for // the sake of this tag. It's Free Software. +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index e58ae29a223d755bf58f685ae248db2909097c46..aedad59f8a4589af32e0ee3002f33b44ba65e667 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -148,7 +148,6 @@ static const s8 budtab[256] = { * 0 - success * -ENOMEM - insufficient memory * -EIO - i/o error - * -EINVAL - wrong bmap data */ int dbMount(struct inode *ipbmap) { @@ -180,12 +179,6 @@ int dbMount(struct inode *ipbmap) bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree); bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage); bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag); - if (!bmp->db_numag) { - release_metapage(mp); - kfree(bmp); - return -EINVAL; - } - bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel); bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag); bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index b2dc4d1f9dcc559117e0a5bcdd38676e873d3e53..8a02b9bdea19bfe6adf2eeb8d8a735b4bd682325 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -37,6 +37,7 @@ MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *jfs_inode_cachep; diff --git a/fs/libfs.c b/fs/libfs.c index 1b4a215f7b749ef48392d605f3c737ef25ef3be6..40359a0b57e139ea1ebf7fe42001c1d48cad927b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -225,7 +225,7 @@ ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t { return -EISDIR; } -EXPORT_SYMBOL(generic_read_dir); +EXPORT_SYMBOL_NS(generic_read_dir, ANDROID_GKI_VFS_EXPORT_ONLY); const struct file_operations simple_dir_operations = { .open = dcache_dir_open, diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 34f546404aa11385388f140c7a7a22d345f5fc31..8a9d4a28290d1207076df03bd2681fb1f6cae57d 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -719,4 +719,5 @@ static void __exit exit_minix_fs(void) module_init(init_minix_fs) module_exit(exit_minix_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/mpage.c b/fs/mpage.c index 00ac5c329b59f5ccd9b25b43911eff4db87a8225..55d2bfa0629207dde7f992c4f301ffb98db131f5 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -428,7 +428,7 @@ void mpage_readahead(struct readahead_control *rac, get_block_t get_block) if (args.bio) mpage_bio_submit(REQ_OP_READ, REQ_RAHEAD, args.bio); } -EXPORT_SYMBOL(mpage_readahead); +EXPORT_SYMBOL_NS(mpage_readahead, ANDROID_GKI_VFS_EXPORT_ONLY); /* * This isn't called much at all @@ -446,7 +446,7 @@ int mpage_readpage(struct page *page, get_block_t get_block) mpage_bio_submit(REQ_OP_READ, 0, args.bio); return 0; } -EXPORT_SYMBOL(mpage_readpage); +EXPORT_SYMBOL_NS(mpage_readpage, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Writing is not so simple. diff --git a/fs/namei.c b/fs/namei.c index 1e6f5f6751a2bca88009fc655bf8d5962905a4c6..d7b609a6f6dc94459628c5eb8ce64726ddc34af3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2533,7 +2533,7 @@ int kern_path(const char *name, unsigned int flags, struct path *path) return filename_lookup(AT_FDCWD, getname_kernel(name), flags, path, NULL); } -EXPORT_SYMBOL(kern_path); +EXPORT_SYMBOL_NS(kern_path, ANDROID_GKI_VFS_EXPORT_ONLY); /** * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair @@ -2887,7 +2887,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, fsnotify_create(dir, dentry); return error; } -EXPORT_SYMBOL(vfs_create); +EXPORT_SYMBOL_NS(vfs_create, ANDROID_GKI_VFS_EXPORT_ONLY); int vfs_mkobj(struct dentry *dentry, umode_t mode, int (*f)(struct dentry *, umode_t, void *), @@ -3727,7 +3727,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) fsnotify_mkdir(dir, dentry); return error; } -EXPORT_SYMBOL(vfs_mkdir); +EXPORT_SYMBOL_NS(vfs_mkdir, ANDROID_GKI_VFS_EXPORT_ONLY); static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode) { @@ -3801,7 +3801,7 @@ out: d_delete_notify(dir, dentry); return error; } -EXPORT_SYMBOL(vfs_rmdir); +EXPORT_SYMBOL_NS(vfs_rmdir, ANDROID_GKI_VFS_EXPORT_ONLY); long do_rmdir(int dfd, struct filename *name) { @@ -3924,7 +3924,7 @@ out: return error; } -EXPORT_SYMBOL(vfs_unlink); +EXPORT_SYMBOL_NS(vfs_unlink, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Make sure that the actual truncation of the file will occur outside its @@ -4159,7 +4159,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de fsnotify_link(dir, inode, new_dentry); return error; } -EXPORT_SYMBOL(vfs_link); +EXPORT_SYMBOL_NS(vfs_link, ANDROID_GKI_VFS_EXPORT_ONLY); /* * Hardlinks are often used in delicate situations. We avoid @@ -4419,7 +4419,7 @@ out: return error; } -EXPORT_SYMBOL(vfs_rename); +EXPORT_SYMBOL_NS(vfs_rename, ANDROID_GKI_VFS_EXPORT_ONLY); static int do_renameat2(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags) diff --git a/fs/namespace.c b/fs/namespace.c index 046b084136c51a0a36972c326f63d65bae5d4e7d..6d1f11a6b2904af12db512cf1488463e0d37c677 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -415,7 +415,7 @@ int mnt_want_write_file(struct file *file) sb_end_write(file_inode(file)->i_sb); return ret; } -EXPORT_SYMBOL_GPL(mnt_want_write_file); +EXPORT_SYMBOL_NS_GPL(mnt_want_write_file, ANDROID_GKI_VFS_EXPORT_ONLY); /** * __mnt_drop_write - give up write access to a mount @@ -457,7 +457,7 @@ void mnt_drop_write_file(struct file *file) __mnt_drop_write_file(file); sb_end_write(file_inode(file)->i_sb); } -EXPORT_SYMBOL(mnt_drop_write_file); +EXPORT_SYMBOL_NS(mnt_drop_write_file, ANDROID_GKI_VFS_EXPORT_ONLY); static int mnt_make_readonly(struct mount *mnt) { diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a5209643ac36ce4c7d04c8a7be1e6ce4db79bd45..b44219ce60b869c5c6556ab6053ee5e47c12b170 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -353,11 +353,12 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp, struct cb_process_state *cps) { struct cb_devicenotifyargs *args = argp; - const struct pnfs_layoutdriver_type *ld = NULL; uint32_t i; __be32 res = 0; + struct nfs_client *clp = cps->clp; + struct nfs_server *server = NULL; - if (!cps->clp) { + if (!clp) { res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION); goto out; } @@ -365,15 +366,23 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp, for (i = 0; i < args->ndevs; i++) { struct cb_devicenotifyitem *dev = &args->devs[i]; - if (!ld || ld->id != dev->cbd_layout_type) { - pnfs_put_layoutdriver(ld); - ld = pnfs_find_layoutdriver(dev->cbd_layout_type); - if (!ld) - continue; + if (!server || + server->pnfs_curr_ld->id != dev->cbd_layout_type) { + rcu_read_lock(); + list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) + if (server->pnfs_curr_ld && + server->pnfs_curr_ld->id == dev->cbd_layout_type) { + rcu_read_unlock(); + goto found; + } + rcu_read_unlock(); + continue; } - nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id); + + found: + nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id); } - pnfs_put_layoutdriver(ld); + out: kfree(args->devs); return res; diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index ca8a4aa351dc948303dafa647a50f8893caa0465..1725079a05276275c4b9d90d0af3bdc591079bc4 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -272,6 +272,10 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, n = ntohl(*p++); if (n == 0) goto out; + if (n > ULONG_MAX / sizeof(*args->devs)) { + status = htonl(NFS4ERR_BADXDR); + goto out; + } args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); if (!args->devs) { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f27ecc2e490f23ee62aaa15493df9f1025d96614..f17ad75d0afd845c668ce1ee4fc0ffaf926afdcc 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -2337,6 +2337,7 @@ static void __exit exit_nfs_fs(void) /* Not quite true; I just maintain it */ MODULE_AUTHOR("Olaf Kirch "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_param(enable_ino64, bool, 0644); module_init(init_nfs_fs) diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 5e6453e9b30790bd8cb7160c14feecfc5bb71186..f6676af37d5dbb26baee5e776f5c7c05554227ab 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -948,7 +948,7 @@ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, error = decode_filename_inline(xdr, &entry->name, &entry->len); if (unlikely(error)) - return -EAGAIN; + return error; /* * The type (size and byte order) of nfscookie isn't defined in diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index b5a9379b14504cb15172886a6c97acd7e6bdc0d7..dff6b52d26a856ab698828d32f35f56ab7a7c939 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -1964,6 +1964,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, bool plus) { struct user_namespace *userns = rpc_userns(entry->server->client); + struct nfs_entry old = *entry; __be32 *p; int error; u64 new_cookie; @@ -1983,15 +1984,15 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, error = decode_fileid3(xdr, &entry->ino); if (unlikely(error)) - return -EAGAIN; + return error; error = decode_inline_filename3(xdr, &entry->name, &entry->len); if (unlikely(error)) - return -EAGAIN; + return error; error = decode_cookie3(xdr, &new_cookie); if (unlikely(error)) - return -EAGAIN; + return error; entry->d_type = DT_UNKNOWN; @@ -1999,7 +2000,7 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, entry->fattr->valid = 0; error = decode_post_op_attr(xdr, entry->fattr, userns); if (unlikely(error)) - return -EAGAIN; + return error; if (entry->fattr->valid & NFS_ATTR_FATTR_V3) entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); @@ -2014,8 +2015,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, return -EAGAIN; if (*p != xdr_zero) { error = decode_nfs_fh3(xdr, entry->fh); - if (unlikely(error)) - return -EAGAIN; + if (unlikely(error)) { + if (error == -E2BIG) + goto out_truncated; + return error; + } } else zero_nfs_fh3(entry->fh); } @@ -2024,6 +2028,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, entry->cookie = new_cookie; return 0; + +out_truncated: + dprintk("NFS: directory entry contains invalid file handle\n"); + *entry = old; + return -EAGAIN; } /* diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4d4ce7fd4e707da6e7b7be9af8ba0e198fcf48fb..a3612c184f887efbd8cc34ff07f761842dabf272 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8208,7 +8208,6 @@ nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata) case -NFS4ERR_DEADSESSION: nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); - return; } if (args->dir == NFS4_CDFC4_FORE_OR_BOTH && res->dir != NFS4_CDFS4_BOTH) { diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index d09bcfd7db89488eec9291c4e985e13953f079d3..b422e8a09d2510445331c20ea838a094a093e036 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -309,6 +309,7 @@ static void __exit exit_nfs_v4(void) } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_nfs_v4); module_exit(exit_nfs_v4); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index b3b9eff5d57275a4be84a9e394c67ea581fa90aa..5370e082aded53187e7779f0832b7a2901e9701e 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -92,17 +92,6 @@ find_pnfs_driver(u32 id) return local; } -const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id) -{ - return find_pnfs_driver(id); -} - -void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld) -{ - if (ld) - module_put(ld->owner); -} - void unset_pnfs_layoutdriver(struct nfs_server *nfss) { diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 11d9ed9addc06ef51d6f00704c0c4080f68b86a2..0212fe32e63aa285f871b80595ef7a339f36114d 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -236,8 +236,6 @@ struct pnfs_devicelist { extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); -extern const struct pnfs_layoutdriver_type *pnfs_find_layoutdriver(u32 id); -extern void pnfs_put_layoutdriver(const struct pnfs_layoutdriver_type *ld); /* nfs4proc.c */ extern size_t max_response_pages(struct nfs_server *server); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index cc926e69ee9baaebb898d801e4591207e5ec0a6a..bde4c362841f009cdb492d0b5787c14fbc100409 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -314,10 +314,7 @@ static void nfs_mapping_set_error(struct page *page, int error) struct address_space *mapping = page_file_mapping(page); SetPageError(page); - filemap_set_wb_err(mapping, error); - if (mapping->host) - errseq_set(&mapping->host->i_sb->s_wb_err, - error == -ENOSPC ? -ENOSPC : -EIO); + mapping_set_error(mapping, error); nfs_set_pageerror(mapping); } diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index acd0898e3866d88d7d44edb7845052207707ea9a..e5aad1c10ea32dd050a2fedb504f0b33d1fb5c94 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -641,7 +641,7 @@ nfsd_file_cache_init(void) if (!nfsd_filecache_wq) goto out; - nfsd_file_hashtbl = kvcalloc(NFSD_FILE_HASH_SIZE, + nfsd_file_hashtbl = kcalloc(NFSD_FILE_HASH_SIZE, sizeof(*nfsd_file_hashtbl), GFP_KERNEL); if (!nfsd_file_hashtbl) { pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n"); @@ -708,7 +708,7 @@ out_err: nfsd_file_slab = NULL; kmem_cache_destroy(nfsd_file_mark_slab); nfsd_file_mark_slab = NULL; - kvfree(nfsd_file_hashtbl); + kfree(nfsd_file_hashtbl); nfsd_file_hashtbl = NULL; destroy_workqueue(nfsd_filecache_wq); nfsd_filecache_wq = NULL; @@ -854,7 +854,7 @@ nfsd_file_cache_shutdown(void) fsnotify_wait_marks_destroyed(); kmem_cache_destroy(nfsd_file_mark_slab); nfsd_file_mark_slab = NULL; - kvfree(nfsd_file_hashtbl); + kfree(nfsd_file_hashtbl); nfsd_file_hashtbl = NULL; destroy_workqueue(nfsd_filecache_wq); nfsd_filecache_wq = NULL; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 84dd68091f42262ba2eafa95e01296b84666a3c0..d01d7929753efec03f8e942d0b61e320e12c85b9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4607,14 +4607,6 @@ nfsd_break_deleg_cb(struct file_lock *fl) return ret; } -/** - * nfsd_breaker_owns_lease - Check if lease conflict was resolved - * @fl: Lock state to check - * - * Return values: - * %true: Lease conflict was resolved - * %false: Lease conflict was not resolved. - */ static bool nfsd_breaker_owns_lease(struct file_lock *fl) { struct nfs4_delegation *dl = fl->fl_owner; @@ -4622,11 +4614,11 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl) struct nfs4_client *clp; if (!i_am_nfsd()) - return false; + return NULL; rqst = kthread_data(current); /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) - return false; + return NULL; clp = *(rqst->rq_lease_breaker); return dl->dl_stid.sc_client == clp; } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index dedec4771ecc2cd1d569184d19db07b356b7964d..2796ecfdfd5d0e5728d45a28c0d8b278168d3e8b 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1584,5 +1584,6 @@ static void __exit exit_nfsd(void) MODULE_AUTHOR("Olaf Kirch "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_nfsd) module_exit(exit_nfsd) diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index bbd01e8397f6e53905f4a8ba1515986a440044e0..9c9de2b66e64169b93c21a028d3a78c113dabe6f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -223,7 +223,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) unsigned long cnt = argp->len; unsigned int nvecs; - dprintk("nfsd: WRITE %s %u bytes at %d\n", + dprintk("nfsd: WRITE %s %d bytes at %d\n", SVCFH_fmt(&argp->fh), argp->len, argp->offset); diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index b8cc6a4b2e0ec6f272cb9f17d8c66f951d3bad53..0ff336b0b25f9a3b498516dab19863631e96f088 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -33,7 +33,7 @@ struct nfsd_readargs { struct nfsd_writeargs { svc_fh fh; __u32 offset; - __u32 len; + int len; struct kvec first; }; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 4abd928b0bc839db191e75d4dff935bee6ab7e29..ab1a5e8467f21c618bce27db3df3d513562bb52f 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -53,6 +53,7 @@ MODULE_AUTHOR("NTT Corp."); MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " "(NILFS)"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); static struct kmem_cache *nilfs_inode_cachep; struct kmem_cache *nilfs_transaction_cachep; diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 52ccd34b1e792370597b77f7d228c4d79bf96600..06c368ce3aa22ef90a01bfd2809c8077b5c41515 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -541,8 +541,8 @@ struct nls_table *load_nls_default(void) } EXPORT_SYMBOL(unregister_nls); -EXPORT_SYMBOL(unload_nls); -EXPORT_SYMBOL(load_nls); -EXPORT_SYMBOL(load_nls_default); +EXPORT_SYMBOL_NS(unload_nls, ANDROID_GKI_VFS_EXPORT_ONLY); +EXPORT_SYMBOL_NS(load_nls, ANDROID_GKI_VFS_EXPORT_ONLY); +EXPORT_SYMBOL_NS(load_nls_default, ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c index 162b3f160353c6ab076644079c861a2b4f1fd736..498b8a435d7e17be106e74b0e706fbac8ff2b233 100644 --- a/fs/nls/nls_euc-jp.c +++ b/fs/nls/nls_euc-jp.c @@ -578,3 +578,4 @@ module_init(init_nls_euc_jp) module_exit(exit_nls_euc_jp) MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c index a80a741a8676dc5a6ead28c9a584169050fc3c79..99ceec9085ecd5e72a75354d4d8d0b5ca2959213 100644 --- a/fs/nls/nls_koi8-ru.c +++ b/fs/nls/nls_koi8-ru.c @@ -80,3 +80,4 @@ module_init(init_nls_koi8_ru) module_exit(exit_nls_koi8_ru) MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index cf222c9225d6d5816b7928d26a1c0eecda00f0c4..ea18e4a2a691df3a3679dbc56dfbf31596be21b0 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1881,10 +1881,6 @@ int ntfs_read_inode_mount(struct inode *vi) } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); - if (!ni->attr_list_size) { - ntfs_error(sb, "Attr_list_size is zero"); - goto put_err_out; - } ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); if (!ni->attr_list) { ntfs_error(sb, "Not enough memory to allocate buffer " diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 0d7e948cb29c93193bf783d8cfb9accf86707263..56edd625cf4d2d9a88bc712f45731c6eed5dc10d 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3186,6 +3186,7 @@ MODULE_AUTHOR("Anton Altaparmakov "); MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc."); MODULE_VERSION(NTFS_VERSION); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); #ifdef DEBUG module_param(debug_msgs, bint, 0); MODULE_PARM_DESC(debug_msgs, "Enable debug messages."); diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 583820ec63e2d80173bbd3cc332d311a03456102..5b3a8681f87ef55d8f6a9acc6d7e672ef8b1ec62 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -615,6 +615,7 @@ static void __exit exit_dlmfs_fs(void) MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("OCFS2 DLM-Filesystem"); module_init(init_dlmfs_fs) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 477ad05a34ea2edf075fb8db225b60f608713b49..f48369c0211149ea6a65b97ad57089b491a7cdaa 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -71,6 +71,7 @@ static struct dentry *ocfs2_debugfs_root; MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_DESCRIPTION("OCFS2 cluster file system"); struct mount_options @@ -1110,6 +1111,17 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } + root = d_make_root(inode); + if (!root) { + status = -ENOMEM; + mlog_errno(status); + goto read_super_error; + } + + sb->s_root = root; + + ocfs2_complete_mount_recovery(osb); + osb->osb_dev_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj); if (!osb->osb_dev_kset) { @@ -1127,17 +1139,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } - root = d_make_root(inode); - if (!root) { - status = -ENOMEM; - mlog_errno(status); - goto read_super_error; - } - - sb->s_root = root; - - ocfs2_complete_mount_recovery(osb); - if (ocfs2_mount_local(osb)) snprintf(nodestr, sizeof(nodestr), "local"); else diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index ce93ccca86392badb8e7ecb490f0252e5342484d..27143a2cd962a9ba9dc8d407f335445ad29a9675 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -20,6 +20,7 @@ MODULE_AUTHOR("Bob Copeland "); MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) { diff --git a/fs/open.c b/fs/open.c index 78f32d483aefb4d180501005f3d1539be06b67f8..b9d55ca3763b652a227e6a9bc406b8352629f674 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1158,7 +1158,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode) } return file; } -EXPORT_SYMBOL(filp_open); +EXPORT_SYMBOL_NS(filp_open, ANDROID_GKI_VFS_EXPORT_ONLY); /* ANDROID: Allow drivers to open only block files from kernel mode */ struct file *filp_open_block(const char *filename, int flags, umode_t mode) @@ -1390,7 +1390,7 @@ int generic_file_open(struct inode * inode, struct file * filp) return 0; } -EXPORT_SYMBOL(generic_file_open); +EXPORT_SYMBOL_NS(generic_file_open, ANDROID_GKI_VFS_EXPORT_ONLY); /* * This is used by subsystems that don't want seekable diff --git a/fs/orangefs/orangefs-mod.c b/fs/orangefs/orangefs-mod.c index 74a3d6337ef432c0a7b06bd9db53562970df38df..a76a6ba8b355314ab404e2a70371508445910a46 100644 --- a/fs/orangefs/orangefs-mod.c +++ b/fs/orangefs/orangefs-mod.c @@ -36,6 +36,7 @@ int orangefs_dcache_timeout_msecs = 50; int orangefs_getattr_timeout_msecs = 50; MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_AUTHOR("ORANGEFS Development Team"); MODULE_DESCRIPTION("The Linux Kernel VFS interface to ORANGEFS"); MODULE_PARM_DESC(module_parm_debug_mask, "debugging level (see orangefs-debug.h for values)"); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index e7f7163fae1048bb9d979de0e70e881f2e62fade..4a2ce2eeee88785fc5689dd071bc121f8d87e0c5 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -20,6 +20,7 @@ MODULE_AUTHOR("Miklos Szeredi "); MODULE_DESCRIPTION("Overlay filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); struct ovl_dir_cache; diff --git a/fs/proc/bootconfig.c b/fs/proc/bootconfig.c index 2e244ada1f970b40dfc11417e5fd43579074d42f..6d8d4bf2083773d097ec1fbbf1b1abe34721a731 100644 --- a/fs/proc/bootconfig.c +++ b/fs/proc/bootconfig.c @@ -32,8 +32,6 @@ static int __init copy_xbc_key_value_list(char *dst, size_t size) int ret = 0; key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL); - if (!key) - return -ENOMEM; xbc_for_each_key_value(leaf, val) { ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 13f8e6f3d30f3ee0cf4ff3e674ad901063e24cea..b1bcbe7aca0eb88ff963b1128ae5c1fb3b9fbcae 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -309,7 +309,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) name = arch_vma_name(vma); if (!name) { - const char *anon_name; + struct anon_vma_name *anon_name; if (!mm) { name = "[vdso]"; @@ -327,10 +327,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) goto done; } - anon_name = vma_anon_name(vma); + anon_name = anon_vma_name(vma); if (anon_name) { seq_pad(m, ' '); - seq_printf(m, "[anon:%s]", anon_name); + seq_printf(m, "[anon:%s]", anon_name->name); } } diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index ce03c3dbb5c308ea93d2a84491123e279fa31435..b1ebf7b61732c396f731cb988f5e07addee065b8 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -143,22 +143,21 @@ static void pstore_timer_kick(void) mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms)); } -static bool pstore_cannot_block_path(enum kmsg_dump_reason reason) +/* + * Should pstore_dump() wait for a concurrent pstore_dump()? If + * not, the current pstore_dump() will report a failure to dump + * and return. + */ +static bool pstore_cannot_wait(enum kmsg_dump_reason reason) { - /* - * In case of NMI path, pstore shouldn't be blocked - * regardless of reason. - */ + /* In NMI path, pstore shouldn't block regardless of reason. */ if (in_nmi()) return true; switch (reason) { /* In panic case, other cpus are stopped by smp_send_stop(). */ case KMSG_DUMP_PANIC: - /* - * Emergency restart shouldn't be blocked by spinning on - * pstore_info::buf_lock. - */ + /* Emergency restart shouldn't be blocked. */ case KMSG_DUMP_EMERG: return true; default: @@ -389,19 +388,21 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long total = 0; const char *why; unsigned int part = 1; - unsigned long flags = 0; int ret; why = kmsg_dump_reason_str(reason); - if (pstore_cannot_block_path(reason)) { - if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) { - pr_err("dump skipped in %s path because of concurrent dump\n", - in_nmi() ? "NMI" : why); + if (down_trylock(&psinfo->buf_lock)) { + /* Failed to acquire lock: give up if we cannot wait. */ + if (pstore_cannot_wait(reason)) { + pr_err("dump skipped in %s path: may corrupt error record\n", + in_nmi() ? "NMI" : why); + return; + } + if (down_interruptible(&psinfo->buf_lock)) { + pr_err("could not grab semaphore?!\n"); return; } - } else { - spin_lock_irqsave(&psinfo->buf_lock, flags); } oopscount++; @@ -463,7 +464,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, total += record.size; part++; } - spin_unlock_irqrestore(&psinfo->buf_lock, flags); + + up(&psinfo->buf_lock); } static struct kmsg_dumper pstore_dumper = { @@ -589,7 +591,7 @@ int pstore_register(struct pstore_info *psi) psi->write_user = pstore_write_user_compat; psinfo = psi; mutex_init(&psinfo->read_mutex); - spin_lock_init(&psinfo->buf_lock); + sema_init(&psinfo->buf_lock, 1); if (psi->flags & PSTORE_FLAGS_DMESG) allocate_buf_for_compression(); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 3fb7fc819b4fc9ea54089e52ef594be08b661718..704fb7d09f0e2f321a2829d1dd06ffe75aa9c11d 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -420,4 +420,5 @@ static void __exit exit_qnx4_fs(void) module_init(init_qnx4_fs) module_exit(exit_qnx4_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c index 61191f7bdf62df8776edaf511574a228b77e4d2c..ac771f0e02388161704f1c10936ad613262076cb 100644 --- a/fs/qnx6/inode.c +++ b/fs/qnx6/inode.c @@ -679,3 +679,4 @@ static void __exit exit_qnx6_fs(void) module_init(init_qnx6_fs) module_exit(exit_qnx6_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/read_write.c b/fs/read_write.c index 75f764b434184238a33f3c9bc688bfb395b83cb9..ae703cb90599771aaaba7c078db3d3761ee67db4 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -471,7 +471,7 @@ ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) return ret; return __kernel_read(file, buf, count, pos); } -EXPORT_SYMBOL(kernel_read); +EXPORT_SYMBOL_NS(kernel_read, ANDROID_GKI_VFS_EXPORT_ONLY); ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { @@ -580,7 +580,7 @@ ssize_t kernel_write(struct file *file, const void *buf, size_t count, file_end_write(file); return ret; } -EXPORT_SYMBOL(kernel_write); +EXPORT_SYMBOL_NS(kernel_write, ANDROID_GKI_VFS_EXPORT_ONLY); ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 913f5af9bf248988d16cfa53973da58a041a7b2c..d84c2f2df0b729e1088b697d0ba1f968ee42dc03 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2655,6 +2655,7 @@ MODULE_ALIAS_FS("reiserfs"); MODULE_DESCRIPTION("ReiserFS journaled filesystem"); MODULE_AUTHOR("Hans Reiser "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_reiserfs_fs); module_exit(exit_reiserfs_fs); diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 259f684d9236e77d22c018c3844dc8801161d676..c335658c2e0f35ef64f0cdae0add0b7a96f2907d 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -666,3 +666,4 @@ module_exit(exit_romfs_fs); MODULE_DESCRIPTION("Direct-MTD Capable RomFS"); MODULE_AUTHOR("Red Hat, Inc."); MODULE_LICENSE("GPL"); /* Actually dual-licensed, but it doesn't matter for */ +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/splice.c b/fs/splice.c index 866d5c2367b233091e98e372b2ab25c04c93fef3..036a47937c18ee55c8f385c0ac511ca37dd53388 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -326,7 +326,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, return ret; } -EXPORT_SYMBOL(generic_file_splice_read); +EXPORT_SYMBOL_NS(generic_file_splice_read, ANDROID_GKI_VFS_EXPORT_ONLY); const struct pipe_buf_operations default_pipe_buf_ops = { .release = generic_pipe_buf_release, @@ -722,7 +722,7 @@ done: return ret; } -EXPORT_SYMBOL(iter_file_splice_write); +EXPORT_SYMBOL_NS(iter_file_splice_write, ANDROID_GKI_VFS_EXPORT_ONLY); /** * generic_splice_sendpage - splice data from a pipe to a socket diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 88cc94be10765c7f76b223536a8195eeb30f0296..83c48769f4140c32a870131bb64136adc59764f6 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -498,3 +498,4 @@ module_exit(exit_squashfs_fs); MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); MODULE_AUTHOR("Phillip Lougher "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/stat.c b/fs/stat.c index 1196af4d1ea03dfec6d003ed3233be4c21080805..c8a078f3acf89353b6995fefcf5c6dbb1689987b 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -49,7 +49,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) stat->blksize = i_blocksize(inode); stat->blocks = inode->i_blocks; } -EXPORT_SYMBOL(generic_fillattr); +EXPORT_SYMBOL_NS(generic_fillattr, ANDROID_GKI_VFS_EXPORT_ONLY); /** * vfs_getattr_nosec - getattr without security checks diff --git a/fs/super.c b/fs/super.c index bae3fe80f852e73de6e55f75454bcff169590bea..ae2b97dabe312c9804bd6bb143167a84643cb961 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1435,7 +1435,7 @@ error_bdev: error: return ERR_PTR(error); } -EXPORT_SYMBOL(mount_bdev); +EXPORT_SYMBOL_NS(mount_bdev, ANDROID_GKI_VFS_EXPORT_ONLY); void kill_block_super(struct super_block *sb) { @@ -1449,7 +1449,7 @@ void kill_block_super(struct super_block *sb) blkdev_put(bdev, mode | FMODE_EXCL); } -EXPORT_SYMBOL(kill_block_super); +EXPORT_SYMBOL_NS(kill_block_super, ANDROID_GKI_VFS_EXPORT_ONLY); #endif struct dentry *mount_nodev(struct file_system_type *fs_type, diff --git a/fs/sync.c b/fs/sync.c index 8e1c2272470fe234296d8ab5d6ec698a56569277..9bbaa61994fc384f8fbaaf2a69832dd7280be8d7 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -66,7 +66,7 @@ int sync_filesystem(struct super_block *sb) return ret; return __sync_filesystem(sb, 1); } -EXPORT_SYMBOL(sync_filesystem); +EXPORT_SYMBOL_NS(sync_filesystem, ANDROID_GKI_VFS_EXPORT_ONLY); static void sync_inodes_one_sb(struct super_block *sb, void *arg) { diff --git a/fs/sysv/super.c b/fs/sysv/super.c index cc8e2ed155c84e700ab1191efc563ada2266a65e..e5383bff5dadefc4ec3a8826187819439145a29e 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -592,3 +592,4 @@ static void __exit exit_sysv_fs(void) module_init(init_sysv_fs) module_exit(exit_sysv_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index bd250ed0a26fa71e57e3d5fa328103a718dd3789..a17cb7c8214f071fd4e820e442457b9f2683beb1 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -432,8 +432,6 @@ out_inode: make_bad_inode(inode); if (!instantiated) iput(inode); - else if (whiteout) - iput(*whiteout); out_budg: ubifs_release_budget(c, &req); if (!instantiated) @@ -1325,7 +1323,6 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, if (flags & RENAME_WHITEOUT) { union ubifs_dev_desc *dev = NULL; - struct ubifs_budget_req wht_req; dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) { @@ -1347,23 +1344,6 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, whiteout_ui->data = dev; whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); ubifs_assert(c, !whiteout_ui->dirty); - - memset(&wht_req, 0, sizeof(struct ubifs_budget_req)); - wht_req.dirtied_ino = 1; - wht_req.dirtied_ino_d = ALIGN(whiteout_ui->data_len, 8); - /* - * To avoid deadlock between space budget (holds ui_mutex and - * waits wb work) and writeback work(waits ui_mutex), do space - * budget before ubifs inodes locked. - */ - err = ubifs_budget_space(c, &wht_req); - if (err) { - iput(whiteout); - goto out_release; - } - - /* Add the old_dentry size to the old_dir size. */ - old_sz -= CALC_DENT_SIZE(fname_len(&old_nm)); } lock_4_inodes(old_dir, new_dir, new_inode, whiteout); @@ -1438,6 +1418,18 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, } if (whiteout) { + struct ubifs_budget_req wht_req = { .dirtied_ino = 1, + .dirtied_ino_d = \ + ALIGN(ubifs_inode(whiteout)->data_len, 8) }; + + err = ubifs_budget_space(c, &wht_req); + if (err) { + kfree(whiteout_ui->data); + whiteout_ui->data_len = 0; + iput(whiteout); + goto out_release; + } + inc_nlink(whiteout); mark_inode_dirty(whiteout); diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 354457e846cda4dc4c9c1486a1e5a09712f179ff..f4826b6da6828aa1818c42919c8cc0179f208441 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -570,7 +570,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping, } if (!PagePrivate(page)) { - attach_page_private(page, (void *)1); + SetPagePrivate(page); atomic_long_inc(&c->dirty_pg_cnt); __set_page_dirty_nobuffers(page); } @@ -947,7 +947,7 @@ static int do_writepage(struct page *page, int len) release_existing_page_budget(c); atomic_long_dec(&c->dirty_pg_cnt); - detach_page_private(page); + ClearPagePrivate(page); ClearPageChecked(page); kunmap(page); @@ -1303,7 +1303,7 @@ static void ubifs_invalidatepage(struct page *page, unsigned int offset, release_existing_page_budget(c); atomic_long_dec(&c->dirty_pg_cnt); - detach_page_private(page); + ClearPagePrivate(page); ClearPageChecked(page); } @@ -1470,8 +1470,8 @@ static int ubifs_migrate_page(struct address_space *mapping, return rc; if (PagePrivate(page)) { - detach_page_private(page); - attach_page_private(newpage, (void *)1); + ClearPagePrivate(page); + SetPagePrivate(newpage); } if (mode != MIGRATE_SYNC_NO_COPY) @@ -1495,7 +1495,7 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) return 0; ubifs_assert(c, PagePrivate(page)); ubifs_assert(c, 0); - detach_page_private(page); + ClearPagePrivate(page); ClearPageChecked(page); return 1; } @@ -1566,7 +1566,7 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf) else { if (!PageChecked(page)) ubifs_convert_page_budget(c); - attach_page_private(page, (void *)1); + SetPagePrivate(page); atomic_long_inc(&c->dirty_pg_cnt); __set_page_dirty_nobuffers(page); } diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 89b671ad0f9aa4f4942ce7c0d47869d36db7f2f0..eae9cf5a57b05948fb083131eb3a743ac195d109 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -846,42 +846,16 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) */ n = aligned_len >> c->max_write_shift; if (n) { - int m = n - 1; - + n <<= c->max_write_shift; dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, wbuf->offs); - - if (m) { - /* '(n-1)<max_write_shift < len' is always true. */ - m <<= c->max_write_shift; - err = ubifs_leb_write(c, wbuf->lnum, buf + written, - wbuf->offs, m); - if (err) - goto out; - wbuf->offs += m; - aligned_len -= m; - len -= m; - written += m; - } - - /* - * The non-written len of buf may be less than 'n' because - * parameter 'len' is not 8 bytes aligned, so here we read - * min(len, n) bytes from buf. - */ - n = 1 << c->max_write_shift; - memcpy(wbuf->buf, buf + written, min(len, n)); - if (n > len) { - ubifs_assert(c, n - len < 8); - ubifs_pad(c, wbuf->buf + len, n - len); - } - - err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, n); + err = ubifs_leb_write(c, wbuf->lnum, buf + written, + wbuf->offs, n); if (err) goto out; wbuf->offs += n; aligned_len -= n; - len -= min(len, n); + len -= n; written += n; } diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 8db380a000325a72cd273d431264b788e4244abc..4363d85a3fd4010f7b189ce419edecc3a76e0cba 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -107,7 +107,7 @@ static int setflags(struct inode *inode, int flags) struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_budget_req req = { .dirtied_ino = 1, - .dirtied_ino_d = ALIGN(ui->data_len, 8) }; + .dirtied_ino_d = ui->data_len }; err = ubifs_budget_space(c, &req); if (err) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 6a8f9efc2e2f08812a7518d04233e845ec9ac748..54093d0a8f0254f7fcb20f78d55bcd3e9bc44e30 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2475,6 +2475,7 @@ static void __exit ubifs_exit(void) module_exit(ubifs_exit); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_VERSION(__stringify(UBIFS_VERSION)); MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); MODULE_DESCRIPTION("UBIFS - UBI File System"); diff --git a/fs/udf/super.c b/fs/udf/super.c index 3448098e547681001c6a24ea76031b3ecc464583..c31c5c44b9fe5ce08fd56d21f082f9b9a93db1f5 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2545,5 +2545,6 @@ static unsigned int udf_count_free(struct super_block *sb) MODULE_AUTHOR("Ben Fennema"); MODULE_DESCRIPTION("Universal Disk Format Filesystem"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(init_udf_fs) module_exit(exit_udf_fs) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 983558b572c70b3d87fe6657caa0db093812b15e..e0d7149f76ca3d75ea358f0e09f0dd2740a93c98 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1542,3 +1542,4 @@ static void __exit exit_ufs_fs(void) module_init(init_ufs_fs) module_exit(exit_ufs_fs) MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 1c171cb26412e5f3f724e1567f86b780e30ba6f9..da8c8409528dc82dfe5dcffcd14b432f71f5503e 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -880,7 +880,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file) new_flags, vma->anon_vma, vma->vm_file, vma->vm_pgoff, vma_policy(vma), - NULL_VM_UFFD_CTX, vma_anon_name(vma)); + NULL_VM_UFFD_CTX, anon_vma_name(vma)); if (prev) vma = prev; else @@ -1438,7 +1438,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx, vma->anon_vma, vma->vm_file, vma->vm_pgoff, vma_policy(vma), ((struct vm_userfaultfd_ctx){ ctx }), - vma_anon_name(vma)); + anon_vma_name(vma)); if (prev) { vma = prev; goto next; @@ -1617,7 +1617,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx, prev = vma_merge(mm, prev, start, vma_end, new_flags, vma->anon_vma, vma->vm_file, vma->vm_pgoff, vma_policy(vma), - NULL_VM_UFFD_CTX, vma_anon_name(vma)); + NULL_VM_UFFD_CTX, anon_vma_name(vma)); if (prev) { vma = prev; goto next; diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c index c578e772cbd58b8b614953ce12c52358590ba277..0d4a0408cbd7ea74f264035be3f2b978e165517d 100644 --- a/fs/vboxsf/super.c +++ b/fs/vboxsf/super.c @@ -482,4 +482,5 @@ module_exit(vboxsf_fini); MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access"); MODULE_AUTHOR("Oracle Corporation"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); MODULE_ALIAS_FS("vboxsf"); diff --git a/fs/verity/Makefile b/fs/verity/Makefile index 435559a4fa9eae1d947ef0d90d0945bc14b08ee8..4b8323450f90a4dab3431334ed0d34400c4db52b 100644 --- a/fs/verity/Makefile +++ b/fs/verity/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=ANDROID_GKI_VFS_EXPORT_ONLY + obj-$(CONFIG_FS_VERITY) += enable.o \ hash_algs.o \ init.o \ diff --git a/fs/xattr.c b/fs/xattr.c index d6bf5a7e2420e7080add682f4a4926f2a2cecff0..f157f0b1bdfc238850db44c36fe41600e8ae4058 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -291,7 +291,7 @@ retry_deleg: } return error; } -EXPORT_SYMBOL_GPL(vfs_setxattr); +EXPORT_SYMBOL_NS_GPL(vfs_setxattr, ANDROID_GKI_VFS_EXPORT_ONLY); static ssize_t xattr_getsecurity(struct inode *inode, const char *name, void *value, @@ -405,7 +405,7 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { return __vfs_getxattr(dentry, dentry->d_inode, name, value, size, 0); } -EXPORT_SYMBOL_GPL(vfs_getxattr); +EXPORT_SYMBOL_NS_GPL(vfs_getxattr, ANDROID_GKI_VFS_EXPORT_ONLY); ssize_t vfs_listxattr(struct dentry *dentry, char *list, size_t size) @@ -425,7 +425,7 @@ vfs_listxattr(struct dentry *dentry, char *list, size_t size) } return error; } -EXPORT_SYMBOL_GPL(vfs_listxattr); +EXPORT_SYMBOL_NS_GPL(vfs_listxattr, ANDROID_GKI_VFS_EXPORT_ONLY); int __vfs_removexattr(struct dentry *dentry, const char *name) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index e3e229e52512adafac15b804f873eacd432b534d..6a7724a3560acebf8665ea1c911ff302ad53ab72 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -2224,3 +2224,4 @@ module_exit(exit_xfs_fs); MODULE_AUTHOR("Silicon Graphics, Inc."); MODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index e60759d8bb5fba0438b72bef13ebfc12c2c1b6d5..0ed752c6ef25f9f59746202d6c5dd93074e73737 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -1800,5 +1800,6 @@ MODULE_AUTHOR("Damien Le Moal"); MODULE_DESCRIPTION("Zone file system for zoned block devices"); MODULE_LICENSE("GPL"); MODULE_ALIAS_FS("zonefs"); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); module_init(zonefs_init); module_exit(zonefs_exit); diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 5a9786e6b5546d6bf9aa015c44d246d37604cad7..0571701ab1c57cc0d3dcddb119ea0c503e1ba641 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -82,9 +82,6 @@ struct coredump_params { unsigned long mm_flags; loff_t written; loff_t pos; - int vma_count; - size_t vma_data_size; - struct core_vma_metadata *vma_meta; }; /* diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index 0e6e84db06f6747cfd825aea1d2a7cb7d040398a..c8fc9792ac776d333f5696662cf2e5404571774f 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -24,7 +24,6 @@ #include #include #include -#include /* percpu_counter batch for blkg_[rw]stats, per-cpu drift doesn't matter */ #define BLKG_STAT_CPU_BATCH (INT_MAX / 2) @@ -600,21 +599,6 @@ static inline void blkcg_clear_delay(struct blkcg_gq *blkg) atomic_dec(&blkg->blkcg->css.cgroup->congestion_count); } -/** - * blk_cgroup_mergeable - Determine whether to allow or disallow merges - * @rq: request to merge into - * @bio: bio to merge - * - * @bio and @rq should belong to the same cgroup and their issue_as_root should - * match. The latter is necessary as we don't want to throttle e.g. a metadata - * update because it happens to be next to a regular IO. - */ -static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bio) -{ - return rq->bio->bi_blkg == bio->bi_blkg && - bio_issue_as_root_blkg(rq->bio) == bio_issue_as_root_blkg(bio); -} - void blk_cgroup_bio_start(struct bio *bio); void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta); void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay); @@ -670,7 +654,6 @@ static inline void blkg_put(struct blkcg_gq *blkg) { } static inline bool blkcg_punt_bio_submit(struct bio *bio) { return false; } static inline void blkcg_bio_issue_init(struct bio *bio) { } static inline void blk_cgroup_bio_start(struct bio *bio) { } -static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bio) { return true; } #define blk_queue_for_each_rl(rl, q) \ for ((rl) = &(q)->root_rl; (rl); (rl) = NULL) diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index cd894eaea34966a2cd32dc865b2b38f8b816f03e..142c98a3497d933142c8974b14b94d1b9d24498b 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -78,7 +78,7 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm, #endif /* CONFIG_BPF_LSM */ #endif #ifdef CONFIG_FUSE_BPF -BPF_PROG_TYPE(BPF_PROG_TYPE_FUSE, fuse, struct fuse_args, struct fuse_args) +BPF_PROG_TYPE(BPF_PROG_TYPE_FUSE, fuse, struct fuse_bpf_args, struct fuse_bpf_args) #endif BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 67b2190b1daef5e896158d2132cf19c53b1cd729..ceecd7829d35524f68b6f2b676342c54b2a3cfa3 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -435,6 +435,18 @@ static inline void cgroup_put(struct cgroup *cgrp) css_put(&cgrp->self); } +extern struct mutex cgroup_mutex; + +static inline void cgroup_lock(void) +{ + mutex_lock(&cgroup_mutex); +} + +static inline void cgroup_unlock(void) +{ + mutex_unlock(&cgroup_mutex); +} + /** * task_css_set_check - obtain a task's css_set with extra access conditions * @task: the task to obtain css_set for @@ -449,7 +461,6 @@ static inline void cgroup_put(struct cgroup *cgrp) * as locks used during the cgroup_subsys::attach() methods. */ #ifdef CONFIG_PROVE_RCU -extern struct mutex cgroup_mutex; extern spinlock_t css_set_lock; #define task_css_set_check(task, __c) \ rcu_dereference_check((task)->cgroups, \ @@ -709,6 +720,8 @@ struct cgroup; static inline u64 cgroup_id(struct cgroup *cgrp) { return 1; } static inline void css_get(struct cgroup_subsys_state *css) {} static inline void css_put(struct cgroup_subsys_state *css) {} +static inline void cgroup_lock(void) {} +static inline void cgroup_unlock(void) {} static inline int cgroup_attach_task_all(struct task_struct *from, struct task_struct *t) { return 0; } static inline int cgroupstats_build(struct cgroupstats *stats, diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 5300d0cb70f7ee0d8613c276106b53cc3bdcf8b9..e58e8c2077828d3d3f7f526f34976fff0062d40b 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -11,8 +11,6 @@ struct core_vma_metadata { unsigned long start, end; unsigned long flags; unsigned long dump_size; - unsigned long pgoff; - struct file *file; }; /* @@ -26,6 +24,9 @@ extern int dump_align(struct coredump_params *cprm, int align); extern void dump_truncate(struct coredump_params *cprm); int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len); +int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, + struct core_vma_metadata **vma_meta, + size_t *vma_data_size_ptr); #ifdef CONFIG_COREDUMP extern void do_coredump(const kernel_siginfo_t *siginfo); #else diff --git a/include/linux/damon.h b/include/linux/damon.h new file mode 100644 index 0000000000000000000000000000000000000000..5e1e3a128b77a9bac6452a7fa40c69e2c2cc456b --- /dev/null +++ b/include/linux/damon.h @@ -0,0 +1,511 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DAMON api + * + * Author: SeongJae Park + */ + +#ifndef _DAMON_H_ +#define _DAMON_H_ + +#include +#include +#include +#include + +/* Minimal region size. Every damon_region is aligned by this. */ +#define DAMON_MIN_REGION PAGE_SIZE +/* Max priority score for DAMON-based operation schemes */ +#define DAMOS_MAX_SCORE (99) + +/* Get a random number in [l, r) */ +static inline unsigned long damon_rand(unsigned long l, unsigned long r) +{ + return l + prandom_u32_max(r - l); +} + +/** + * struct damon_addr_range - Represents an address region of [@start, @end). + * @start: Start address of the region (inclusive). + * @end: End address of the region (exclusive). + */ +struct damon_addr_range { + unsigned long start; + unsigned long end; +}; + +/** + * struct damon_region - Represents a monitoring target region. + * @ar: The address range of the region. + * @sampling_addr: Address of the sample for the next access check. + * @nr_accesses: Access frequency of this region. + * @list: List head for siblings. + * @age: Age of this region. + * + * @age is initially zero, increased for each aggregation interval, and reset + * to zero again if the access frequency is significantly changed. If two + * regions are merged into a new region, both @nr_accesses and @age of the new + * region are set as region size-weighted average of those of the two regions. + */ +struct damon_region { + struct damon_addr_range ar; + unsigned long sampling_addr; + unsigned int nr_accesses; + struct list_head list; + + unsigned int age; +/* private: Internal value for age calculation. */ + unsigned int last_nr_accesses; +}; + +/** + * struct damon_target - Represents a monitoring target. + * @id: Unique identifier for this target. + * @nr_regions: Number of monitoring target regions of this target. + * @regions_list: Head of the monitoring target regions of this target. + * @list: List head for siblings. + * + * Each monitoring context could have multiple targets. For example, a context + * for virtual memory address spaces could have multiple target processes. The + * @id of each target should be unique among the targets of the context. For + * example, in the virtual address monitoring context, it could be a pidfd or + * an address of an mm_struct. + */ +struct damon_target { + unsigned long id; + unsigned int nr_regions; + struct list_head regions_list; + struct list_head list; +}; + +/** + * enum damos_action - Represents an action of a Data Access Monitoring-based + * Operation Scheme. + * + * @DAMOS_WILLNEED: Call ``madvise()`` for the region with MADV_WILLNEED. + * @DAMOS_COLD: Call ``madvise()`` for the region with MADV_COLD. + * @DAMOS_PAGEOUT: Call ``madvise()`` for the region with MADV_PAGEOUT. + * @DAMOS_HUGEPAGE: Call ``madvise()`` for the region with MADV_HUGEPAGE. + * @DAMOS_NOHUGEPAGE: Call ``madvise()`` for the region with MADV_NOHUGEPAGE. + * @DAMOS_STAT: Do nothing but count the stat. + */ +enum damos_action { + DAMOS_WILLNEED, + DAMOS_COLD, + DAMOS_PAGEOUT, + DAMOS_HUGEPAGE, + DAMOS_NOHUGEPAGE, + DAMOS_STAT, /* Do nothing but only record the stat */ +}; + +/** + * struct damos_quota - Controls the aggressiveness of the given scheme. + * @ms: Maximum milliseconds that the scheme can use. + * @sz: Maximum bytes of memory that the action can be applied. + * @reset_interval: Charge reset interval in milliseconds. + * + * @weight_sz: Weight of the region's size for prioritization. + * @weight_nr_accesses: Weight of the region's nr_accesses for prioritization. + * @weight_age: Weight of the region's age for prioritization. + * + * To avoid consuming too much CPU time or IO resources for applying the + * &struct damos->action to large memory, DAMON allows users to set time and/or + * size quotas. The quotas can be set by writing non-zero values to &ms and + * &sz, respectively. If the time quota is set, DAMON tries to use only up to + * &ms milliseconds within &reset_interval for applying the action. If the + * size quota is set, DAMON tries to apply the action only up to &sz bytes + * within &reset_interval. + * + * Internally, the time quota is transformed to a size quota using estimated + * throughput of the scheme's action. DAMON then compares it against &sz and + * uses smaller one as the effective quota. + * + * For selecting regions within the quota, DAMON prioritizes current scheme's + * target memory regions using the &struct damon_primitive->get_scheme_score. + * You could customize the prioritization logic by setting &weight_sz, + * &weight_nr_accesses, and &weight_age, because monitoring primitives are + * encouraged to respect those. + */ +struct damos_quota { + unsigned long ms; + unsigned long sz; + unsigned long reset_interval; + + unsigned int weight_sz; + unsigned int weight_nr_accesses; + unsigned int weight_age; + +/* private: */ + /* For throughput estimation */ + unsigned long total_charged_sz; + unsigned long total_charged_ns; + + unsigned long esz; /* Effective size quota in bytes */ + + /* For charging the quota */ + unsigned long charged_sz; + unsigned long charged_from; + struct damon_target *charge_target_from; + unsigned long charge_addr_from; + + /* For prioritization */ + unsigned long histogram[DAMOS_MAX_SCORE + 1]; + unsigned int min_score; +}; + +/** + * enum damos_wmark_metric - Represents the watermark metric. + * + * @DAMOS_WMARK_NONE: Ignore the watermarks of the given scheme. + * @DAMOS_WMARK_FREE_MEM_RATE: Free memory rate of the system in [0,1000]. + */ +enum damos_wmark_metric { + DAMOS_WMARK_NONE, + DAMOS_WMARK_FREE_MEM_RATE, +}; + +/** + * struct damos_watermarks - Controls when a given scheme should be activated. + * @metric: Metric for the watermarks. + * @interval: Watermarks check time interval in microseconds. + * @high: High watermark. + * @mid: Middle watermark. + * @low: Low watermark. + * + * If &metric is &DAMOS_WMARK_NONE, the scheme is always active. Being active + * means DAMON does monitoring and applying the action of the scheme to + * appropriate memory regions. Else, DAMON checks &metric of the system for at + * least every &interval microseconds and works as below. + * + * If &metric is higher than &high, the scheme is inactivated. If &metric is + * between &mid and &low, the scheme is activated. If &metric is lower than + * &low, the scheme is inactivated. + */ +struct damos_watermarks { + enum damos_wmark_metric metric; + unsigned long interval; + unsigned long high; + unsigned long mid; + unsigned long low; + +/* private: */ + bool activated; +}; + +/** + * struct damos_stat - Statistics on a given scheme. + * @nr_tried: Total number of regions that the scheme is tried to be applied. + * @sz_tried: Total size of regions that the scheme is tried to be applied. + * @nr_applied: Total number of regions that the scheme is applied. + * @sz_applied: Total size of regions that the scheme is applied. + * @qt_exceeds: Total number of times the quota of the scheme has exceeded. + */ +struct damos_stat { + unsigned long nr_tried; + unsigned long sz_tried; + unsigned long nr_applied; + unsigned long sz_applied; + unsigned long qt_exceeds; +}; + +/** + * struct damos - Represents a Data Access Monitoring-based Operation Scheme. + * @min_sz_region: Minimum size of target regions. + * @max_sz_region: Maximum size of target regions. + * @min_nr_accesses: Minimum ``->nr_accesses`` of target regions. + * @max_nr_accesses: Maximum ``->nr_accesses`` of target regions. + * @min_age_region: Minimum age of target regions. + * @max_age_region: Maximum age of target regions. + * @action: &damo_action to be applied to the target regions. + * @quota: Control the aggressiveness of this scheme. + * @wmarks: Watermarks for automated (in)activation of this scheme. + * @stat: Statistics of this scheme. + * @list: List head for siblings. + * + * For each aggregation interval, DAMON finds regions which fit in the + * condition (&min_sz_region, &max_sz_region, &min_nr_accesses, + * &max_nr_accesses, &min_age_region, &max_age_region) and applies &action to + * those. To avoid consuming too much CPU time or IO resources for the + * &action, "a is used. + * + * To do the work only when needed, schemes can be activated for specific + * system situations using &wmarks. If all schemes that registered to the + * monitoring context are inactive, DAMON stops monitoring either, and just + * repeatedly checks the watermarks. + * + * If all schemes that registered to a &struct damon_ctx are inactive, DAMON + * stops monitoring and just repeatedly checks the watermarks. + * + * After applying the &action to each region, &stat_count and &stat_sz is + * updated to reflect the number of regions and total size of regions that the + * &action is applied. + */ +struct damos { + unsigned long min_sz_region; + unsigned long max_sz_region; + unsigned int min_nr_accesses; + unsigned int max_nr_accesses; + unsigned int min_age_region; + unsigned int max_age_region; + enum damos_action action; + struct damos_quota quota; + struct damos_watermarks wmarks; + struct damos_stat stat; + struct list_head list; +}; + +struct damon_ctx; + +/** + * struct damon_primitive - Monitoring primitives for given use cases. + * + * @init: Initialize primitive-internal data structures. + * @update: Update primitive-internal data structures. + * @prepare_access_checks: Prepare next access check of target regions. + * @check_accesses: Check the accesses to target regions. + * @reset_aggregated: Reset aggregated accesses monitoring results. + * @get_scheme_score: Get the score of a region for a scheme. + * @apply_scheme: Apply a DAMON-based operation scheme. + * @target_valid: Determine if the target is valid. + * @cleanup: Clean up the context. + * + * DAMON can be extended for various address spaces and usages. For this, + * users should register the low level primitives for their target address + * space and usecase via the &damon_ctx.primitive. Then, the monitoring thread + * (&damon_ctx.kdamond) calls @init and @prepare_access_checks before starting + * the monitoring, @update after each &damon_ctx.primitive_update_interval, and + * @check_accesses, @target_valid and @prepare_access_checks after each + * &damon_ctx.sample_interval. Finally, @reset_aggregated is called after each + * &damon_ctx.aggr_interval. + * + * @init should initialize primitive-internal data structures. For example, + * this could be used to construct proper monitoring target regions and link + * those to @damon_ctx.adaptive_targets. + * @update should update the primitive-internal data structures. For example, + * this could be used to update monitoring target regions for current status. + * @prepare_access_checks should manipulate the monitoring regions to be + * prepared for the next access check. + * @check_accesses should check the accesses to each region that made after the + * last preparation and update the number of observed accesses of each region. + * It should also return max number of observed accesses that made as a result + * of its update. The value will be used for regions adjustment threshold. + * @reset_aggregated should reset the access monitoring results that aggregated + * by @check_accesses. + * @get_scheme_score should return the priority score of a region for a scheme + * as an integer in [0, &DAMOS_MAX_SCORE]. + * @apply_scheme is called from @kdamond when a region for user provided + * DAMON-based operation scheme is found. It should apply the scheme's action + * to the region and return bytes of the region that the action is successfully + * applied. + * @target_valid should check whether the target is still valid for the + * monitoring. + * @cleanup is called from @kdamond just before its termination. + */ +struct damon_primitive { + void (*init)(struct damon_ctx *context); + void (*update)(struct damon_ctx *context); + void (*prepare_access_checks)(struct damon_ctx *context); + unsigned int (*check_accesses)(struct damon_ctx *context); + void (*reset_aggregated)(struct damon_ctx *context); + int (*get_scheme_score)(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme); + unsigned long (*apply_scheme)(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme); + bool (*target_valid)(void *target); + void (*cleanup)(struct damon_ctx *context); +}; + +/** + * struct damon_callback - Monitoring events notification callbacks. + * + * @before_start: Called before starting the monitoring. + * @after_sampling: Called after each sampling. + * @after_aggregation: Called after each aggregation. + * @before_terminate: Called before terminating the monitoring. + * @private: User private data. + * + * The monitoring thread (&damon_ctx.kdamond) calls @before_start and + * @before_terminate just before starting and finishing the monitoring, + * respectively. Therefore, those are good places for installing and cleaning + * @private. + * + * The monitoring thread calls @after_sampling and @after_aggregation for each + * of the sampling intervals and aggregation intervals, respectively. + * Therefore, users can safely access the monitoring results without additional + * protection. For the reason, users are recommended to use these callback for + * the accesses to the results. + * + * If any callback returns non-zero, monitoring stops. + */ +struct damon_callback { + void *private; + + int (*before_start)(struct damon_ctx *context); + int (*after_sampling)(struct damon_ctx *context); + int (*after_aggregation)(struct damon_ctx *context); + void (*before_terminate)(struct damon_ctx *context); +}; + +/** + * struct damon_ctx - Represents a context for each monitoring. This is the + * main interface that allows users to set the attributes and get the results + * of the monitoring. + * + * @sample_interval: The time between access samplings. + * @aggr_interval: The time between monitor results aggregations. + * @primitive_update_interval: The time between monitoring primitive updates. + * + * For each @sample_interval, DAMON checks whether each region is accessed or + * not. It aggregates and keeps the access information (number of accesses to + * each region) for @aggr_interval time. DAMON also checks whether the target + * memory regions need update (e.g., by ``mmap()`` calls from the application, + * in case of virtual memory monitoring) and applies the changes for each + * @primitive_update_interval. All time intervals are in micro-seconds. + * Please refer to &struct damon_primitive and &struct damon_callback for more + * detail. + * + * @kdamond: Kernel thread who does the monitoring. + * @kdamond_stop: Notifies whether kdamond should stop. + * @kdamond_lock: Mutex for the synchronizations with @kdamond. + * + * For each monitoring context, one kernel thread for the monitoring is + * created. The pointer to the thread is stored in @kdamond. + * + * Once started, the monitoring thread runs until explicitly required to be + * terminated or every monitoring target is invalid. The validity of the + * targets is checked via the &damon_primitive.target_valid of @primitive. The + * termination can also be explicitly requested by writing non-zero to + * @kdamond_stop. The thread sets @kdamond to NULL when it terminates. + * Therefore, users can know whether the monitoring is ongoing or terminated by + * reading @kdamond. Reads and writes to @kdamond and @kdamond_stop from + * outside of the monitoring thread must be protected by @kdamond_lock. + * + * Note that the monitoring thread protects only @kdamond and @kdamond_stop via + * @kdamond_lock. Accesses to other fields must be protected by themselves. + * + * @primitive: Set of monitoring primitives for given use cases. + * @callback: Set of callbacks for monitoring events notifications. + * + * @min_nr_regions: The minimum number of adaptive monitoring regions. + * @max_nr_regions: The maximum number of adaptive monitoring regions. + * @adaptive_targets: Head of monitoring targets (&damon_target) list. + * @schemes: Head of schemes (&damos) list. + */ +struct damon_ctx { + unsigned long sample_interval; + unsigned long aggr_interval; + unsigned long primitive_update_interval; + +/* private: internal use only */ + struct timespec64 last_aggregation; + struct timespec64 last_primitive_update; + +/* public: */ + struct task_struct *kdamond; + struct mutex kdamond_lock; + + struct damon_primitive primitive; + struct damon_callback callback; + + unsigned long min_nr_regions; + unsigned long max_nr_regions; + struct list_head adaptive_targets; + struct list_head schemes; +}; + +static inline struct damon_region *damon_next_region(struct damon_region *r) +{ + return container_of(r->list.next, struct damon_region, list); +} + +static inline struct damon_region *damon_prev_region(struct damon_region *r) +{ + return container_of(r->list.prev, struct damon_region, list); +} + +static inline struct damon_region *damon_last_region(struct damon_target *t) +{ + return list_last_entry(&t->regions_list, struct damon_region, list); +} + +#define damon_for_each_region(r, t) \ + list_for_each_entry(r, &t->regions_list, list) + +#define damon_for_each_region_safe(r, next, t) \ + list_for_each_entry_safe(r, next, &t->regions_list, list) + +#define damon_for_each_target(t, ctx) \ + list_for_each_entry(t, &(ctx)->adaptive_targets, list) + +#define damon_for_each_target_safe(t, next, ctx) \ + list_for_each_entry_safe(t, next, &(ctx)->adaptive_targets, list) + +#define damon_for_each_scheme(s, ctx) \ + list_for_each_entry(s, &(ctx)->schemes, list) + +#define damon_for_each_scheme_safe(s, next, ctx) \ + list_for_each_entry_safe(s, next, &(ctx)->schemes, list) + +#ifdef CONFIG_DAMON + +struct damon_region *damon_new_region(unsigned long start, unsigned long end); + +/* + * Add a region between two other regions + */ +static inline void damon_insert_region(struct damon_region *r, + struct damon_region *prev, struct damon_region *next, + struct damon_target *t) +{ + __list_add(&r->list, &prev->list, &next->list); + t->nr_regions++; +} + +void damon_add_region(struct damon_region *r, struct damon_target *t); +void damon_destroy_region(struct damon_region *r, struct damon_target *t); + +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action, struct damos_quota *quota, + struct damos_watermarks *wmarks); +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s); +void damon_destroy_scheme(struct damos *s); + +struct damon_target *damon_new_target(unsigned long id); +void damon_add_target(struct damon_ctx *ctx, struct damon_target *t); +bool damon_targets_empty(struct damon_ctx *ctx); +void damon_free_target(struct damon_target *t); +void damon_destroy_target(struct damon_target *t); +unsigned int damon_nr_regions(struct damon_target *t); + +struct damon_ctx *damon_new_ctx(void); +void damon_destroy_ctx(struct damon_ctx *ctx); +int damon_set_targets(struct damon_ctx *ctx, + unsigned long *ids, ssize_t nr_ids); +int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, + unsigned long aggr_int, unsigned long primitive_upd_int, + unsigned long min_nr_reg, unsigned long max_nr_reg); +int damon_set_schemes(struct damon_ctx *ctx, + struct damos **schemes, ssize_t nr_schemes); +int damon_nr_running_ctxs(void); + +int damon_start(struct damon_ctx **ctxs, int nr_ctxs); +int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); + +#endif /* CONFIG_DAMON */ + +#ifdef CONFIG_DAMON_VADDR +bool damon_va_target_valid(void *t); +void damon_va_set_primitives(struct damon_ctx *ctx); +#endif /* CONFIG_DAMON_VADDR */ + +#ifdef CONFIG_DAMON_PADDR +bool damon_pa_target_valid(void *t); +void damon_pa_set_primitives(struct damon_ctx *ctx); +#endif /* CONFIG_DAMON_PADDR */ + +#endif /* _DAMON_H */ diff --git a/include/linux/delay.h b/include/linux/delay.h index 1d0e2ce6b6d9f1ff4fa9461cb2b00d40d92fd7c2..abecbccab6e444abd0281e5c21a1f744a2059cb7 100644 --- a/include/linux/delay.h +++ b/include/linux/delay.h @@ -20,6 +20,7 @@ */ #include +#include extern unsigned long loops_per_jiffy; @@ -58,8 +59,15 @@ void calibrate_delay(void); void __attribute__((weak)) calibration_delay_done(void); void msleep(unsigned int msecs); unsigned long msleep_interruptible(unsigned int msecs); +void usleep_range_state(unsigned long min, unsigned long max, + unsigned int state); void usleep_range(unsigned long min, unsigned long max); +static inline void usleep_idle_range(unsigned long min, unsigned long max) +{ + usleep_range_state(min, max, TASK_IDLE); +} + static inline void ssleep(unsigned int seconds) { msleep(seconds * 1000); diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 03befff63edaa9763393b825251904fc4f5dd6ce..7270f12e2c7807f508ae4288d88bea764e33347e 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -61,21 +61,13 @@ */ #define DMA_ATTR_PRIVILEGED (1UL << 9) -/* - * This is a hint to the DMA-mapping subsystem that the device is expected - * to overwrite the entire mapped size, thus the caller does not require any - * of the previous buffer contents to be preserved. This allows - * bounce-buffering implementations to optimise DMA_FROM_DEVICE transfers. - */ -#define DMA_ATTR_OVERWRITE (1UL << 10) - /* * DMA_ATTR_SYS_CACHE_ONLY: used to indicate that the buffer should be mapped * with the correct memory attributes so that it can be cached in the system * or last level cache. This is useful for buffers that are being mapped for * devices that are non-coherent, but can use the system cache. */ -#define DMA_ATTR_SYS_CACHE_ONLY (1UL << 14) +#define DMA_ATTR_SYS_CACHE_ONLY (1UL << 10) /* * DMA_ATTR_SYS_CACHE_ONLY_NWA: used to indicate that the buffer should be @@ -84,7 +76,7 @@ * useful for buffers that are being mapped for devices that are non-coherent, * but can use the system cache. */ -#define DMA_ATTR_SYS_CACHE_ONLY_NWA (1UL << 15) +#define DMA_ATTR_SYS_CACHE_ONLY_NWA (1UL << 11) /* * A dma_addr_t can hold any valid DMA or bus address for the platform. It can diff --git a/include/linux/export.h b/include/linux/export.h index 8889809924156b4952ac7e1217722d40d0a253d6..3b25f680180fa18277cba0b9111238c7b6dc6add 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -190,8 +190,10 @@ struct kernel_symbol { #define EXPORT_SYMBOL(sym) _EXPORT_SYMBOL(sym, "") #define EXPORT_SYMBOL_GPL(sym) _EXPORT_SYMBOL(sym, "_gpl") #define EXPORT_SYMBOL_GPL_FUTURE(sym) _EXPORT_SYMBOL(sym, "_gpl_future") -#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", #ns) -#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns) +#define _EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", #ns) +#define _EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns) +#define EXPORT_SYMBOL_NS(sym, ns) _EXPORT_SYMBOL_NS(sym, ns) +#define EXPORT_SYMBOL_NS_GPL(sym, ns) _EXPORT_SYMBOL_NS_GPL(sym, ns) #ifdef CONFIG_UNUSED_SYMBOLS #define EXPORT_UNUSED_SYMBOL(sym) _EXPORT_SYMBOL(sym, "_unused") diff --git a/include/linux/gfp.h b/include/linux/gfp.h index def31f0f5a0779822b7ca5e48722a382422dff84..ae480a3d5307c8d6f9dec1bcffdbc68da515b687 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -262,13 +262,9 @@ struct vm_area_struct; /* Room for N __GFP_FOO bits */ #ifdef CONFIG_CMA -#define __GFP_BITS_SHIFT (25 + \ - 3 * IS_ENABLED(CONFIG_KASAN_HW_TAGS) + \ - IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT (28 + IS_ENABLED(CONFIG_LOCKDEP)) #else -#define __GFP_BITS_SHIFT (24 + \ - 3 * IS_ENABLED(CONFIG_KASAN_HW_TAGS) + \ - IS_ENABLED(CONFIG_LOCKDEP)) +#define __GFP_BITS_SHIFT (27 + IS_ENABLED(CONFIG_LOCKDEP)) #endif #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index e147ea6794670888fbf949e9cee5dc38e16d8c3e..bf5c5f32c65e46cc3d58208612482c4f42594333 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -51,7 +51,6 @@ static inline bool dev_is_mac_header_xmit(const struct net_device *dev) case ARPHRD_VOID: case ARPHRD_NONE: case ARPHRD_RAWIP: - case ARPHRD_PIMREG: return false; default: return true; diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 1f503288f222bebc335c070bce375836a27b5ac7..90c54edfe5565677bf020de5cf65643127cdf733 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -17,19 +17,14 @@ struct task_struct; #include #include -/* kasan_data struct is used in KUnit tests for KASAN expected failures */ -struct kunit_kasan_expectation { - bool report_found; -}; - #endif typedef unsigned int __bitwise kasan_vmalloc_flags_t; -#define KASAN_VMALLOC_NONE 0x00u -#define KASAN_VMALLOC_INIT 0x01u -#define KASAN_VMALLOC_VM_ALLOC 0x02u -#define KASAN_VMALLOC_PROT_NORMAL 0x04u +#define KASAN_VMALLOC_NONE ((__force kasan_vmalloc_flags_t)0x00u) +#define KASAN_VMALLOC_INIT ((__force kasan_vmalloc_flags_t)0x01u) +#define KASAN_VMALLOC_VM_ALLOC ((__force kasan_vmalloc_flags_t)0x02u) +#define KASAN_VMALLOC_PROT_NORMAL ((__force kasan_vmalloc_flags_t)0x04u) #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 6ea0873708b1d5bac08dee0164b8d24e16a1d526..531cb39a00f75531e3284ad42806453dfe085672 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -332,6 +332,11 @@ struct mem_cgroup { struct deferred_split deferred_split_queue; #endif +#ifdef CONFIG_LRU_GEN + /* per-memcg mm_struct list */ + struct lru_gen_mm_list mm_list; +#endif + ANDROID_OEM_DATA(1); struct mem_cgroup_per_node *nodeinfo[0]; /* WARNING: nodeinfo must be the last member here */ @@ -735,6 +740,23 @@ static inline unsigned long memcg_page_state_local(struct mem_cgroup *memcg, void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val); +/* try to stablize page_memcg() for all the pages in a memcg */ +static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) +{ + rcu_read_lock(); + + if (mem_cgroup_disabled() || !atomic_read(&memcg->moving_account)) + return true; + + rcu_read_unlock(); + return false; +} + +static inline void mem_cgroup_unlock_pages(void) +{ + rcu_read_unlock(); +} + /* idx can be of type enum memcg_stat_item or node_stat_item */ static inline void mod_memcg_state(struct mem_cgroup *memcg, int idx, int val) @@ -1153,6 +1175,18 @@ static inline void unlock_page_memcg(struct page *page) { } +static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) +{ + /* to match page_memcg_rcu() */ + rcu_read_lock(); + return true; +} + +static inline void mem_cgroup_unlock_pages(void) +{ + rcu_read_unlock(); +} + static inline void mem_cgroup_handle_over_high(void) { } diff --git a/include/linux/mm.h b/include/linux/mm.h index f8ae933c9ed31e7c1f4e5e8ba1dc714d92a730e7..c93e896ab4d839a3fe8e3934cd3164a4ca3e5dd2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1107,6 +1107,8 @@ vm_fault_t finish_mkwrite_fault(struct vm_fault *vmf); #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) +#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) +#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) /* * Define the bit shifts to access each section. For non-existent @@ -1286,7 +1288,6 @@ static inline void put_page(struct page *page) */ #define GUP_PIN_COUNTING_BIAS (1U << 10) -void put_user_page(struct page *page); void unpin_user_page(struct page *page); void unpin_user_pages_dirty_lock(struct page **pages, unsigned long npages, bool make_dirty); @@ -2672,13 +2673,13 @@ extern struct vm_area_struct *__vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *anon, struct file *file, pgoff_t pgoff, struct mempolicy *mpol, struct vm_userfaultfd_ctx uff, - const char *, bool keep_locked); + struct anon_vma_name *, bool keep_locked); static inline struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *anon, struct file *file, pgoff_t off, struct mempolicy *pol, struct vm_userfaultfd_ctx uff, - const char *anon_name) + struct anon_vma_name *anon_name) { return __vma_merge(mm, prev, addr, end, vm_flags, anon, file, off, pol, uff, anon_name, false); @@ -3397,11 +3398,12 @@ static inline int seal_check_future_write(int seals, struct vm_area_struct *vma) #ifdef CONFIG_ANON_VMA_NAME int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, - unsigned long len_in, const char *name); + unsigned long len_in, + struct anon_vma_name *anon_name); #else static inline int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, - unsigned long len_in, const char *name) { + unsigned long len_in, struct anon_vma_name *anon_name) { return 0; } #endif diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 589e828f8fa810bf7860a8a63ae36b3f999e23b9..af0790da3b9fe39ffee6cc6f1053af1c844df441 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -31,6 +31,8 @@ static __always_inline void __update_lru_size(struct lruvec *lruvec, { struct pglist_data *pgdat = lruvec_pgdat(lruvec); + lockdep_assert_held(&pgdat->lru_lock); + __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); __mod_zone_page_state(&pgdat->node_zones[zid], NR_ZONE_LRU_BASE + lru, nr_pages); @@ -46,133 +48,363 @@ static __always_inline void update_lru_size(struct lruvec *lruvec, #endif } +/** + * __clear_page_lru_flags - clear page lru flags before releasing a page + * @page: the page that was on lru and now has a zero reference + */ +static __always_inline void __clear_page_lru_flags(struct page *page) +{ + VM_BUG_ON_PAGE(!PageLRU(page), page); + + __ClearPageLRU(page); + + /* this shouldn't happen, so leave the flags to bad_page() */ + if (PageActive(page) && PageUnevictable(page)) + return; + + __ClearPageActive(page); + __ClearPageUnevictable(page); +} + +/** + * page_lru - which LRU list should a page be on? + * @page: the page to test + * + * Returns the LRU list a page should be on, as an index + * into the array of LRU lists. + */ +static __always_inline enum lru_list page_lru(struct page *page) +{ + enum lru_list lru; + + VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); + + if (PageUnevictable(page)) + return LRU_UNEVICTABLE; + + lru = page_is_file_lru(page) ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON; + if (PageActive(page)) + lru += LRU_ACTIVE; + + return lru; +} + +#ifdef CONFIG_LRU_GEN + +static inline bool lru_gen_enabled(void) +{ +#ifdef CONFIG_LRU_GEN_ENABLED + DECLARE_STATIC_KEY_TRUE(lru_gen_caps[NR_LRU_GEN_CAPS]); + + return static_branch_likely(&lru_gen_caps[LRU_GEN_CORE]); +#else + DECLARE_STATIC_KEY_FALSE(lru_gen_caps[NR_LRU_GEN_CAPS]); + + return static_branch_unlikely(&lru_gen_caps[LRU_GEN_CORE]); +#endif +} + +static inline bool lru_gen_in_fault(void) +{ + return current->in_lru_fault; +} + +static inline int lru_gen_from_seq(unsigned long seq) +{ + return seq % MAX_NR_GENS; +} + +static inline int lru_hist_from_seq(unsigned long seq) +{ + return seq % NR_HIST_GENS; +} + +static inline int lru_tier_from_refs(int refs) +{ + VM_BUG_ON(refs > BIT(LRU_REFS_WIDTH)); + + /* see the comment on MAX_NR_TIERS */ + return order_base_2(refs + 1); +} + +static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) +{ + unsigned long max_seq = lruvec->lrugen.max_seq; + + VM_BUG_ON(gen >= MAX_NR_GENS); + + /* see the comment on MIN_NR_GENS */ + return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); +} + +static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, + int old_gen, int new_gen) +{ + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + int delta = thp_nr_pages(page); + enum lru_list lru = type * LRU_INACTIVE_FILE; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(old_gen != -1 && old_gen >= MAX_NR_GENS); + VM_BUG_ON(new_gen != -1 && new_gen >= MAX_NR_GENS); + VM_BUG_ON(old_gen == -1 && new_gen == -1); + + if (old_gen >= 0) + WRITE_ONCE(lrugen->nr_pages[old_gen][type][zone], + lrugen->nr_pages[old_gen][type][zone] - delta); + if (new_gen >= 0) + WRITE_ONCE(lrugen->nr_pages[new_gen][type][zone], + lrugen->nr_pages[new_gen][type][zone] + delta); + + /* addition */ + if (old_gen < 0) { + if (lru_gen_is_active(lruvec, new_gen)) + lru += LRU_ACTIVE; + __update_lru_size(lruvec, lru, zone, delta); + return; + } + + /* deletion */ + if (new_gen < 0) { + if (lru_gen_is_active(lruvec, old_gen)) + lru += LRU_ACTIVE; + __update_lru_size(lruvec, lru, zone, -delta); + return; + } + + /* promotion */ + if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { + __update_lru_size(lruvec, lru, zone, -delta); + __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); + } + + /* demotion requires isolation, e.g., lru_deactivate_fn() */ + VM_BUG_ON(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); +} + +static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + int gen; + unsigned long old_flags, new_flags; + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + if (PageUnevictable(page) || !lrugen->enabled) + return false; + /* + * There are three common cases for this page: + * 1. If it's hot, e.g., freshly faulted in or previously hot and + * migrated, add it to the youngest generation. + * 2. If it's cold but can't be evicted immediately, i.e., an anon page + * not in swapcache or a dirty page pending writeback, add it to the + * second oldest generation. + * 3. Everything else (clean, cold) is added to the oldest generation. + */ + if (PageActive(page)) + gen = lru_gen_from_seq(lrugen->max_seq); + else if ((type == LRU_GEN_ANON && !PageSwapCache(page)) || + (PageReclaim(page) && (PageDirty(page) || PageWriteback(page)))) + gen = lru_gen_from_seq(lrugen->min_seq[type] + 1); + else + gen = lru_gen_from_seq(lrugen->min_seq[type]); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + VM_BUG_ON_PAGE(new_flags & LRU_GEN_MASK, page); + + /* see the comment on MIN_NR_GENS */ + new_flags &= ~(LRU_GEN_MASK | BIT(PG_active)); + new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, -1, gen); + /* for rotate_reclaimable_page() */ + if (reclaiming) + list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); + else + list_add(&page->lru, &lrugen->lists[gen][type][zone]); + + return true; +} + +static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + int gen; + unsigned long old_flags, new_flags; + + do { + new_flags = old_flags = READ_ONCE(page->flags); + if (!(new_flags & LRU_GEN_MASK)) + return false; + + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + + gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; + + new_flags &= ~LRU_GEN_MASK; + if (!(new_flags & BIT(PG_referenced))) + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + /* for shrink_page_list() */ + if (reclaiming) + new_flags &= ~(BIT(PG_referenced) | BIT(PG_reclaim)); + else if (lru_gen_is_active(lruvec, gen)) + new_flags |= BIT(PG_active); + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, gen, -1); + list_del(&page->lru); + + return true; +} + +#else + +static inline bool lru_gen_enabled(void) +{ + return false; +} + +static inline bool lru_gen_in_fault(void) +{ + return false; +} + +static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + return false; +} + +static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + return false; +} + +#endif /* CONFIG_LRU_GEN */ + static __always_inline void add_page_to_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) + struct lruvec *lruvec) { + enum lru_list lru = page_lru(page); + + if (lru_gen_add_page(lruvec, page, false)) + return; + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add(&page->lru, &lruvec->lists[lru]); } static __always_inline void add_page_to_lru_list_tail(struct page *page, - struct lruvec *lruvec, enum lru_list lru) + struct lruvec *lruvec) { + enum lru_list lru = page_lru(page); + + if (lru_gen_add_page(lruvec, page, true)) + return; + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add_tail(&page->lru, &lruvec->lists[lru]); } static __always_inline void del_page_from_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) + struct lruvec *lruvec) { + if (lru_gen_del_page(lruvec, page, false)) + return; + list_del(&page->lru); - update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page)); + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -thp_nr_pages(page)); } -/** - * page_lru_base_type - which LRU list type should a page be on? - * @page: the page to test - * - * Used for LRU list index arithmetic. - * - * Returns the base LRU type - file or anon - @page should be on. +#ifdef CONFIG_ANON_VMA_NAME +/* + * mmap_lock should be read-locked when calling anon_vma_name(). Caller should + * either keep holding the lock while using the returned pointer or it should + * raise anon_vma_name refcount before releasing the lock. */ -static inline enum lru_list page_lru_base_type(struct page *page) +extern struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma); +extern struct anon_vma_name *anon_vma_name_alloc(const char *name); +extern void anon_vma_name_free(struct kref *kref); + +/* mmap_lock should be read-locked */ +static inline void anon_vma_name_get(struct anon_vma_name *anon_name) { - if (page_is_file_lru(page)) - return LRU_INACTIVE_FILE; - return LRU_INACTIVE_ANON; + if (anon_name) + kref_get(&anon_name->kref); } -/** - * page_off_lru - which LRU list was page on? clearing its lru flags. - * @page: the page to test - * - * Returns the LRU list a page was on, as an index into the array of LRU - * lists; and clears its Unevictable or Active flags, ready for freeing. - */ -static __always_inline enum lru_list page_off_lru(struct page *page) +static inline void anon_vma_name_put(struct anon_vma_name *anon_name) { - enum lru_list lru; - - if (PageUnevictable(page)) { - __ClearPageUnevictable(page); - lru = LRU_UNEVICTABLE; - } else { - lru = page_lru_base_type(page); - if (PageActive(page)) { - __ClearPageActive(page); - lru += LRU_ACTIVE; - } - } - return lru; + if (anon_name) + kref_put(&anon_name->kref, anon_vma_name_free); } -/** - * page_lru - which LRU list should a page be on? - * @page: the page to test - * - * Returns the LRU list a page should be on, as an index - * into the array of LRU lists. - */ -static __always_inline enum lru_list page_lru(struct page *page) +static inline +struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name) { - enum lru_list lru; + /* Prevent anon_name refcount saturation early on */ + if (kref_read(&anon_name->kref) < REFCOUNT_MAX) { + anon_vma_name_get(anon_name); + return anon_name; - if (PageUnevictable(page)) - lru = LRU_UNEVICTABLE; - else { - lru = page_lru_base_type(page); - if (PageActive(page)) - lru += LRU_ACTIVE; } - return lru; + return anon_vma_name_alloc(anon_name->name); } -#ifdef CONFIG_ANON_VMA_NAME -/* - * mmap_lock should be read-locked when calling vma_anon_name() and while using - * the returned pointer. - */ -extern const char *vma_anon_name(struct vm_area_struct *vma); - -/* - * mmap_lock should be read-locked for orig_vma->vm_mm. - * mmap_lock should be write-locked for new_vma->vm_mm or new_vma should be - * isolated. - */ -extern void dup_vma_anon_name(struct vm_area_struct *orig_vma, - struct vm_area_struct *new_vma); +static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma, + struct vm_area_struct *new_vma) +{ + struct anon_vma_name *anon_name = anon_vma_name(orig_vma); -/* - * mmap_lock should be write-locked or vma should have been isolated under - * write-locked mmap_lock protection. - */ -extern void free_vma_anon_name(struct vm_area_struct *vma); + if (anon_name) + new_vma->anon_name = anon_vma_name_reuse(anon_name); +} -/* mmap_lock should be read-locked */ -static inline bool is_same_vma_anon_name(struct vm_area_struct *vma, - const char *name) +static inline void free_anon_vma_name(struct vm_area_struct *vma) { - const char *vma_name = vma_anon_name(vma); + /* + * Not using anon_vma_name because it generates a warning if mmap_lock + * is not held, which might be the case here. + */ + if (!vma->vm_file) + anon_vma_name_put(vma->anon_name); +} - /* either both NULL, or pointers to same string */ - if (vma_name == name) +static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1, + struct anon_vma_name *anon_name2) +{ + if (anon_name1 == anon_name2) return true; - return name && vma_name && !strcmp(name, vma_name); + return anon_name1 && anon_name2 && + !strcmp(anon_name1->name, anon_name2->name); } #else /* CONFIG_ANON_VMA_NAME */ -static inline const char *vma_anon_name(struct vm_area_struct *vma) +static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma) { return NULL; } -static inline void dup_vma_anon_name(struct vm_area_struct *orig_vma, - struct vm_area_struct *new_vma) {} -static inline void free_vma_anon_name(struct vm_area_struct *vma) {} -static inline bool is_same_vma_anon_name(struct vm_area_struct *vma, - const char *name) + +static inline struct anon_vma_name *anon_vma_name_alloc(const char *name) +{ + return NULL; +} + +static inline void anon_vma_name_get(struct anon_vma_name *anon_name) {} +static inline void anon_vma_name_put(struct anon_vma_name *anon_name) {} +static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma, + struct vm_area_struct *new_vma) {} +static inline void free_anon_vma_name(struct vm_area_struct *vma) {} + +static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1, + struct anon_vma_name *anon_name2) { return true; } + #endif /* CONFIG_ANON_VMA_NAME */ #endif diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 04f1003826148b0deaeee7f81b1bf34ddf32a5d0..988f4e6a4e39f53adf760400ce55f18a8c09bfa7 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -3,6 +3,7 @@ #define _LINUX_MM_TYPES_H #include +#include #include #include @@ -16,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -86,6 +89,7 @@ struct page { * by the page owner. */ struct list_head lru; + /* See page-flags.h for PAGE_MAPPING_FLAGS */ struct address_space *mapping; pgoff_t index; /* Our offset within mapping. */ @@ -356,7 +360,10 @@ struct vm_area_struct { struct rb_node rb; unsigned long rb_subtree_last; } shared; - /* Serialized by mmap_sem. */ + /* + * Serialized by mmap_sem. Never use directly because it is + * valid only when vm_file is NULL. Use anon_vma_name instead. + */ struct anon_vma_name *anon_name; }; @@ -611,6 +618,23 @@ struct mm_struct { u32 pasid; #endif +#ifdef CONFIG_LRU_GEN + struct { + /* this mm_struct is on lru_gen_mm_list */ + struct list_head list; +#ifdef CONFIG_MEMCG + /* points to the memcg of "owner" above */ + struct mem_cgroup *memcg; +#endif + /* + * Set when switching to this mm_struct, as a hint of + * whether it has been used since the last time per-node + * page table walkers cleared the corresponding bits. + */ + nodemask_t nodes; + } lru_gen; +#endif /* CONFIG_LRU_GEN */ + ANDROID_KABI_RESERVE(1); } __randomize_layout; @@ -638,6 +662,65 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) return (struct cpumask *)&mm->cpu_bitmap; } +#ifdef CONFIG_LRU_GEN + +struct lru_gen_mm_list { + /* mm_struct list for page table walkers */ + struct list_head fifo; + /* protects the list above */ + spinlock_t lock; +}; + +void lru_gen_add_mm(struct mm_struct *mm); +void lru_gen_del_mm(struct mm_struct *mm); +#ifdef CONFIG_MEMCG +void lru_gen_migrate_mm(struct mm_struct *mm); +#endif + +static inline void lru_gen_init_mm(struct mm_struct *mm) +{ + INIT_LIST_HEAD(&mm->lru_gen.list); +#ifdef CONFIG_MEMCG + mm->lru_gen.memcg = NULL; +#endif + nodes_clear(mm->lru_gen.nodes); +} + +static inline void lru_gen_use_mm(struct mm_struct *mm) +{ + /* unlikely but not a bug when racing with lru_gen_migrate_mm() */ + VM_WARN_ON(list_empty(&mm->lru_gen.list)); + + if (!(current->flags & PF_KTHREAD) && !nodes_full(mm->lru_gen.nodes)) + nodes_setall(mm->lru_gen.nodes); +} + +#else /* !CONFIG_LRU_GEN */ + +static inline void lru_gen_add_mm(struct mm_struct *mm) +{ +} + +static inline void lru_gen_del_mm(struct mm_struct *mm) +{ +} + +#ifdef CONFIG_MEMCG +static inline void lru_gen_migrate_mm(struct mm_struct *mm) +{ +} +#endif + +static inline void lru_gen_init_mm(struct mm_struct *mm) +{ +} + +static inline void lru_gen_use_mm(struct mm_struct *mm) +{ +} + +#endif /* CONFIG_LRU_GEN */ + struct mmu_gather; extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end); diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index f72b488b790b8ad2b9f2f668847e6e32b91115ed..b149f792e3ea2d50e994896797f7a07ba21824a9 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -277,6 +277,206 @@ enum lruvec_flags { */ }; +#endif /* !__GENERATING_BOUNDS_H */ + +/* + * Evictable pages are divided into multiple generations. The youngest and the + * oldest generation numbers, max_seq and min_seq, are monotonically increasing. + * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An + * offset within MAX_NR_GENS, gen, indexes the LRU list of the corresponding + * generation. The gen counter in page->flags stores gen+1 while a page is on + * one of lrugen->lists[]. Otherwise it stores 0. + * + * A page is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this page over to the + * eviction. The first check takes care of the accessed bit set on the initial + * fault; the second check makes sure this page hasn't been used since then. + * This process, AKA second chance, requires a minimum of two generations, + * hence MIN_NR_GENS. And to maintain ABI compatibility with the active/inactive + * LRU, these two generations are considered active; the rest of generations, if + * they exist, are considered inactive. See lru_gen_is_active(). PG_active is + * always cleared while a page is on one of lrugen->lists[] so that the aging + * needs not to worry about it. And it's set again when a page considered active + * is isolated for non-reclaiming purposes, e.g., migration. See + * lru_gen_add_page() and lru_gen_del_page(). + * + * MAX_NR_GENS is set to 4 so that the multi-gen LRU can support twice of the + * categories of the active/inactive LRU when keeping track of accesses through + * page tables. It requires order_base_2(MAX_NR_GENS+1) bits in page->flags. + */ +#define MIN_NR_GENS 2U +#define MAX_NR_GENS 4U + +/* + * Each generation is divided into multiple tiers. Tiers represent different + * ranges of numbers of accesses through file descriptors. A page accessed N + * times through file descriptors is in tier order_base_2(N). A page in the + * first tier (N=0,1) is marked by PG_referenced unless it was faulted in + * though page tables or read ahead. A page in any other tier (N>1) is marked + * by PG_referenced and PG_workingset. + * + * In contrast to moving across generations which requires the LRU lock, moving + * across tiers only requires operations on page->flags and therefore has a + * negligible cost in the buffered access path. In the eviction path, + * comparisons of refaulted/(evicted+protected) from the first tier and the + * rest infer whether pages accessed multiple times through file descriptors + * are statistically hot and thus worth protecting. + * + * MAX_NR_TIERS is set to 4 so that the multi-gen LRU can support twice of the + * categories of the active/inactive LRU when keeping track of accesses through + * file descriptors. It requires MAX_NR_TIERS-2 additional bits in page->flags. + */ +#define MAX_NR_TIERS 4U + +#ifndef __GENERATING_BOUNDS_H + +struct lruvec; +struct page_vma_mapped_walk; + +#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) +#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) +#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) + +#ifdef CONFIG_LRU_GEN + +enum { + LRU_GEN_ANON, + LRU_GEN_FILE, +}; + +enum { + LRU_GEN_CORE, + LRU_GEN_MM_WALK, + LRU_GEN_NONLEAF_YOUNG, + NR_LRU_GEN_CAPS +}; + +#define MIN_LRU_BATCH BITS_PER_LONG +#define MAX_LRU_BATCH (MIN_LRU_BATCH * 128) + +/* whether to keep historical stats from evicted generations */ +#ifdef CONFIG_LRU_GEN_STATS +#define NR_HIST_GENS MAX_NR_GENS +#else +#define NR_HIST_GENS 1U +#endif + +/* + * The youngest generation number is stored in max_seq for both anon and file + * types as they are aged on an equal footing. The oldest generation numbers are + * stored in min_seq[] separately for anon and file types as clean file pages + * can be evicted regardless of swap constraints. + * + * Normally anon and file min_seq are in sync. But if swapping is constrained, + * e.g., out of swap space, file min_seq is allowed to advance and leave anon + * min_seq behind. + */ +struct lru_gen_struct { + /* the aging increments the youngest generation number */ + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ + unsigned long min_seq[ANON_AND_FILE]; + /* the birth time of each generation in jiffies */ + unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists */ + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the sizes of the above lists */ + unsigned long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the exponential moving average of refaulted */ + unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; + /* the exponential moving average of evicted+protected */ + unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; + /* the first tier doesn't need protection, hence the minus one */ + unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; + /* can be modified without holding the LRU lock */ + atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + /* whether the multi-gen LRU is enabled */ + bool enabled; +}; + +enum { + MM_PTE_TOTAL, /* total leaf entries */ + MM_PTE_OLD, /* old leaf entries */ + MM_PTE_YOUNG, /* young leaf entries */ + MM_PMD_TOTAL, /* total non-leaf entries */ + MM_PMD_FOUND, /* non-leaf entries found in Bloom filters */ + MM_PMD_ADDED, /* non-leaf entries added to Bloom filters */ + NR_MM_STATS +}; + +/* mnemonic codes for the mm stats above */ +#define MM_STAT_CODES "toydfa" + +/* double-buffering Bloom filters */ +#define NR_BLOOM_FILTERS 2 + +struct lru_gen_mm_state { + /* set to max_seq after each iteration */ + unsigned long seq; + /* where the current iteration starts (inclusive) */ + struct list_head *head; + /* where the last iteration ends (exclusive) */ + struct list_head *tail; + /* to wait for the last page table walker to finish */ + struct wait_queue_head wait; + /* Bloom filters flip after each iteration */ + unsigned long *filters[NR_BLOOM_FILTERS]; + /* the mm stats for debugging */ + unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; + /* the number of concurrent page table walkers */ + int nr_walkers; +}; + +struct lru_gen_mm_walk { + /* the lruvec under reclaim */ + struct lruvec *lruvec; + /* unstable max_seq from lru_gen_struct */ + unsigned long max_seq; + /* the next address within an mm to scan */ + unsigned long next_addr; + /* to batch page table entries */ + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)]; + /* to batch promoted pages */ + int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* to batch the mm stats */ + int mm_stats[NR_MM_STATS]; + /* total batched items */ + int batched; + bool can_swap; + bool full_scan; +}; + +void lru_gen_init_lruvec(struct lruvec *lruvec); +void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + +#ifdef CONFIG_MEMCG +void lru_gen_init_memcg(struct mem_cgroup *memcg); +void lru_gen_exit_memcg(struct mem_cgroup *memcg); +#endif + +#else /* !CONFIG_LRU_GEN */ + +static inline void lru_gen_init_lruvec(struct lruvec *lruvec) +{ +} + +static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +{ +} + +#ifdef CONFIG_MEMCG +static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) +{ +} + +static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) +{ +} +#endif + +#endif /* CONFIG_LRU_GEN */ + struct lruvec { struct list_head lists[NR_LRU_LISTS]; /* @@ -292,9 +492,16 @@ struct lruvec { unsigned long refaults[ANON_AND_FILE]; /* Various lruvec state flags (enum lruvec_flags) */ unsigned long flags; +#ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ + struct lru_gen_struct lrugen; + /* to concurrently iterate lru_gen_mm_list */ + struct lru_gen_mm_state mm_state; +#endif #ifdef CONFIG_MEMCG struct pglist_data *pgdat; #endif + ANDROID_VENDOR_DATA(1); }; /* Isolate unmapped pages */ @@ -340,6 +547,11 @@ struct per_cpu_pageset { #endif }; +struct per_cpu_pageset_ext { + spinlock_t lock; /* Protects pageset.pcp.lists field */ + struct per_cpu_pageset pageset; +}; + struct per_cpu_nodestat { s8 stat_threshold; s8 vm_node_stat_diff[NR_VM_NODE_STAT_ITEMS]; @@ -827,6 +1039,11 @@ typedef struct pglist_data { unsigned long flags; +#ifdef CONFIG_LRU_GEN + /* kswap mm walk data */ + struct lru_gen_mm_walk mm_walk; +#endif + ZONE_PADDING(_pad2_) /* Per-node vmstats */ diff --git a/include/linux/module.h b/include/linux/module.h index 4fa2f7de56e61440eaf2999eac0b1f17da234b6e..c5c3ce08f64664615b811a319d16fa5ba1ef7c06 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -293,7 +293,8 @@ extern typeof(name) __mod_##type##__##name##_device_table \ * files require multiple MODULE_FIRMWARE() specifiers */ #define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) -#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) +#define _MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) +#define MODULE_IMPORT_NS(ns) _MODULE_IMPORT_NS(ns) struct notifier_block; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index db2eaff77f41aa10e16c619a6c2de632fa11637a..aac07940de09d7b503d23f74d5adfe6e59873b7b 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1083,7 +1083,6 @@ struct nand_manufacturer { * @lock: Lock protecting the suspended field. Also used to serialize accesses * to the NAND device * @suspended: Set to 1 when the device is suspended, 0 when it's not - * @resume_wq: wait queue to sleep if rawnand is in suspended state. * @cur_cs: Currently selected target. -1 means no target selected, otherwise we * should always have cur_cs >= 0 && cur_cs < nanddev_ntargets(). * NAND Controller drivers should not modify this value, but they're @@ -1136,7 +1135,6 @@ struct nand_chip { /* Internals */ struct mutex lock; unsigned int suspended : 1; - wait_queue_head_t resume_wq; int cur_cs; int read_retries; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3639d7ae68e84e6cbab8a99a3a07d22c114d3e1b..9dadd780a2a67082ab49188d40745761edd150f5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4027,8 +4027,7 @@ void netdev_run_todo(void); */ static inline void dev_put(struct net_device *dev) { - if (dev) - this_cpu_dec(*dev->pcpu_refcnt); + this_cpu_dec(*dev->pcpu_refcnt); } /** @@ -4039,8 +4038,7 @@ static inline void dev_put(struct net_device *dev) */ static inline void dev_hold(struct net_device *dev) { - if (dev) - this_cpu_inc(*dev->pcpu_refcnt); + this_cpu_inc(*dev->pcpu_refcnt); } /* Carrier loss detection, dial on demand. The functions netif_carrier_on diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index ac398e143c9a1cee72a8b59eacb0a7a148b142b1..89fe4e3592f9309d5853657903282e92c07479d1 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h @@ -486,6 +486,7 @@ static inline int num_node_state(enum node_states state) #define first_online_node 0 #define first_memory_node 0 #define next_online_node(nid) (MAX_NUMNODES) +#define next_memory_node(nid) (MAX_NUMNODES) #define nr_node_ids 1U #define nr_online_nodes 1U diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h index 7d4ec26d8a3ed284e30b0508a9f6082e2fb596dd..c1946cdb845fec775097fb10e2747e543bf70b88 100644 --- a/include/linux/page-flags-layout.h +++ b/include/linux/page-flags-layout.h @@ -21,16 +21,17 @@ #elif MAX_NR_ZONES <= 8 #define ZONES_SHIFT 3 #else -#error ZONES_SHIFT -- too many zones configured adjust calculation +#error ZONES_SHIFT "Too many zones configured" #endif +#define ZONES_WIDTH ZONES_SHIFT + #ifdef CONFIG_SPARSEMEM #include - -/* SECTION_SHIFT #bits space required to store a section # */ #define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS) - -#endif /* CONFIG_SPARSEMEM */ +#else +#define SECTIONS_SHIFT 0 +#endif #ifndef BUILD_VDSO32_64 /* @@ -54,17 +55,29 @@ #define SECTIONS_WIDTH 0 #endif -#define ZONES_WIDTH ZONES_SHIFT - -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS +#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_SHIFT \ + <= BITS_PER_LONG - NR_PAGEFLAGS #define NODES_WIDTH NODES_SHIFT -#else -#ifdef CONFIG_SPARSEMEM_VMEMMAP +#elif defined(CONFIG_SPARSEMEM_VMEMMAP) #error "Vmemmap: No space for nodes field in page flags" -#endif +#else #define NODES_WIDTH 0 #endif +/* + * Note that this #define MUST have a value so that it can be tested with + * the IS_ENABLED() macro. + */ +#if NODES_SHIFT != 0 && NODES_WIDTH == 0 +#define NODE_NOT_IN_PAGE_FLAGS 1 +#endif + +#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS) +#define KASAN_TAG_WIDTH 8 +#else +#define KASAN_TAG_WIDTH 0 +#endif + #ifdef CONFIG_NUMA_BALANCING #define LAST__PID_SHIFT 8 #define LAST__PID_MASK ((1 << LAST__PID_SHIFT)-1) @@ -77,36 +90,20 @@ #define LAST_CPUPID_SHIFT 0 #endif -#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS) -#define KASAN_TAG_WIDTH 8 -#else -#define KASAN_TAG_WIDTH 0 -#endif - -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT+KASAN_TAG_WIDTH \ - <= BITS_PER_LONG - NR_PAGEFLAGS +#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ + KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT #else #define LAST_CPUPID_WIDTH 0 #endif -#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH+LAST_CPUPID_WIDTH+KASAN_TAG_WIDTH \ - > BITS_PER_LONG - NR_PAGEFLAGS -#error "Not enough bits in page flags" -#endif - -/* - * We are going to use the flags for the page to node mapping if its in - * there. This includes the case where there is no node, so it is implicit. - * Note that this #define MUST have a value so that it can be tested with - * the IS_ENABLED() macro. - */ -#if !(NODES_WIDTH > 0 || NODES_SHIFT == 0) -#define NODE_NOT_IN_PAGE_FLAGS 1 +#if LAST_CPUPID_SHIFT != 0 && LAST_CPUPID_WIDTH == 0 +#define LAST_CPUPID_NOT_IN_PAGE_FLAGS #endif -#if defined(CONFIG_NUMA_BALANCING) && LAST_CPUPID_WIDTH == 0 -#define LAST_CPUPID_NOT_IN_PAGE_FLAGS +#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ + KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS +#error "Not enough bits in page flags" #endif #endif diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 1c5027fdc2a9e4b7a29a47247fc80cb57a188a7a..1d2a9a3103da7f3d8ddac285db7619fcc3ea4b44 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -132,7 +132,7 @@ enum pageflags { #ifdef CONFIG_MEMORY_FAILURE PG_hwpoison, /* hardware poisoned page. Don't touch */ #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) PG_young, PG_idle, #endif @@ -440,7 +440,7 @@ PAGEFLAG_FALSE(HWPoison) #define __PG_HWPOISON 0 #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) TESTPAGEFLAG(Young, young, PF_ANY) SETPAGEFLAG(Young, young, PF_ANY) TESTCLEARFLAG(Young, young, PF_ANY) @@ -803,7 +803,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) 1UL << PG_private | 1UL << PG_private_2 | \ 1UL << PG_writeback | 1UL << PG_reserved | \ 1UL << PG_slab | 1UL << PG_active | \ - 1UL << PG_unevictable | __PG_MLOCKED) + 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) /* * Flags checked when a page is prepped for return by the page allocator. @@ -814,7 +814,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) * alloc-free cycle to prevent from reusing the page. */ #define PAGE_FLAGS_CHECK_AT_PREP \ - (((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) + ((((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) #define PAGE_FLAGS_PRIVATE \ (1UL << PG_private | 1UL << PG_private_2) diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index cd45c1927d903df99b1da91fc0b11c1d3b3bfa95..2e64843c1468988a3819f9a094886ec3a81b8a1c 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -20,12 +20,10 @@ enum page_ext_flags { PAGE_EXT_OWNER, PAGE_EXT_OWNER_ALLOCATED, #if defined(CONFIG_PAGE_PINNER) - /* page refcount was increased by GUP or follow_page(FOLL_GET) */ - PAGE_EXT_GET, /* page migration failed */ PAGE_EXT_PINNER_MIGRATION_FAILED, #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) PAGE_EXT_YOUNG, PAGE_EXT_IDLE, #endif diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h index 1e894d34bdceb2a91318bd1ea7796a17deeddf8b..d8a6aecf99cb9f0fc63bc49126b06fe5936d82e4 100644 --- a/include/linux/page_idle.h +++ b/include/linux/page_idle.h @@ -6,7 +6,7 @@ #include #include -#ifdef CONFIG_IDLE_PAGE_TRACKING +#ifdef CONFIG_PAGE_IDLE_FLAG #ifdef CONFIG_64BIT static inline bool page_is_young(struct page *page) @@ -106,7 +106,7 @@ static inline void clear_page_idle(struct page *page) } #endif /* CONFIG_64BIT */ -#else /* !CONFIG_IDLE_PAGE_TRACKING */ +#else /* !CONFIG_PAGE_IDLE_FLAG */ static inline bool page_is_young(struct page *page) { @@ -135,6 +135,6 @@ static inline void clear_page_idle(struct page *page) { } -#endif /* CONFIG_IDLE_PAGE_TRACKING */ +#endif /* CONFIG_PAGE_IDLE_FLAG */ #endif /* _LINUX_MM_PAGE_IDLE_H */ diff --git a/include/linux/page_pinner.h b/include/linux/page_pinner.h index ba14d7636dc001666d5d97b2c9c228297270279f..4d574d1ced59c11ac377d15ee489b7d46eed59d0 100644 --- a/include/linux/page_pinner.h +++ b/include/linux/page_pinner.h @@ -9,34 +9,14 @@ extern struct static_key_false page_pinner_inited; extern struct static_key_true failure_tracking; extern struct page_ext_operations page_pinner_ops; -extern void __reset_page_pinner(struct page *page, unsigned int order, bool free); -extern void __set_page_pinner(struct page *page, unsigned int order); -extern void __dump_page_pinner(struct page *page); -void __page_pinner_migration_failed(struct page *page); -void __page_pinner_mark_migration_failed_pages(struct list_head *page_list); - -static inline void reset_page_pinner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_pinner_inited)) - __reset_page_pinner(page, order, false); -} +extern void __free_page_pinner(struct page *page, unsigned int order); +void __page_pinner_failure_detect(struct page *page); +void __page_pinner_put_page(struct page *page); static inline void free_page_pinner(struct page *page, unsigned int order) { if (static_branch_unlikely(&page_pinner_inited)) - __reset_page_pinner(page, order, true); -} - -static inline void set_page_pinner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_pinner_inited)) - __set_page_pinner(page, order); -} - -static inline void dump_page_pinner(struct page *page) -{ - if (static_branch_unlikely(&page_pinner_inited)) - __dump_page_pinner(page); + __free_page_pinner(page, order); } static inline void page_pinner_put_page(struct page *page) @@ -44,7 +24,7 @@ static inline void page_pinner_put_page(struct page *page) if (!static_branch_unlikely(&failure_tracking)) return; - __page_pinner_migration_failed(page); + __page_pinner_put_page(page); } static inline void page_pinner_failure_detect(struct page *page) @@ -52,37 +32,17 @@ static inline void page_pinner_failure_detect(struct page *page) if (!static_branch_unlikely(&failure_tracking)) return; - __page_pinner_migration_failed(page); -} - -static inline void page_pinner_mark_migration_failed_pages(struct list_head *page_list) -{ - if (!static_branch_unlikely(&failure_tracking)) - return; - - __page_pinner_mark_migration_failed_pages(page_list); + __page_pinner_failure_detect(page); } #else -static inline void reset_page_pinner(struct page *page, unsigned int order) -{ -} static inline void free_page_pinner(struct page *page, unsigned int order) { } -static inline void set_page_pinner(struct page *page, unsigned int order) -{ -} -static inline void dump_page_pinner(struct page *page) -{ -} static inline void page_pinner_put_page(struct page *page) { } static inline void page_pinner_failure_detect(struct page *page) { } -static inline void page_pinner_mark_migration_failed_pages(struct list_head *page_list) -{ -} #endif /* CONFIG_PAGE_PINNER */ #endif /* __LINUX_PAGE_PINNER_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 4d2c9a3c83bd35933f9eb0be4a9430e64c50e135..605ac0bd908a643288a8e6b409d09fd508d2ef2f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -647,7 +647,6 @@ struct pci_bus { struct bin_attribute *legacy_io; /* Legacy I/O for this bus */ struct bin_attribute *legacy_mem; /* Legacy mem */ unsigned int is_added:1; - unsigned int unsafe_warn:1; /* warned about RW1C config write */ ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index eb724505951f83872f7759087efdb239418bc996..ab7287e59c070629347e29fff71bc5f0a4534124 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -194,7 +194,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, #endif #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) @@ -215,7 +215,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, BUILD_BUG(); return 0; } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH @@ -241,6 +241,19 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif +#ifndef arch_has_hw_pte_young +/* + * Return whether the accessed bit is supported on the local CPU. + * + * This stub assumes accessing through an old PTE triggers a page fault. + * Architectures that automatically set the access bit should overwrite it. + */ +static inline bool arch_has_hw_pte_young(void) +{ + return false; +} +#endif + #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long address, diff --git a/include/linux/pstore.h b/include/linux/pstore.h index e97a8188f0fd8bcac0e0edd8a5570c7aa00edf9d..eb93a54cff31fa21d49b77012f14888b51e01bca 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -87,7 +87,7 @@ struct pstore_record { * @owner: module which is responsible for this backend driver * @name: name of the backend driver * - * @buf_lock: spinlock to serialize access to @buf + * @buf_lock: semaphore to serialize access to @buf * @buf: preallocated crash dump buffer * @bufsize: size of @buf available for crash dump bytes (must match * smallest number of bytes available for writing to a @@ -178,7 +178,7 @@ struct pstore_info { struct module *owner; const char *name; - spinlock_t buf_lock; + struct semaphore buf_lock; char *buf; size_t bufsize; diff --git a/include/linux/sched.h b/include/linux/sched.h index 637d25c313740755dcddbdb649f7f1d6ca8c4b02..df2259962ba1e2a8784dd6ddcd06c41f9a53b2ce 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -835,6 +835,10 @@ struct task_struct { #ifdef CONFIG_MEMCG unsigned in_user_fault:1; #endif +#ifdef CONFIG_LRU_GEN + /* whether the LRU algorithm may apply to this access */ + unsigned in_lru_fault:1; +#endif #ifdef CONFIG_COMPAT_BRK unsigned brk_randomized:1; #endif diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 52004d800c9351013d421760554d4338888ac0d6..0a361d4b58de6859e4e531620f67a5b9c5fac90b 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -472,8 +472,6 @@ extern void uart_handle_cts_change(struct uart_port *uport, extern void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag); -void uart_xchar_out(struct uart_port *uport, int offset); - #ifdef CONFIG_MAGIC_SYSRQ_SERIAL #define SYSRQ_TIMEOUT (HZ * 5) diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index b1af87330f863e1aaa346edab61996504d601948..cf27b080e148216905d65c8be80630e2fb624784 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -618,7 +618,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, static inline struct ti_sci_resource * devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev, - u32 dev_id, u32 sub_type) + u32 dev_id, u32 sub_type); { return ERR_PTR(-EINVAL); } diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 6d9d1520612b87e07dedff9875c49f302aa70075..b998e4b7369129328ad616831e1f73245ca71fef 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -603,8 +603,6 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) return -EBADMSG; - if (len > SIZE_MAX / sizeof(*p)) - return -EBADMSG; p = xdr_inline_decode(xdr, len * sizeof(*p)); if (unlikely(!p)) return -EBADMSG; diff --git a/include/linux/swap.h b/include/linux/swap.h index beda0a50d0b91961acf510d12cab230dfd0cbce6..dfdf026dc54d11e2fea39b32efcdc95f90c168e7 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -130,6 +130,10 @@ union swap_header { */ struct reclaim_state { unsigned long reclaimed_slab; +#ifdef CONFIG_LRU_GEN + /* per-thread mm walk data */ + struct lru_gen_mm_walk *mm_walk; +#endif }; #ifdef __KERNEL__ @@ -281,6 +285,7 @@ struct swap_info_struct { */ struct work_struct discard_work; /* discard worker */ struct swap_cluster_list discard_clusters; /* discard clusters list */ + ANDROID_VENDOR_DATA(1); struct plist_node avail_lists[]; /* * entries in swap_avail_heads, one * entry per node. @@ -350,6 +355,7 @@ extern void lru_add_drain_cpu(int cpu); extern void lru_add_drain_cpu_zone(struct zone *zone); extern void lru_add_drain_all(void); extern void rotate_reclaimable_page(struct page *page); +extern void activate_page(struct page *page); extern void deactivate_file_page(struct page *page); extern void deactivate_page(struct page *page); extern void mark_page_lazyfree(struct page *page); diff --git a/include/linux/swap_slots.h b/include/linux/swap_slots.h index 347f1a30419059a577157e3a2fd68979db294dfd..c4dc91ebbaa8771a997b15b93cc42f5f68bb680b 100644 --- a/include/linux/swap_slots.h +++ b/include/linux/swap_slots.h @@ -19,6 +19,7 @@ struct swap_slots_cache { spinlock_t free_lock; /* protects slots_ret, n_ret */ swp_entry_t *slots_ret; int n_ret; + ANDROID_VENDOR_DATA(1); }; void disable_swap_slots_cache_lock(void); diff --git a/include/linux/wait.h b/include/linux/wait.h index 9b8b0833100a0b736699f429ddb9f568f5d3f0fd..5dfae54f88fde27e1b45d88bf317af3843f34c5b 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -219,6 +219,7 @@ void __wake_up_pollfree(struct wait_queue_head *wq_head); #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL) #define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE) +#define wake_up_sync(x) __wake_up_sync((x), TASK_NORMAL) /* * Wakeup macros to be used to report events to the targets. diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 4d8589244dc75acb2d8efbea4521c2a67d0008c4..b1c7172869939c2d0bfb2f08f11d773e1ed1028b 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -197,8 +197,7 @@ struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr); struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, struct sockaddr_vm *dst); void vsock_remove_sock(struct vsock_sock *vsk); -void vsock_for_each_connected_socket(struct vsock_transport *transport, - void (*fn)(struct sock *sk)); +void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)); int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk); bool vsock_find_cid(unsigned int cid); diff --git a/include/net/esp.h b/include/net/esp.h index 90cd02ff77ef67f7f65e2c53127c4510c23bd4a9..9c5637d41d95168052686caf7b3ff51b517e6b9b 100644 --- a/include/net/esp.h +++ b/include/net/esp.h @@ -4,8 +4,6 @@ #include -#define ESP_SKB_FRAG_MAXSIZE (PAGE_SIZE << SKB_FRAG_PAGE_ORDER) - struct ip_esp_hdr; static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb) diff --git a/include/net/sock.h b/include/net/sock.h index f458d74d3623b924d2750396eac2fa6c8bc936d9..fd78d61b8fec2649e3cee9057db88975e62a3368 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2683,7 +2683,6 @@ extern int sysctl_optmem_max; extern __u32 sysctl_wmem_default; extern __u32 sysctl_rmem_default; -#define SKB_FRAG_PAGE_ORDER get_order(32768) DECLARE_STATIC_KEY_FALSE(net_high_order_alloc_disable_key); static inline int sk_get_wmem0(const struct sock *sk, const struct proto *proto) diff --git a/include/net/udp.h b/include/net/udp.h index 4017f257628f34301d4a3571804b6e662453949e..435cc009e6eaaa79d376d3d71156ed5d3186534b 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -467,7 +467,6 @@ void udp_init(void); DECLARE_STATIC_KEY_FALSE(udp_encap_needed_key); void udp_encap_enable(void); -void udp_encap_disable(void); #if IS_ENABLED(CONFIG_IPV6) DECLARE_STATIC_KEY_FALSE(udpv6_encap_needed_key); void udpv6_encap_enable(void); diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 24ece06bad9eff61612d89f618d389ae0e2f03b8..2ea453dac87624ba1612fe008f08b1c7de9c0b1e 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -177,8 +177,9 @@ static inline void udp_tunnel_encap_enable(struct socket *sock) #if IS_ENABLED(CONFIG_IPV6) if (sock->sk->sk_family == PF_INET6) ipv6_stub->udpv6_encap_enable(); + else #endif - udp_encap_enable(); + udp_encap_enable(); } #define UDP_TUNNEL_NIC_MAX_TABLES 4 diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 0dd9dbc2ae21cda657999210c1c06350961cff00..d54a6cb496dac301dac853df556fe5f76b239d55 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -206,6 +206,7 @@ struct scsi_device { unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device * creation time */ unsigned ignore_media_change:1; /* Ignore MEDIA CHANGE on resume */ + unsigned silence_suspend:1; /* Do not print runtime PM related messages */ bool offline_already; /* Device offline message logged */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 5ffc2efedd9f83f9d4f2ab88f83e21a5bea6b9e4..2336bf9243e185cd0e8b84b4afe3add26faf59b6 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -398,8 +398,6 @@ struct snd_pcm_runtime { wait_queue_head_t tsleep; /* transfer sleep */ struct fasync_struct *fasync; bool stop_operating; /* sync_stop will be called */ - struct mutex buffer_mutex; /* protect for buffer changes */ - atomic_t buffer_accessing; /* >0: in r/w operation, <0: blocked */ /* -- private section -- */ void *private_data; diff --git a/include/trace/events/damon.h b/include/trace/events/damon.h new file mode 100644 index 0000000000000000000000000000000000000000..c79f1d4c39afe754a18d3c646a0bd262e531eb83 --- /dev/null +++ b/include/trace/events/damon.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM damon + +#if !defined(_TRACE_DAMON_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_DAMON_H + +#include +#include +#include + +TRACE_EVENT(damon_aggregated, + + TP_PROTO(struct damon_target *t, unsigned int target_id, + struct damon_region *r, unsigned int nr_regions), + + TP_ARGS(t, target_id, r, nr_regions), + + TP_STRUCT__entry( + __field(unsigned long, target_id) + __field(unsigned int, nr_regions) + __field(unsigned long, start) + __field(unsigned long, end) + __field(unsigned int, nr_accesses) + __field(unsigned int, age) + ), + + TP_fast_assign( + __entry->target_id = target_id; + __entry->nr_regions = nr_regions; + __entry->start = r->ar.start; + __entry->end = r->ar.end; + __entry->nr_accesses = r->nr_accesses; + __entry->age = r->age; + ), + + TP_printk("target_id=%lu nr_regions=%u %lu-%lu: %u %u", + __entry->target_id, __entry->nr_regions, + __entry->start, __entry->end, + __entry->nr_accesses, __entry->age) +); + +#endif /* _TRACE_DAMON_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 4973265655a7fb324d20943fef497c046457c252..70ae5497b73a6d3da4ec9543aa34c6cebf073a2e 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -95,17 +95,6 @@ TRACE_DEFINE_ENUM(ES_REFERENCED_B); { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"}, \ { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"}) -TRACE_DEFINE_ENUM(EXT4_FC_REASON_XATTR); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_CROSS_RENAME); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_NOMEM); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_SWAP_BOOT); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_RESIZE); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_RENAME_DIR); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_FALLOC_RANGE); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_INODE_JOURNAL_DATA); -TRACE_DEFINE_ENUM(EXT4_FC_REASON_MAX); - #define show_fc_reason(reason) \ __print_symbolic(reason, \ { EXT4_FC_REASON_XATTR, "XATTR"}, \ @@ -2910,50 +2899,41 @@ TRACE_EVENT(ext4_fc_commit_stop, #define FC_REASON_NAME_STAT(reason) \ show_fc_reason(reason), \ - __entry->fc_ineligible_rc[reason] + __entry->sbi->s_fc_stats.fc_ineligible_reason_count[reason] TRACE_EVENT(ext4_fc_stats, - TP_PROTO(struct super_block *sb), + TP_PROTO(struct super_block *sb), - TP_ARGS(sb), + TP_ARGS(sb), - TP_STRUCT__entry( - __field(dev_t, dev) - __array(unsigned int, fc_ineligible_rc, EXT4_FC_REASON_MAX) - __field(unsigned long, fc_commits) - __field(unsigned long, fc_ineligible_commits) - __field(unsigned long, fc_numblks) - ), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(struct ext4_sb_info *, sbi) + __field(int, count) + ), - TP_fast_assign( - int i; + TP_fast_assign( + __entry->dev = sb->s_dev; + __entry->sbi = EXT4_SB(sb); + ), + + TP_printk("dev %d:%d fc ineligible reasons:\n" + "%s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d, %s:%d; " + "num_commits:%ld, ineligible: %ld, numblks: %ld", + MAJOR(__entry->dev), MINOR(__entry->dev), + FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), + FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), + FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_NOMEM), + FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), + FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), + FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), + FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA), + __entry->sbi->s_fc_stats.fc_num_commits, + __entry->sbi->s_fc_stats.fc_ineligible_commits, + __entry->sbi->s_fc_stats.fc_numblks) - __entry->dev = sb->s_dev; - for (i = 0; i < EXT4_FC_REASON_MAX; i++) { - __entry->fc_ineligible_rc[i] = - EXT4_SB(sb)->s_fc_stats.fc_ineligible_reason_count[i]; - } - __entry->fc_commits = EXT4_SB(sb)->s_fc_stats.fc_num_commits; - __entry->fc_ineligible_commits = - EXT4_SB(sb)->s_fc_stats.fc_ineligible_commits; - __entry->fc_numblks = EXT4_SB(sb)->s_fc_stats.fc_numblks; - ), - - TP_printk("dev %d,%d fc ineligible reasons:\n" - "%s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u, %s:%u " - "num_commits:%lu, ineligible: %lu, numblks: %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - FC_REASON_NAME_STAT(EXT4_FC_REASON_XATTR), - FC_REASON_NAME_STAT(EXT4_FC_REASON_CROSS_RENAME), - FC_REASON_NAME_STAT(EXT4_FC_REASON_JOURNAL_FLAG_CHANGE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_NOMEM), - FC_REASON_NAME_STAT(EXT4_FC_REASON_SWAP_BOOT), - FC_REASON_NAME_STAT(EXT4_FC_REASON_RESIZE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_RENAME_DIR), - FC_REASON_NAME_STAT(EXT4_FC_REASON_FALLOC_RANGE), - FC_REASON_NAME_STAT(EXT4_FC_REASON_INODE_JOURNAL_DATA), - __entry->fc_commits, __entry->fc_ineligible_commits, - __entry->fc_numblks) ); #define DEFINE_TRACE_DENTRY_EVENT(__type) \ diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h index d26bfc4951291472c8d39042e6ce7bae1baddf89..12d76932e390ed8fd00b260a2765861bd30c1cdb 100644 --- a/include/trace/events/mmflags.h +++ b/include/trace/events/mmflags.h @@ -83,7 +83,7 @@ #define IF_HAVE_PG_HWPOISON(flag,string) #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) #define IF_HAVE_PG_IDLE(flag,string) ,{1UL << flag, string} #else #define IF_HAVE_PG_IDLE(flag,string) diff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h index 8fd1babae761b901bc6627bb45e85f3631f4fa48..e1735fe7c76afd0900294a42c3f1e0e8b22998ce 100644 --- a/include/trace/events/pagemap.h +++ b/include/trace/events/pagemap.h @@ -27,24 +27,21 @@ TRACE_EVENT(mm_lru_insertion, - TP_PROTO( - struct page *page, - int lru - ), + TP_PROTO(struct page *page), - TP_ARGS(page, lru), + TP_ARGS(page), TP_STRUCT__entry( __field(struct page *, page ) __field(unsigned long, pfn ) - __field(int, lru ) + __field(enum lru_list, lru ) __field(unsigned long, flags ) ), TP_fast_assign( __entry->page = page; __entry->pfn = page_to_pfn(page); - __entry->lru = lru; + __entry->lru = page_lru(page); __entry->flags = trace_pagemap_flags(page); ), diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index 4a3ab0ed6e0629d48c61c50b49cbdcb5d4638dea..e70c90116edaed0f14d3df2c7fa4cb98cec4eb22 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -83,15 +83,12 @@ enum rxrpc_call_trace { rxrpc_call_error, rxrpc_call_got, rxrpc_call_got_kernel, - rxrpc_call_got_timer, rxrpc_call_got_userid, rxrpc_call_new_client, rxrpc_call_new_service, rxrpc_call_put, rxrpc_call_put_kernel, rxrpc_call_put_noqueue, - rxrpc_call_put_notimer, - rxrpc_call_put_timer, rxrpc_call_put_userid, rxrpc_call_queued, rxrpc_call_queued_ref, @@ -281,15 +278,12 @@ enum rxrpc_tx_point { EM(rxrpc_call_error, "*E*") \ EM(rxrpc_call_got, "GOT") \ EM(rxrpc_call_got_kernel, "Gke") \ - EM(rxrpc_call_got_timer, "GTM") \ EM(rxrpc_call_got_userid, "Gus") \ EM(rxrpc_call_new_client, "NWc") \ EM(rxrpc_call_new_service, "NWs") \ EM(rxrpc_call_put, "PUT") \ EM(rxrpc_call_put_kernel, "Pke") \ - EM(rxrpc_call_put_noqueue, "PnQ") \ - EM(rxrpc_call_put_notimer, "PnT") \ - EM(rxrpc_call_put_timer, "PTM") \ + EM(rxrpc_call_put_noqueue, "PNQ") \ EM(rxrpc_call_put_userid, "Pus") \ EM(rxrpc_call_queued, "QUE") \ EM(rxrpc_call_queued_ref, "QUR") \ diff --git a/include/trace/hooks/avc.h b/include/trace/hooks/avc.h index 2c76e02fc3c52947c46f7275ae7767c27eb7e734..1d205382e6df4e82b1fdd3fa98d4ce1b88225622 100644 --- a/include/trace/hooks/avc.h +++ b/include/trace/hooks/avc.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_AVC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_AVC_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/binder.h b/include/trace/hooks/binder.h index ffba8746e58ba8be12ea08ff219f79cd1721ec13..d7419ef64de21c75a96c731ac78416df45aa6d83 100644 --- a/include/trace/hooks/binder.h +++ b/include/trace/hooks/binder.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_BINDER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_BINDER_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/block.h b/include/trace/hooks/block.h index 0d9d7db39968041cd10c757558dbfdf1fe2bde82..ca9762a9be5b04b15c053e1faabb9f1209c4fad9 100644 --- a/include/trace/hooks/block.h +++ b/include/trace/hooks/block.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_BLOCK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_BLOCK_H -#include #include struct blk_mq_tag_set; diff --git a/include/trace/hooks/bug.h b/include/trace/hooks/bug.h index 685859e0eaf795a27c6460425f3d570f9a9ffd6c..3bd683e54f71370b39f89f0b59f7d9b16a0f9951 100644 --- a/include/trace/hooks/bug.h +++ b/include/trace/hooks/bug.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_BUG_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_BUG_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/cgroup.h b/include/trace/hooks/cgroup.h index 6b6d7918c51867591140eedc15108ffeedfa25e9..e33d3519d6765f3328301c32bdf95990387ab44e 100644 --- a/include/trace/hooks/cgroup.h +++ b/include/trace/hooks/cgroup.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CGROUP_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CGROUP_H -#include #include struct task_struct; diff --git a/include/trace/hooks/cpu.h b/include/trace/hooks/cpu.h index 645702996b00043ee9d5d039efd3a9771b3b08fe..b368736e7285771d3ee0c8ae0700bf85f4317cf0 100644 --- a/include/trace/hooks/cpu.h +++ b/include/trace/hooks/cpu.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CPU_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CPU_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/cpufreq.h b/include/trace/hooks/cpufreq.h index 5142cd5a07de45f0c17e2afe64cded50e803c355..70f90a3ef25c23905a99801c1d0d699e3ebbfd90 100644 --- a/include/trace/hooks/cpufreq.h +++ b/include/trace/hooks/cpufreq.h @@ -8,7 +8,6 @@ #define _TRACE_HOOK_CPUFREQ_H #include -#include #include DECLARE_HOOK(android_vh_show_max_freq, diff --git a/include/trace/hooks/cpuidle.h b/include/trace/hooks/cpuidle.h index 6d1f4bf7f1edb899ba2cb469361df95ded45eb29..c2ddabe37b00beaf2cdeba720340e441fa6150ac 100644 --- a/include/trace/hooks/cpuidle.h +++ b/include/trace/hooks/cpuidle.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_CPUIDLE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CPUIDLE_H -#include #include struct cpuidle_device; diff --git a/include/trace/hooks/cpuidle_psci.h b/include/trace/hooks/cpuidle_psci.h index 94b01eba0b4ec13d2b16d4ee2bfdffe90a782d47..eef0032c0879b6e798f8047949c2bae190fa9d9b 100644 --- a/include/trace/hooks/cpuidle_psci.h +++ b/include/trace/hooks/cpuidle_psci.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CPUIDLE_PSCI_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CPUIDLE_PSCI_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/creds.h b/include/trace/hooks/creds.h index dd877e3a1f3e46868335c52ae37883803804eb43..92b0d8e981f3a4a7659708cc0518e603383b677a 100644 --- a/include/trace/hooks/creds.h +++ b/include/trace/hooks/creds.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_CREDS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_CREDS_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/debug.h b/include/trace/hooks/debug.h index ac006d7fdd0a22fb41c2ea8bbb1af5f82483c013..90d81041a48b5461aa24bd6b5602882b505b0337 100644 --- a/include/trace/hooks/debug.h +++ b/include/trace/hooks/debug.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_DEBUG_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_DEBUG_H -#include #include #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/dtask.h b/include/trace/hooks/dtask.h index 3c49af0e65608d188c848ee3d6e5ea53d268feac..b483037e10131e35a65a651f483cdee9c9248ad5 100644 --- a/include/trace/hooks/dtask.h +++ b/include/trace/hooks/dtask.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_DTASK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_DTASK_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/epoch.h b/include/trace/hooks/epoch.h index f1c5342c822e3e782aed060f78dc9d799428d5ab..c3f018edf130616d46ab3530d4594e44318fa233 100644 --- a/include/trace/hooks/epoch.h +++ b/include/trace/hooks/epoch.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_EPOCH_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_EPOCH_H -#include #include DECLARE_HOOK(android_vh_show_suspend_epoch_val, diff --git a/include/trace/hooks/fault.h b/include/trace/hooks/fault.h index 1daf2d250f310bdb3f4e789ace0365ecc2bf3841..8803a1b3d2f08950e8a7a48e0957ba68bc6f7115 100644 --- a/include/trace/hooks/fault.h +++ b/include/trace/hooks/fault.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_FAULT_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FAULT_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/fips140.h b/include/trace/hooks/fips140.h index 3aebf61687915c4fd22bded0e0fddf5833c27d91..fd4a42c013c744e7aff914880af968c63e648334 100644 --- a/include/trace/hooks/fips140.h +++ b/include/trace/hooks/fips140.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_FIPS140_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FIPS140_H -#include #include struct crypto_aes_ctx; diff --git a/include/trace/hooks/fpsimd.h b/include/trace/hooks/fpsimd.h index a4a3ce228fff9ba3bb78dfe885182f507faaba77..3365c298e6bc179941fa1debbabe57faea36008c 100644 --- a/include/trace/hooks/fpsimd.h +++ b/include/trace/hooks/fpsimd.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_FPSIMD_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FPSIMD_H -#include #include struct task_struct; diff --git a/include/trace/hooks/fs.h b/include/trace/hooks/fs.h index 90acad536bdbafedc39623f97439daf9033703eb..1c8d692be3afa24e1df12d08fb100adf569b38c9 100644 --- a/include/trace/hooks/fs.h +++ b/include/trace/hooks/fs.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_FS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FS_H -#include #include DECLARE_HOOK(android_vh_ep_create_wakeup_source, TP_PROTO(char *name, int len), diff --git a/include/trace/hooks/ftrace_dump.h b/include/trace/hooks/ftrace_dump.h index ed3be8a0d74b15c2a497b545e5730da63a98b706..b63d9c80942607a107b1823a26c905a8412ec57a 100644 --- a/include/trace/hooks/ftrace_dump.h +++ b/include/trace/hooks/ftrace_dump.h @@ -10,7 +10,6 @@ #include #include -#include #include DECLARE_HOOK(android_vh_ftrace_oops_enter, diff --git a/include/trace/hooks/futex.h b/include/trace/hooks/futex.h index 0692dd68d93c42885f3aa9212ca7b5fd5a2c8707..3acf8128dc3e63eb5257b4efec3dfe1284c577bc 100644 --- a/include/trace/hooks/futex.h +++ b/include/trace/hooks/futex.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_FUTEX_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_FUTEX_H -#include #include #include /* diff --git a/include/trace/hooks/gic.h b/include/trace/hooks/gic.h index 2f7d3cfa6d9b3e497f28b6a3ddd132ed01ab9e11..d33786f2de95bb94064f12df84bfdf05a7258963 100644 --- a/include/trace/hooks/gic.h +++ b/include/trace/hooks/gic.h @@ -8,7 +8,6 @@ #define _TRACE_HOOK_GIC_H -#include #include struct gic_chip_data; diff --git a/include/trace/hooks/gic_v3.h b/include/trace/hooks/gic_v3.h index 3afb7379145d1a5b6b1c4d824e306ea1659bae21..337f7e1348c1864495045fbd8f2244727dede91a 100644 --- a/include/trace/hooks/gic_v3.h +++ b/include/trace/hooks/gic_v3.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_GIC_V3_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_GIC_V3_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/gpiolib.h b/include/trace/hooks/gpiolib.h index 96aca935f953d40e182a49e6457ecd96ded85013..24cb3f54fb82eb497e6b5f577579e1448585887e 100644 --- a/include/trace/hooks/gpiolib.h +++ b/include/trace/hooks/gpiolib.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_GPIOLIB_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_GPIOLIB_H -#include #include #include "../drivers/gpio/gpiolib.h" diff --git a/include/trace/hooks/gup.h b/include/trace/hooks/gup.h new file mode 100644 index 0000000000000000000000000000000000000000..47ea47eeede409bfb624272354a007f049c2b829 --- /dev/null +++ b/include/trace/hooks/gup.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM gup +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH trace/hooks +#if !defined(_TRACE_HOOK_GUP_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_GUP_H +#include + +struct page; + +DECLARE_HOOK(android_vh_try_grab_compound_head, + TP_PROTO(struct page *page, int refs, unsigned int flags, bool *ret), + TP_ARGS(page, refs, flags, ret)); + +DECLARE_HOOK(android_vh___get_user_pages_remote, + TP_PROTO(int *locked, unsigned int *gup_flags, struct page **pages), + TP_ARGS(locked, gup_flags, pages)); + +DECLARE_HOOK(android_vh_get_user_pages, + TP_PROTO(unsigned int *gup_flags, struct page **pages), + TP_ARGS(gup_flags, pages)); + +DECLARE_HOOK(android_vh_internal_get_user_pages_fast, + TP_PROTO(unsigned int *gup_flags, struct page **pages), + TP_ARGS(gup_flags, pages)); + +DECLARE_HOOK(android_vh_pin_user_pages, + TP_PROTO(unsigned int *gup_flags, struct page **pages), + TP_ARGS(gup_flags, pages)); +#endif /* _TRACE_HOOK_GUP_H */ +/* This part must be outside protection */ +#include diff --git a/include/trace/hooks/hung_task.h b/include/trace/hooks/hung_task.h index b355828df349e8695502664c1638f8ede6665ce9..1559d3ed774f00597b2d93a3edfd9ace3cbca80c 100644 --- a/include/trace/hooks/hung_task.h +++ b/include/trace/hooks/hung_task.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_HUNG_TASK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_HUNG_TASK_H -#include #include DECLARE_HOOK(android_vh_check_uninterruptible_tasks, diff --git a/include/trace/hooks/i2c.h b/include/trace/hooks/i2c.h index 71536ad67f6701cc01991c742837e4cc782c3f04..306c0f8cab51f9fcfe292ffd981c0ae4e5ca1ce3 100644 --- a/include/trace/hooks/i2c.h +++ b/include/trace/hooks/i2c.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_I2C_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_I2C_H -#include #include DECLARE_HOOK(android_vh_of_i2c_get_board_info, diff --git a/include/trace/hooks/iommu.h b/include/trace/hooks/iommu.h index c9a52193c4e94821c458337a51586a051a5e2c80..6c30cb7932fa6db6abc8293281e5c90df52f71e4 100644 --- a/include/trace/hooks/iommu.h +++ b/include/trace/hooks/iommu.h @@ -9,7 +9,6 @@ #include -#include #include #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/ipv6.h b/include/trace/hooks/ipv6.h index c1998af0c5a0ae430e0c3510ed547094d35fe5e7..64a54816123321aaceca887a42dc03fd195899a3 100644 --- a/include/trace/hooks/ipv6.h +++ b/include/trace/hooks/ipv6.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_IPV6_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_IPV6_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/logbuf.h b/include/trace/hooks/logbuf.h index f73ad597fc648b8efe8fc046270f8409fd546559..72c34f7fbad0c8d439d7ecbdae14a78d35761a24 100644 --- a/include/trace/hooks/logbuf.h +++ b/include/trace/hooks/logbuf.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_LOGBUF_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_LOGBUF_H -#include #include struct printk_ringbuffer; diff --git a/include/trace/hooks/memory.h b/include/trace/hooks/memory.h index 4b3f77a72d82c528f2e38b7a5bb1c785987aca80..940af43d736c599b097a5fd96f0dc2b2ac8701e4 100644 --- a/include/trace/hooks/memory.h +++ b/include/trace/hooks/memory.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_MEMORY_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MEMORY_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h index ac6142a6e02ad5c2de190cdcb2053ad8fb5fd431..9b583a3371011734c114238a52c101f77ea22605 100644 --- a/include/trace/hooks/mm.h +++ b/include/trace/hooks/mm.h @@ -11,7 +11,6 @@ #include #include -#include #include struct cma; diff --git a/include/trace/hooks/mmc_core.h b/include/trace/hooks/mmc_core.h index ad367782d59f66e7d6ddc2f6a5f7a631f5df1c10..2e36dd8b2b67a63d23506786ecd1514c1f2dd597 100644 --- a/include/trace/hooks/mmc_core.h +++ b/include/trace/hooks/mmc_core.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_MMC_CORE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MMC_CORE_H -#include #include struct mmc_host; diff --git a/include/trace/hooks/module.h b/include/trace/hooks/module.h index 281cb0d37c12cf0d19d93763647b35a58e3fbeef..78b49869ca65ca7f6fdfd4bf95d3d80437c44a32 100644 --- a/include/trace/hooks/module.h +++ b/include/trace/hooks/module.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_MODULE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MODULE_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/mpam.h b/include/trace/hooks/mpam.h index 8479fe7c2356f498a89b3c2065aa83f794321b9b..b62f965032da75760f15dd9df51c4adf5d93662a 100644 --- a/include/trace/hooks/mpam.h +++ b/include/trace/hooks/mpam.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_MPAM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_MPAM_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/net.h b/include/trace/hooks/net.h index 6715aa4eb668d768a7079997e15c77cd48e1d779..0b6de6f659cf79f7a0df3b6babd7166e21b7dd58 100644 --- a/include/trace/hooks/net.h +++ b/include/trace/hooks/net.h @@ -6,7 +6,6 @@ #if !defined(_TRACE_HOOK_NET_VH_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_NET_VH_H -#include #include struct packet_type; diff --git a/include/trace/hooks/pci.h b/include/trace/hooks/pci.h new file mode 100644 index 0000000000000000000000000000000000000000..00d38980ec4992454b7ff2683b62c725cc63fa8d --- /dev/null +++ b/include/trace/hooks/pci.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM pci +#define TRACE_INCLUDE_PATH trace/hooks + +#if !defined(_TRACE_HOOK_PCI_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_PCI_H +#include +/* + * Following tracepoints are not exported in tracefs and provide a + * mechanism for vendor modules to hook and extend functionality + */ + +DECLARE_RESTRICTED_HOOK(android_rvh_pci_d3_sleep, + TP_PROTO(struct pci_dev *dev, unsigned int *delay), + TP_ARGS(dev, delay), 1); + +#endif /* _TRACE_HOOK_PCI_H */ + +/* This part must be outside protection */ +#include diff --git a/include/trace/hooks/pm_domain.h b/include/trace/hooks/pm_domain.h index 548e350e8090805cdb52a91b05eb496f8c53d0da..f6b1c3808ce98a696d612fcdb4e9e844f1a8f98e 100644 --- a/include/trace/hooks/pm_domain.h +++ b/include/trace/hooks/pm_domain.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_PM_DOMAIN_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PM_DOMAIN_H -#include #include struct generic_pm_domain; diff --git a/include/trace/hooks/power.h b/include/trace/hooks/power.h index 149ea08580b808750b5830fb6a29a29e1a7536e0..195538679f322e0769a44005bd7378b375d29f61 100644 --- a/include/trace/hooks/power.h +++ b/include/trace/hooks/power.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_POWER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_POWER_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/preemptirq.h b/include/trace/hooks/preemptirq.h index b4d32c473f3aca459bcf1caa7f96f91523169377..4fbab929f4cf5ee002acd5a60d1a1962a553637f 100644 --- a/include/trace/hooks/preemptirq.h +++ b/include/trace/hooks/preemptirq.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_PREEMPTIRQ_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PREEMPTIRQ_H -#include #include DECLARE_RESTRICTED_HOOK(android_rvh_preempt_disable, diff --git a/include/trace/hooks/printk.h b/include/trace/hooks/printk.h index e4df6e4bf7a8a8a5fff08ba5ea27332291443479..5ec4d743d67f5fb756c8cc997ddc1e52d4aecb8a 100644 --- a/include/trace/hooks/printk.h +++ b/include/trace/hooks/printk.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_PRINTK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PRINTK_H -#include #include DECLARE_HOOK(android_vh_printk_hotplug, diff --git a/include/trace/hooks/psi.h b/include/trace/hooks/psi.h index 62d1a0ee7b6352976844460def3207575fbea1e3..bd704c16185b4b5f661534864280db99424439b2 100644 --- a/include/trace/hooks/psi.h +++ b/include/trace/hooks/psi.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_PSI_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_PSI_H -#include #include #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/remoteproc.h b/include/trace/hooks/remoteproc.h index 7cc5e93d2ebe50789edb30281033e3426aa35d07..ee0a2f0ea147f9b37e65dc7d1a700b0ebe783c94 100644 --- a/include/trace/hooks/remoteproc.h +++ b/include/trace/hooks/remoteproc.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_RPROC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_RPROC_H -#include #include struct rproc; diff --git a/include/trace/hooks/rwsem.h b/include/trace/hooks/rwsem.h index d644a6e2125989d0cfd24f11f08f0813501981c9..9737879e3bc8f31417d127a3e523e4be636140b1 100644 --- a/include/trace/hooks/rwsem.h +++ b/include/trace/hooks/rwsem.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_RWSEM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_RWSEM_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/sched.h b/include/trace/hooks/sched.h index a9884beaf2e8acfbd4fb02a58bc83aa728d72e1d..79e8b401b3a071c17af5ad013a8303d34744944c 100644 --- a/include/trace/hooks/sched.h +++ b/include/trace/hooks/sched.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SCHED_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a @@ -405,6 +404,30 @@ DECLARE_HOOK(android_vh_setscheduler_uclamp, TP_PROTO(struct task_struct *tsk, int clamp_id, unsigned int value), TP_ARGS(tsk, clamp_id, value)); +DECLARE_RESTRICTED_HOOK(android_rvh_attach_entity_load_avg, + TP_PROTO(struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_detach_entity_load_avg, + TP_PROTO(struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_update_load_avg, + TP_PROTO(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(now, cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_remove_entity_load_avg, + TP_PROTO(struct cfs_rq *cfs_rq, struct sched_entity *se), + TP_ARGS(cfs_rq, se), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_update_blocked_fair, + TP_PROTO(struct rq *rq), + TP_ARGS(rq), 1); + +DECLARE_RESTRICTED_HOOK(android_rvh_update_rt_rq_load_avg, + TP_PROTO(u64 now, struct rq *rq, struct task_struct *tsk, int running), + TP_ARGS(now, rq, tsk, running), 1); + /* macro versions of hooks are no longer required */ #endif /* _TRACE_HOOK_SCHED_H */ diff --git a/include/trace/hooks/scmi.h b/include/trace/hooks/scmi.h index ea2db9f07a9f80bb2f59809e8349493d0aee8a4f..d889d3334b9cbab35de08925629b4e813ab07a8c 100644 --- a/include/trace/hooks/scmi.h +++ b/include/trace/hooks/scmi.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_SCMI_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SCMI_H -#include #include DECLARE_HOOK(android_vh_scmi_timeout_sync, diff --git a/include/trace/hooks/selinux.h b/include/trace/hooks/selinux.h index 2ad6484d2c5535103087862dd40ba8fd490b9879..ebd6187c41082486ad0c09539a6f41b2d6a158ef 100644 --- a/include/trace/hooks/selinux.h +++ b/include/trace/hooks/selinux.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SELINUX_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SELINUX_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/shmem_fs.h b/include/trace/hooks/shmem_fs.h index 08e63033070e994ff49a66b1cafb56504a3deade..0077707072c5c9c13107a8ec4e98ca68f829e21b 100644 --- a/include/trace/hooks/shmem_fs.h +++ b/include/trace/hooks/shmem_fs.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SHMEM_FS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SHMEM_FS_H -#include #include struct page; diff --git a/include/trace/hooks/signal.h b/include/trace/hooks/signal.h index a0db2e8cf77d3024a2d5a59e34a7d3de5403bf99..937e6c49b7ca8536caf3a01247ea42c746ac495f 100644 --- a/include/trace/hooks/signal.h +++ b/include/trace/hooks/signal.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SIGNAL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SIGNAL_H -#include #include struct task_struct; diff --git a/include/trace/hooks/snd_compr.h b/include/trace/hooks/snd_compr.h index c42ed8d6bc30183e9f1979c929aa97a065e50d14..2e63aff9e4f943b84e3306fdeb6c4fa4b553b8ff 100644 --- a/include/trace/hooks/snd_compr.h +++ b/include/trace/hooks/snd_compr.h @@ -8,7 +8,6 @@ #if !defined(_TRACE_HOOK_SND_COMPR_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SND_COMPR_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/softlockup.h b/include/trace/hooks/softlockup.h index 9294913f91df3ced4f6a1d955ed174e04d2cb555..072f30007d7128c8f6356c13b7a100fa0260fe92 100644 --- a/include/trace/hooks/softlockup.h +++ b/include/trace/hooks/softlockup.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_SOFTLOCKUP_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SOFTLOCKUP_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/sound.h b/include/trace/hooks/sound.h index 2bf018edf39267238a9d072f4815b6f9d0a722e9..3dfd589d264d11097045e8a47735c01e600db493 100644 --- a/include/trace/hooks/sound.h +++ b/include/trace/hooks/sound.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SOUND_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SOUND_H -#include #include #include diff --git a/include/trace/hooks/sys.h b/include/trace/hooks/sys.h index 9e5d7a5cb2cf13a0fa23e227f9305833fa054d51..e2d5d6d4fc142f3624f4e568cde16be51740f87d 100644 --- a/include/trace/hooks/sys.h +++ b/include/trace/hooks/sys.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SYS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SYS_H -#include #include struct task_struct; diff --git a/include/trace/hooks/syscall_check.h b/include/trace/hooks/syscall_check.h index d39802aa4a1e6a5b331b2405731c12a010b346be..56d8267297ca2bd85e3ce6d2539e9e51a9facbbb 100644 --- a/include/trace/hooks/syscall_check.h +++ b/include/trace/hooks/syscall_check.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_SYSCALL_CHECK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SYSCALL_CHECK_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/sysrqcrash.h b/include/trace/hooks/sysrqcrash.h index d163f898a9f6e6b2bee68a3afd30c4d6efb09d36..0056322c38179792896bf03d96119cb7426a3c1c 100644 --- a/include/trace/hooks/sysrqcrash.h +++ b/include/trace/hooks/sysrqcrash.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_SYSRQCRASH_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_SYSRQCRASH_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/thermal.h b/include/trace/hooks/thermal.h index 25d6151b29190129556c91dda84277e938ce15de..78ce2a5ea49bf1e1bd70e7184282892609ee92af 100644 --- a/include/trace/hooks/thermal.h +++ b/include/trace/hooks/thermal.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_THERMAL_H -#include #include #include diff --git a/include/trace/hooks/timer.h b/include/trace/hooks/timer.h index 174d958e4c3145fa6bf9f20f54204f4d810363c5..67ef865dad4adb64c896091055df2a8653771bca 100644 --- a/include/trace/hooks/timer.h +++ b/include/trace/hooks/timer.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_TIMER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TIMER_H -#include #include DECLARE_HOOK(android_vh_timer_calc_index, diff --git a/include/trace/hooks/topology.h b/include/trace/hooks/topology.h index 74014027160c8d6055ee5d810b0355e5fc4d721a..5d29893ba477d80094c5d1a372002d8a95735ebc 100644 --- a/include/trace/hooks/topology.h +++ b/include/trace/hooks/topology.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_TOPOLOGY_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TOPOLOGY_H -#include #include #include diff --git a/include/trace/hooks/traps.h b/include/trace/hooks/traps.h index 350a14369acc963a69d7bc2a6d80b92fddd8072b..38749535aa4d0a9839d02ddf6a06be3e59e43b67 100644 --- a/include/trace/hooks/traps.h +++ b/include/trace/hooks/traps.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_TRAPS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TRAPS_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/typec.h b/include/trace/hooks/typec.h index b7be4d857708192e064b64b2d48591783dbab7ab..6634dbb82917fa74e7ef588755e9d145ab2850be 100644 --- a/include/trace/hooks/typec.h +++ b/include/trace/hooks/typec.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_TYPEC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_TYPEC_H -#include #include #include /* diff --git a/include/trace/hooks/ufshcd.h b/include/trace/hooks/ufshcd.h index 744a1db41631d3f22922f945ac1c8aa23a36d617..eebde088cd240ff4154f4c6055dce6fcbd124329 100644 --- a/include/trace/hooks/ufshcd.h +++ b/include/trace/hooks/ufshcd.h @@ -4,7 +4,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_UFSHCD_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_UFSHCD_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/usb.h b/include/trace/hooks/usb.h index f8459473042e4b994dac34aafc31567e7af41af2..f4d5ff04b6b880b4cb46530c9995a092cffe9b46 100644 --- a/include/trace/hooks/usb.h +++ b/include/trace/hooks/usb.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_USB_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_USB_H -#include #include #include /* diff --git a/include/trace/hooks/user.h b/include/trace/hooks/user.h index b5b507ccd9c265380059383097be37b3a66c5247..773eed2ea75a4837fd1fe3168c3fb4918c2b36ec 100644 --- a/include/trace/hooks/user.h +++ b/include/trace/hooks/user.h @@ -5,7 +5,6 @@ #define TRACE_INCLUDE_PATH trace/hooks #if !defined(_TRACE_HOOK_USER_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_USER_H -#include #include struct user_struct; diff --git a/include/trace/hooks/v4l2core.h b/include/trace/hooks/v4l2core.h index 32b6e96ba627b2a8117377989e9c50553b96ebc2..615e1ce8ff9e9785a2f251f0613cc1d85b6929f6 100644 --- a/include/trace/hooks/v4l2core.h +++ b/include/trace/hooks/v4l2core.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_V4L2CORE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_V4L2_CORE_H -#include #include struct v4l2_format; diff --git a/include/trace/hooks/v4l2mc.h b/include/trace/hooks/v4l2mc.h index 8a4653bd4a4de5acf1e0438d48d0017a6909729a..952c3ffe26e5cd859e525b606e0eb44af3b440a0 100644 --- a/include/trace/hooks/v4l2mc.h +++ b/include/trace/hooks/v4l2mc.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_V4L2MC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_V4L2MC_H -#include #include struct media_link; diff --git a/include/trace/hooks/vendor_hooks.h b/include/trace/hooks/vendor_hooks.h index f51a9ac310457ca06747a4e75e6368cc70e26b8e..a283509abbf61e68d9e23f1353fc46a919f63369 100644 --- a/include/trace/hooks/vendor_hooks.h +++ b/include/trace/hooks/vendor_hooks.h @@ -7,7 +7,9 @@ * will override the DECLARE_RESTRICTED_HOOK and break the second include. */ +#ifndef __GENKSYMS__ #include +#endif #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) diff --git a/include/trace/hooks/vmscan.h b/include/trace/hooks/vmscan.h index b6b77d9895cdd7a1bdfd0b494b16abf4890b95d9..4a3af8e75839f2aff048c4f18d9a021aa25526b1 100644 --- a/include/trace/hooks/vmscan.h +++ b/include/trace/hooks/vmscan.h @@ -7,7 +7,6 @@ #if !defined(_TRACE_HOOK_VMSCAN_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_VMSCAN_H -#include #include DECLARE_HOOK(android_vh_tune_scan_type, diff --git a/include/trace/hooks/workqueue.h b/include/trace/hooks/workqueue.h index 0ffe56433a4c8a66d9dc568ac56685f0ca8bd785..dee037d0b7c04dfb5a9b4c6900a74ec54de83232 100644 --- a/include/trace/hooks/workqueue.h +++ b/include/trace/hooks/workqueue.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_WORKQUEUE_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/trace/hooks/wqlockup.h b/include/trace/hooks/wqlockup.h index 21e23ad6b9d90b6371a63361e14577e61c9a270f..2572ebf5eff46d59cc9ee08bc63d2e61d72df1be 100644 --- a/include/trace/hooks/wqlockup.h +++ b/include/trace/hooks/wqlockup.h @@ -5,7 +5,6 @@ #if !defined(_TRACE_HOOK_WQLOCKUP_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_HOOK_WQLOCKUP_H -#include #include /* * Following tracepoints are not exported in tracefs and provide a diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 8b4a27b17606d61190575128ea80e31c94430775..26b6bee72039a995a5faa06e698201002520d548 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1491,8 +1491,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 1, if current task belongs to the cgroup2. - * * 0, if current task does not belong to the cgroup2. + * * 0, if current task belongs to the cgroup2. + * * 1, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) @@ -2164,8 +2164,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack= * Return - * The non-negative copied *buf* length equal to or less than - * *size* on success, or a negative error in case of failure. + * A non-negative value equal to or less than *size* on success, + * or a negative error in case of failure. * * long bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header) * Description @@ -3449,8 +3449,8 @@ union bpf_attr { * * # sysctl kernel.perf_event_max_stack= * Return - * The non-negative copied *buf* length equal to or less than - * *size* on success, or a negative error in case of failure. + * A non-negative value equal to or less than *size* on success, + * or a negative error in case of failure. * * long bpf_load_hdr_opt(struct bpf_sock_ops *skops, void *searchby_res, u32 len, u64 flags) * Description diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 98aaf3d84c5d0b935cbddb383cd70b6772e880ce..f0521a39a5863a0346eb26db501fbb0ade15b4f8 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -965,42 +965,44 @@ struct fuse_removemapping_one { #define FUSE_REMOVEMAPPING_MAX_ENTRY \ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) -struct fuse_mount; +/* + * Fuse BPF Args + * + * Used to communicate with bpf programs to allow checking or altering certain values. + * The end_offset allows the bpf verifier to check boundaries statically. This reflects + * the ends of the buffer. size shows the length that was actually used. + * + */ /** One input argument of a request */ -struct fuse_in_arg { - unsigned size; +struct fuse_bpf_in_arg { + uint32_t size; const void *value; + const void *end_offset; }; /** One output argument of a request */ -struct fuse_arg { - unsigned size; +struct fuse_bpf_arg { + uint32_t size; void *value; + void *end_offset; }; -struct fuse_args { +#define FUSE_MAX_IN_ARGS 5 +#define FUSE_MAX_OUT_ARGS 3 + +#define FUSE_BPF_FORCE (1 << 0) +#define FUSE_BPF_OUT_ARGVAR (1 << 6) + +struct fuse_bpf_args { uint64_t nodeid; uint32_t opcode; uint32_t error_in; - unsigned short in_numargs; - unsigned short out_numargs; - int force:1; - int noreply:1; - int nocreds:1; - int in_pages:1; - int out_pages:1; - int user_pages:1; - int out_argvar:1; - int page_zeroing:1; - int page_replace:1; - int may_block:1; - struct fuse_in_arg in_args[5]; - struct fuse_arg out_args[3]; - void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); - - /* Path used for completing d_canonical_path */ - struct path *canonical_path; + uint32_t in_numargs; + uint32_t out_numargs; + uint32_t flags; + struct fuse_bpf_in_arg in_args[FUSE_MAX_IN_ARGS]; + struct fuse_bpf_arg out_args[FUSE_MAX_OUT_ARGS]; }; #define FUSE_BPF_USER_FILTER 1 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 2380257670457de6e84bd4063b31dfe7cb4fcc81..facb29ebef2dd50803d6923dae8b940af799b25a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1072,9 +1072,7 @@ struct kvm_ppc_resize_hpt { /* #define KVM_CAP_HYPERV_ENFORCE_CPUID 199 #define KVM_CAP_SREGS2 200 -*/ #define KVM_CAP_EXIT_HYPERCALL 201 -/* #define KVM_CAP_PPC_RPT_INVALIDATE 202 #define KVM_CAP_BINARY_STATS_FD 203 #define KVM_CAP_EXIT_ON_EMULATION_FAILURE 204 diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 2bf93c0d6354b07ec02fbc4561f5ea0fc223c56b..b1484a5a3c3600f709de4fb272b9b91b2bd9a8d5 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -55,6 +55,8 @@ #define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) #define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_0_2_FN64(18) +#define PSCI_1_1_FN64_MEM_PROTECT PSCI_0_2_FN64(19) + /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff #define PSCI_0_2_POWER_STATE_ID_SHIFT 0 diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index 77ee207623a9bfaeb151c92be753e667d5f1810e..9a402fdb60e97bc92591312ebc7071de54fa900c 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h @@ -105,11 +105,23 @@ struct rseq { * Read and set by the kernel. Set by user-space with single-copy * atomicity semantics. This field should only be updated by the * thread which registered this data structure. Aligned on 64-bit. - * - * 32-bit architectures should update the low order bits of the - * rseq_cs field, leaving the high order bits initialized to 0. */ - __u64 rseq_cs; + union { + __u64 ptr64; +#ifdef __LP64__ + __u64 ptr; +#else + struct { +#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || defined(__BIG_ENDIAN) + __u32 padding; /* Initialized to zero. */ + __u32 ptr32; +#else /* LITTLE */ + __u32 ptr32; + __u32 padding; /* Initialized to zero. */ +#endif /* ENDIAN */ + } ptr; +#endif + } rseq_cs; /* * Restartable sequences flags field. diff --git a/kernel/audit.h b/kernel/audit.h index 1918019e6aaf7b8c54a248fcc593d22e3ac772c8..3b9c0945225a121e7031cfe29299925bb0b42516 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -191,10 +191,6 @@ struct audit_context { struct { char *name; } module; - struct { - struct audit_ntp_data ntp_data; - struct timespec64 tk_injoffset; - } time; }; int fds[2]; struct audit_proctitle proctitle; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 07e2788bbbf124ea6b7a7f6077a4eed2d3669d8b..638f424859edc384aa22b8908b1dc5a784d6bd97 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1214,53 +1214,6 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) from_kuid(&init_user_ns, name->fcap.rootid)); } -static void audit_log_time(struct audit_context *context, struct audit_buffer **ab) -{ - const struct audit_ntp_data *ntp = &context->time.ntp_data; - const struct timespec64 *tk = &context->time.tk_injoffset; - static const char * const ntp_name[] = { - "offset", - "freq", - "status", - "tai", - "tick", - "adjust", - }; - int type; - - if (context->type == AUDIT_TIME_ADJNTPVAL) { - for (type = 0; type < AUDIT_NTP_NVALS; type++) { - if (ntp->vals[type].newval != ntp->vals[type].oldval) { - if (!*ab) { - *ab = audit_log_start(context, - GFP_KERNEL, - AUDIT_TIME_ADJNTPVAL); - if (!*ab) - return; - } - audit_log_format(*ab, "op=%s old=%lli new=%lli", - ntp_name[type], - ntp->vals[type].oldval, - ntp->vals[type].newval); - audit_log_end(*ab); - *ab = NULL; - } - } - } - if (tk->tv_sec != 0 || tk->tv_nsec != 0) { - if (!*ab) { - *ab = audit_log_start(context, GFP_KERNEL, - AUDIT_TIME_INJOFFSET); - if (!*ab) - return; - } - audit_log_format(*ab, "sec=%lli nsec=%li", - (long long)tk->tv_sec, tk->tv_nsec); - audit_log_end(*ab); - *ab = NULL; - } -} - static void show_special(struct audit_context *context, int *call_panic) { struct audit_buffer *ab; @@ -1366,11 +1319,6 @@ static void show_special(struct audit_context *context, int *call_panic) audit_log_format(ab, "(null)"); break; - case AUDIT_TIME_ADJNTPVAL: - case AUDIT_TIME_INJOFFSET: - /* this call deviates from the rest, eating the buffer */ - audit_log_time(context, &ab); - break; } audit_log_end(ab); } @@ -2612,26 +2560,31 @@ void __audit_fanotify(unsigned int response) void __audit_tk_injoffset(struct timespec64 offset) { - struct audit_context *context = audit_context(); + audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_INJOFFSET, + "sec=%lli nsec=%li", + (long long)offset.tv_sec, offset.tv_nsec); +} + +static void audit_log_ntp_val(const struct audit_ntp_data *ad, + const char *op, enum audit_ntp_type type) +{ + const struct audit_ntp_val *val = &ad->vals[type]; + + if (val->newval == val->oldval) + return; - /* only set type if not already set by NTP */ - if (!context->type) - context->type = AUDIT_TIME_INJOFFSET; - memcpy(&context->time.tk_injoffset, &offset, sizeof(offset)); + audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJNTPVAL, + "op=%s old=%lli new=%lli", op, val->oldval, val->newval); } void __audit_ntp_log(const struct audit_ntp_data *ad) { - struct audit_context *context = audit_context(); - int type; - - for (type = 0; type < AUDIT_NTP_NVALS; type++) - if (ad->vals[type].newval != ad->vals[type].oldval) { - /* unconditionally set type, overwriting TK */ - context->type = AUDIT_TIME_ADJNTPVAL; - memcpy(&context->time.ntp_data, ad, sizeof(*ad)); - break; - } + audit_log_ntp_val(ad, "offset", AUDIT_NTP_OFFSET); + audit_log_ntp_val(ad, "freq", AUDIT_NTP_FREQ); + audit_log_ntp_val(ad, "status", AUDIT_NTP_STATUS); + audit_log_ntp_val(ad, "tai", AUDIT_NTP_TAI); + audit_log_ntp_val(ad, "tick", AUDIT_NTP_TICK); + audit_log_ntp_val(ad, "adjust", AUDIT_NTP_ADJUST); } void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries, diff --git a/kernel/bounds.c b/kernel/bounds.c index 9795d75b09b2323306ad6a058a6350a87a251443..10dd9e6b03e551a1936587e02543b1c1883e201a 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -22,6 +22,13 @@ int main(void) DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); #endif DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); +#ifdef CONFIG_LRU_GEN + DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); + DEFINE(LRU_REFS_WIDTH, MAX_NR_TIERS - 2); +#else + DEFINE(LRU_GEN_WIDTH, 0); + DEFINE(LRU_REFS_WIDTH, 0); +#endif /* End of constants */ return 0; diff --git a/kernel/bpf/bpf_fuse.c b/kernel/bpf/bpf_fuse.c index 2a4db5ce06b4869985d627252bff3a2b0fbd6227..00738c84b76e6f58100de3f1aa626af6f48bb008 100644 --- a/kernel/bpf/bpf_fuse.c +++ b/kernel/bpf/bpf_fuse.c @@ -36,12 +36,12 @@ static bool fuse_prog_is_valid_access(int off, int size, { int i; - if (off < 0 || off > offsetofend(struct fuse_args, out_args)) + if (off < 0 || off > offsetofend(struct fuse_bpf_args, out_args)) return false; /* TODO This is garbage. Do it properly */ for (i = 0; i < 5; i++) { - if (off == offsetof(struct fuse_args, in_args[i].value)) { + if (off == offsetof(struct fuse_bpf_args, in_args[i].value)) { info->reg_type = PTR_TO_RDONLY_BUF; info->ctx_field_size = 256; if (type != BPF_READ) @@ -50,7 +50,7 @@ static bool fuse_prog_is_valid_access(int off, int size, } } for (i = 0; i < 3; i++) { - if (off == offsetof(struct fuse_args, out_args[i].value)) { + if (off == offsetof(struct fuse_bpf_args, out_args[i].value)) { info->reg_type = PTR_TO_RDWR_BUF; info->ctx_field_size = 256; return true; diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 4575d2d60cb1030c50b4d7b57486e23d98da5785..56cd7e6589ff344b7d8a8883be626cca0d2f6fcd 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -358,7 +358,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, } static struct perf_callchain_entry * -get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) +get_callchain_entry_for_task(struct task_struct *task, u32 init_nr) { #ifdef CONFIG_STACKTRACE struct perf_callchain_entry *entry; @@ -369,8 +369,9 @@ get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) if (!entry) return NULL; - entry->nr = stack_trace_save_tsk(task, (unsigned long *)entry->ip, - max_depth, 0); + entry->nr = init_nr + + stack_trace_save_tsk(task, (unsigned long *)(entry->ip + init_nr), + sysctl_perf_event_max_stack - init_nr, 0); /* stack_trace_save_tsk() works on unsigned long array, while * perf_callchain_entry uses u64 array. For 32-bit systems, it is @@ -382,7 +383,7 @@ get_callchain_entry_for_task(struct task_struct *task, u32 max_depth) int i; /* copy data from the end to avoid using extra buffer */ - for (i = entry->nr - 1; i >= 0; i--) + for (i = entry->nr - 1; i >= (int)init_nr; i--) to[i] = (u64)(from[i]); } @@ -399,19 +400,27 @@ static long __bpf_get_stackid(struct bpf_map *map, { struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map); struct stack_map_bucket *bucket, *new_bucket, *old_bucket; + u32 max_depth = map->value_size / stack_map_data_size(map); + /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */ + u32 init_nr = sysctl_perf_event_max_stack - max_depth; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; u32 hash, id, trace_nr, trace_len; bool user = flags & BPF_F_USER_STACK; u64 *ips; bool hash_matches; - if (trace->nr <= skip) + /* get_perf_callchain() guarantees that trace->nr >= init_nr + * and trace-nr <= sysctl_perf_event_max_stack, so trace_nr <= max_depth + */ + trace_nr = trace->nr - init_nr; + + if (trace_nr <= skip) /* skipping more than usable stack trace */ return -EFAULT; - trace_nr = trace->nr - skip; + trace_nr -= skip; trace_len = trace_nr * sizeof(u64); - ips = trace->ip + skip; + ips = trace->ip + skip + init_nr; hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0); id = hash & (smap->n_buckets - 1); bucket = READ_ONCE(smap->buckets[id]); @@ -468,7 +477,8 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map, u64, flags) { u32 max_depth = map->value_size / stack_map_data_size(map); - u32 skip = flags & BPF_F_SKIP_FIELD_MASK; + /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */ + u32 init_nr = sysctl_perf_event_max_stack - max_depth; bool user = flags & BPF_F_USER_STACK; struct perf_callchain_entry *trace; bool kernel = !user; @@ -477,12 +487,8 @@ BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map, BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID))) return -EINVAL; - max_depth += skip; - if (max_depth > sysctl_perf_event_max_stack) - max_depth = sysctl_perf_event_max_stack; - - trace = get_perf_callchain(regs, 0, kernel, user, max_depth, - false, false); + trace = get_perf_callchain(regs, init_nr, kernel, user, + sysctl_perf_event_max_stack, false, false); if (unlikely(!trace)) /* couldn't fetch the stack trace */ @@ -573,7 +579,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, struct perf_callchain_entry *trace_in, void *buf, u32 size, u64 flags) { - u32 trace_nr, copy_len, elem_size, num_elem, max_depth; + u32 init_nr, trace_nr, copy_len, elem_size, num_elem; bool user_build_id = flags & BPF_F_USER_BUILD_ID; u32 skip = flags & BPF_F_SKIP_FIELD_MASK; bool user = flags & BPF_F_USER_STACK; @@ -598,28 +604,30 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task, goto err_fault; num_elem = size / elem_size; - max_depth = num_elem + skip; - if (sysctl_perf_event_max_stack < max_depth) - max_depth = sysctl_perf_event_max_stack; + if (sysctl_perf_event_max_stack < num_elem) + init_nr = 0; + else + init_nr = sysctl_perf_event_max_stack - num_elem; if (trace_in) trace = trace_in; else if (kernel && task) - trace = get_callchain_entry_for_task(task, max_depth); + trace = get_callchain_entry_for_task(task, init_nr); else - trace = get_perf_callchain(regs, 0, kernel, user, max_depth, + trace = get_perf_callchain(regs, init_nr, kernel, user, + sysctl_perf_event_max_stack, false, false); if (unlikely(!trace)) goto err_fault; - if (trace->nr < skip) + trace_nr = trace->nr - init_nr; + if (trace_nr < skip) goto err_fault; - trace_nr = trace->nr - skip; + trace_nr -= skip; trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem; copy_len = trace_nr * elem_size; - - ips = trace->ip + skip; + ips = trace->ip + skip + init_nr; if (user && user_build_id) stack_map_get_build_id_offset(buf, ips, trace_nr, user); else diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index 6aca805a25c4997c772ead4bba525dc049b56d66..df99cb9071471aa50526a180cac42ab3a98600b9 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -65,25 +65,6 @@ static inline struct cgroup_fs_context *cgroup_fc2context(struct fs_context *fc) return container_of(kfc, struct cgroup_fs_context, kfc); } -struct cgroup_pidlist; - -struct cgroup_file_ctx { - struct cgroup_namespace *ns; - - struct { - void *trigger; - } psi; - - struct { - bool started; - struct css_task_iter iter; - } procs; - - struct { - struct cgroup_pidlist *pidlist; - } procs1; -}; - /* * A cgroup can be associated with multiple css_sets as different tasks may * belong to different cgroups on different hierarchies. In the other @@ -165,7 +146,6 @@ struct cgroup_mgctx { #define DEFINE_CGROUP_MGCTX(name) \ struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name) -extern struct mutex cgroup_mutex; extern spinlock_t css_set_lock; extern struct cgroup_subsys *cgroup_subsys[]; extern struct list_head cgroup_roots; diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 185fbb6a0011a5d79627bd3a8e703b3b8adbef68..f931f6547423ff672f8e036bec2d9e40d0ae7b9f 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -394,7 +394,6 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) * next pid to display, if any */ struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; struct cgroup *cgrp = seq_css(s)->cgroup; struct cgroup_pidlist *l; enum cgroup_filetype type = seq_cft(s)->private; @@ -404,24 +403,25 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) mutex_lock(&cgrp->pidlist_mutex); /* - * !NULL @ctx->procs1.pidlist indicates that this isn't the first - * start() after open. If the matching pidlist is around, we can use - * that. Look for it. Note that @ctx->procs1.pidlist can't be used - * directly. It could already have been destroyed. + * !NULL @of->priv indicates that this isn't the first start() + * after open. If the matching pidlist is around, we can use that. + * Look for it. Note that @of->priv can't be used directly. It + * could already have been destroyed. */ - if (ctx->procs1.pidlist) - ctx->procs1.pidlist = cgroup_pidlist_find(cgrp, type); + if (of->priv) + of->priv = cgroup_pidlist_find(cgrp, type); /* * Either this is the first start() after open or the matching * pidlist has been destroyed inbetween. Create a new one. */ - if (!ctx->procs1.pidlist) { - ret = pidlist_array_load(cgrp, type, &ctx->procs1.pidlist); + if (!of->priv) { + ret = pidlist_array_load(cgrp, type, + (struct cgroup_pidlist **)&of->priv); if (ret) return ERR_PTR(ret); } - l = ctx->procs1.pidlist; + l = of->priv; if (pid) { int end = l->length; @@ -449,8 +449,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) static void cgroup_pidlist_stop(struct seq_file *s, void *v) { struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; - struct cgroup_pidlist *l = ctx->procs1.pidlist; + struct cgroup_pidlist *l = of->priv; if (l) mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork, @@ -461,8 +460,7 @@ static void cgroup_pidlist_stop(struct seq_file *s, void *v) static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos) { struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; - struct cgroup_pidlist *l = ctx->procs1.pidlist; + struct cgroup_pidlist *l = of->priv; pid_t *p = v; pid_t *end = l->list + l->length; /* @@ -547,7 +545,6 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct cgroup *cgrp; - struct cgroup_file_ctx *ctx; BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); @@ -555,9 +552,8 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of, * Release agent gets called with all capabilities, * require capabilities to set release agent. */ - ctx = of->priv; - if ((ctx->ns->user_ns != &init_user_ns) || - !file_ns_capable(of->file, &init_user_ns, CAP_SYS_ADMIN)) + if ((of->file->f_cred->user_ns != &init_user_ns) || + !capable(CAP_SYS_ADMIN)) return -EPERM; cgrp = cgroup_kn_lock_live(of->kn, false); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index c1e1a5c34e774c583e543889b961697db3da4136..e914646569b60e457c48454a0a7ce0b2c42893c5 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -3617,7 +3617,6 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, size_t nbytes, enum psi_res res) { - struct cgroup_file_ctx *ctx = of->priv; struct psi_trigger *new; struct cgroup *cgrp; struct psi_group *psi; @@ -3630,7 +3629,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, cgroup_kn_unlock(of->kn); /* Allow only one trigger per file descriptor */ - if (ctx->psi.trigger) { + if (of->priv) { cgroup_put(cgrp); return -EBUSY; } @@ -3642,7 +3641,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, return PTR_ERR(new); } - smp_store_release(&ctx->psi.trigger, new); + smp_store_release(&of->priv, new); cgroup_put(cgrp); return nbytes; @@ -3672,15 +3671,12 @@ static ssize_t cgroup_cpu_pressure_write(struct kernfs_open_file *of, static __poll_t cgroup_pressure_poll(struct kernfs_open_file *of, poll_table *pt) { - struct cgroup_file_ctx *ctx = of->priv; - return psi_trigger_poll(&ctx->psi.trigger, of->file, pt); + return psi_trigger_poll(&of->priv, of->file, pt); } static void cgroup_pressure_release(struct kernfs_open_file *of) { - struct cgroup_file_ctx *ctx = of->priv; - - psi_trigger_destroy(ctx->psi.trigger); + psi_trigger_destroy(of->priv); } bool cgroup_psi_enabled(void) @@ -3733,43 +3729,24 @@ static ssize_t cgroup_freeze_write(struct kernfs_open_file *of, static int cgroup_file_open(struct kernfs_open_file *of) { struct cftype *cft = of->kn->priv; - struct cgroup_file_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->ns = current->nsproxy->cgroup_ns; - get_cgroup_ns(ctx->ns); - of->priv = ctx; - - if (!cft->open) - return 0; - ret = cft->open(of); - if (ret) { - put_cgroup_ns(ctx->ns); - kfree(ctx); - } - return ret; + if (cft->open) + return cft->open(of); + return 0; } static void cgroup_file_release(struct kernfs_open_file *of) { struct cftype *cft = of->kn->priv; - struct cgroup_file_ctx *ctx = of->priv; if (cft->release) cft->release(of); - put_cgroup_ns(ctx->ns); - kfree(ctx); } static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct cgroup_file_ctx *ctx = of->priv; + struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; struct cgroup *cgrp = of->kn->parent->priv; struct cftype *cft = of->kn->priv; struct cgroup_subsys_state *css; @@ -3786,7 +3763,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, */ if ((cgrp->root->flags & CGRP_ROOT_NS_DELEGATE) && !(cft->flags & CFTYPE_NS_DELEGATABLE) && - ctx->ns != &init_cgroup_ns && ctx->ns->root_cset->dfl_cgrp == cgrp) + ns != &init_cgroup_ns && ns->root_cset->dfl_cgrp == cgrp) return -EPERM; if (cft->write) @@ -4694,21 +4671,21 @@ void css_task_iter_end(struct css_task_iter *it) static void cgroup_procs_release(struct kernfs_open_file *of) { - struct cgroup_file_ctx *ctx = of->priv; - - if (ctx->procs.started) - css_task_iter_end(&ctx->procs.iter); + if (of->priv) { + css_task_iter_end(of->priv); + kfree(of->priv); + } } static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos) { struct kernfs_open_file *of = s->private; - struct cgroup_file_ctx *ctx = of->priv; + struct css_task_iter *it = of->priv; if (pos) (*pos)++; - return css_task_iter_next(&ctx->procs.iter); + return css_task_iter_next(it); } static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos, @@ -4716,18 +4693,21 @@ static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos, { struct kernfs_open_file *of = s->private; struct cgroup *cgrp = seq_css(s)->cgroup; - struct cgroup_file_ctx *ctx = of->priv; - struct css_task_iter *it = &ctx->procs.iter; + struct css_task_iter *it = of->priv; /* * When a seq_file is seeked, it's always traversed sequentially * from position 0, so we can simply keep iterating on !0 *pos. */ - if (!ctx->procs.started) { + if (!it) { if (WARN_ON_ONCE((*pos))) return ERR_PTR(-EINVAL); + + it = kzalloc(sizeof(*it), GFP_KERNEL); + if (!it) + return ERR_PTR(-ENOMEM); + of->priv = it; css_task_iter_start(&cgrp->self, iter_flags, it); - ctx->procs.started = true; } else if (!(*pos)) { css_task_iter_end(it); css_task_iter_start(&cgrp->self, iter_flags, it); @@ -4778,9 +4758,9 @@ static int cgroup_may_write(const struct cgroup *cgrp, struct super_block *sb) static int cgroup_procs_write_permission(struct cgroup *src_cgrp, struct cgroup *dst_cgrp, - struct super_block *sb, - struct cgroup_namespace *ns) + struct super_block *sb) { + struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; struct cgroup *com_cgrp = src_cgrp; int ret; @@ -4809,12 +4789,11 @@ static int cgroup_procs_write_permission(struct cgroup *src_cgrp, static int cgroup_attach_permissions(struct cgroup *src_cgrp, struct cgroup *dst_cgrp, - struct super_block *sb, bool threadgroup, - struct cgroup_namespace *ns) + struct super_block *sb, bool threadgroup) { int ret = 0; - ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp, sb, ns); + ret = cgroup_procs_write_permission(src_cgrp, dst_cgrp, sb); if (ret) return ret; @@ -4831,7 +4810,6 @@ static int cgroup_attach_permissions(struct cgroup *src_cgrp, static ssize_t cgroup_procs_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct cgroup_file_ctx *ctx = of->priv; struct cgroup *src_cgrp, *dst_cgrp; struct task_struct *task; ssize_t ret; @@ -4852,8 +4830,7 @@ static ssize_t cgroup_procs_write(struct kernfs_open_file *of, spin_unlock_irq(&css_set_lock); ret = cgroup_attach_permissions(src_cgrp, dst_cgrp, - of->file->f_path.dentry->d_sb, true, - ctx->ns); + of->file->f_path.dentry->d_sb, true); if (ret) goto out_finish; @@ -4875,7 +4852,6 @@ static void *cgroup_threads_start(struct seq_file *s, loff_t *pos) static ssize_t cgroup_threads_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct cgroup_file_ctx *ctx = of->priv; struct cgroup *src_cgrp, *dst_cgrp; struct task_struct *task; ssize_t ret; @@ -4899,8 +4875,7 @@ static ssize_t cgroup_threads_write(struct kernfs_open_file *of, /* thread migrations follow the cgroup.procs delegation rule */ ret = cgroup_attach_permissions(src_cgrp, dst_cgrp, - of->file->f_path.dentry->d_sb, false, - ctx->ns); + of->file->f_path.dentry->d_sb, false); if (ret) goto out_finish; @@ -6083,8 +6058,7 @@ static int cgroup_css_set_fork(struct kernel_clone_args *kargs) goto err; ret = cgroup_attach_permissions(cset->dfl_cgrp, dst_cgrp, sb, - !(kargs->flags & CLONE_THREAD), - current->nsproxy->cgroup_ns); + !(kargs->flags & CLONE_THREAD)); if (ret) goto err; diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index 13417f0045f028ed04b4348460b415ab31dd94c1..6226502ce04991d8ba1642ca19c97f37ad5df35f 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -350,7 +350,7 @@ int kdb_getarea_size(void *res, unsigned long addr, size_t size) */ int kdb_putarea_size(unsigned long addr, void *res, size_t size) { - int ret = copy_to_kernel_nofault((char *)addr, (char *)res, size); + int ret = copy_from_kernel_nofault((char *)addr, (char *)res, size); if (ret) { if (!KDB_STATE(SUPPRESS)) { kdb_printf("kdb_putarea: Bad address 0x%lx\n", addr); diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c index f8ae5467986511a5c406d192b7113c4624bfc25a..10d07ace46c15d22873ee44de06b703319123987 100644 --- a/kernel/dma/debug.c +++ b/kernel/dma/debug.c @@ -928,7 +928,7 @@ static __init int dma_debug_cmdline(char *str) global_disable = true; } - return 1; + return 0; } static __init int dma_debug_entries_cmdline(char *str) @@ -937,7 +937,7 @@ static __init int dma_debug_entries_cmdline(char *str) return -EINVAL; if (!get_option(&str, &nr_prealloc_entries)) nr_prealloc_entries = PREALLOC_DMA_DEBUG_ENTRIES; - return 1; + return 0; } __setup("dma_debug=", dma_debug_cmdline); diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index aca0690550e2fc660d65bcb9c57abcd1a63c157f..87c40517e82274718bd77e16cbf10f736299abb4 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -579,8 +579,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, mem->slots[index + i].orig_addr = slot_addr(orig_addr, i); tlb_addr = slot_addr(mem->start, index) + offset; if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && - (!(attrs & DMA_ATTR_OVERWRITE) || dir == DMA_TO_DEVICE || - dir == DMA_BIDIRECTIONAL)) + (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE); return tlb_addr; } diff --git a/kernel/events/core.c b/kernel/events/core.c index 9554e408cda60ec7fdef28bdcab0b9be471d0114..f58a026dd2d3042eca865ca4137032f430b93dec 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10266,11 +10266,8 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr, } /* ready to consume more filters */ - kfree(filename); - filename = NULL; state = IF_STATE_ACTION; filter = NULL; - kernel = 0; } } diff --git a/kernel/exit.c b/kernel/exit.c index f61ac326daabd260c57191943112fa5ca4c3a20b..24a302ecde59f4ba24cf76201c583ee9acfb64f7 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -423,6 +423,7 @@ assign_new_owner: goto retry; } WRITE_ONCE(mm->owner, c); + lru_gen_migrate_mm(mm); task_unlock(c); put_task_struct(c); } diff --git a/kernel/fork.c b/kernel/fork.c index 7ea0443320fafc3ef6706a3e6bb72b2922e8f46a..965d97bec20e3de5d9164cbd1dccec698186d35c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -375,14 +375,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) *new = data_race(*orig); INIT_VMA(new); new->vm_next = new->vm_prev = NULL; - dup_vma_anon_name(orig, new); + dup_anon_vma_name(orig, new); } return new; } void vm_area_free(struct vm_area_struct *vma) { - free_vma_anon_name(vma); + free_anon_vma_name(vma); kmem_cache_free(vm_area_cachep, vma); } @@ -1100,6 +1100,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, goto fail_nocontext; mm->user_ns = get_user_ns(user_ns); + lru_gen_init_mm(mm); return mm; fail_nocontext: @@ -1142,6 +1143,7 @@ static inline void __mmput(struct mm_struct *mm) } if (mm->binfmt) module_put(mm->binfmt->module); + lru_gen_del_mm(mm); mmdrop(mm); } @@ -2537,6 +2539,13 @@ pid_t kernel_clone(struct kernel_clone_args *args) get_task_struct(p); } + if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { + /* lock the task to synchronize with memcg migration */ + task_lock(p); + lru_gen_add_mm(p->mm); + task_unlock(p); + } + wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ diff --git a/kernel/futex.c b/kernel/futex.c index 3cd0ae850fdef9f7649ca2eff78ae3d2eac7e6d8..20b27a9551e730858f72db3b4b66c16e6465f27e 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -587,7 +587,7 @@ again: lock_page(page); shmem_swizzled = PageSwapCache(page) || page->mapping; unlock_page(page); - put_user_page(page); + put_page(page); if (shmem_swizzled) goto again; @@ -637,7 +637,7 @@ again: if (READ_ONCE(page->mapping) != mapping) { rcu_read_unlock(); - put_user_page(page); + put_page(page); goto again; } @@ -645,7 +645,7 @@ again: inode = READ_ONCE(mapping->host); if (!inode) { rcu_read_unlock(); - put_user_page(page); + put_page(page); goto again; } @@ -657,7 +657,7 @@ again: } out: - put_user_page(page); + put_page(page); return err; } diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index e8bdce6fdd6479534becc6712d356330932a20f0..f76fdb9255323d809d58495da99882a6710cd855 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -191,7 +191,7 @@ static int klp_find_object_symbol(const char *objname, const char *name, return -EINVAL; } -static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab, +static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symndx, Elf_Shdr *relasec, const char *sec_objname) { @@ -219,7 +219,7 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const char *strtab, relas = (Elf_Rela *) relasec->sh_addr; /* For each rela in this klp relocation section */ for (i = 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) { - sym = (Elf_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info); + sym = (Elf64_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info); if (sym->st_shndx != SHN_LIVEPATCH) { pr_err("symbol %s is not marked as a livepatch symbol\n", strtab + sym->st_name); diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index b6683cefe19a4950af2a2be057401593d38c8472..af4b35450556ff9a3165307edfa54c69b6e78b32 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -182,9 +182,11 @@ static DECLARE_BITMAP(list_entries_in_use, MAX_LOCKDEP_ENTRIES); static struct hlist_head lock_keys_hash[KEYHASH_SIZE]; unsigned long nr_lock_classes; unsigned long nr_zapped_classes; -unsigned long max_lock_class_idx; +#ifndef CONFIG_DEBUG_LOCKDEP +static +#endif struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; -DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); +static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); static inline struct lock_class *hlock_class(struct held_lock *hlock) { @@ -335,7 +337,7 @@ static inline void lock_release_holdtime(struct held_lock *hlock) * elements. These elements are linked together by the lock_entry member in * struct lock_class. */ -static LIST_HEAD(all_lock_classes); +LIST_HEAD(all_lock_classes); static LIST_HEAD(free_lock_classes); /** @@ -1237,7 +1239,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) struct lockdep_subclass_key *key; struct hlist_head *hash_head; struct lock_class *class; - int idx; DEBUG_LOCKS_WARN_ON(!irqs_disabled()); @@ -1303,9 +1304,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) * of classes. */ list_move_tail(&class->lock_entry, &all_lock_classes); - idx = class - lock_classes; - if (idx > max_lock_class_idx) - max_lock_class_idx = idx; if (verbose(class)) { graph_unlock(); @@ -5921,8 +5919,6 @@ static void zap_class(struct pending_free *pf, struct lock_class *class) WRITE_ONCE(class->name, NULL); nr_lock_classes--; __clear_bit(class - lock_classes, lock_classes_in_use); - if (class - lock_classes == max_lock_class_idx) - max_lock_class_idx--; } else { WARN_ONCE(true, "%s() failed for class %s\n", __func__, class->name); @@ -6213,13 +6209,7 @@ void lockdep_reset_lock(struct lockdep_map *lock) lockdep_reset_lock_reg(lock); } -/* - * Unregister a dynamically allocated key. - * - * Unlike lockdep_register_key(), a search is always done to find a matching - * key irrespective of debug_locks to avoid potential invalid access to freed - * memory in lock_class entry. - */ +/* Unregister a dynamically allocated key. */ void lockdep_unregister_key(struct lock_class_key *key) { struct hlist_head *hash_head = keyhashentry(key); @@ -6234,8 +6224,10 @@ void lockdep_unregister_key(struct lock_class_key *key) return; raw_local_irq_save(flags); - lockdep_lock(); + if (!graph_lock()) + goto out_irq; + pf = get_pending_free(); hlist_for_each_entry_rcu(k, hash_head, hash_entry) { if (k == key) { hlist_del_rcu(&k->hash_entry); @@ -6243,13 +6235,11 @@ void lockdep_unregister_key(struct lock_class_key *key) break; } } - WARN_ON_ONCE(!found && debug_locks); - if (found) { - pf = get_pending_free(); - __lockdep_free_key_range(pf, key, 1); - call_rcu_zapped(pf); - } - lockdep_unlock(); + WARN_ON_ONCE(!found); + __lockdep_free_key_range(pf, key, 1); + call_rcu_zapped(pf); + graph_unlock(); +out_irq: raw_local_irq_restore(flags); /* Wait until is_dynamic_key() has finished accessing k->hash_entry. */ diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_internals.h index a19b016353478f844eaa758880939925e62cd82d..de49f9e1c11ba8be13fffcda9159c9c91db16e85 100644 --- a/kernel/locking/lockdep_internals.h +++ b/kernel/locking/lockdep_internals.h @@ -121,6 +121,7 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ = #define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5) +extern struct list_head all_lock_classes; extern struct lock_chain lock_chains[]; #define LOCK_USAGE_CHARS (2*XXX_LOCK_USAGE_STATES + 1) @@ -150,10 +151,6 @@ extern unsigned int nr_large_chain_blocks; extern unsigned int max_lockdep_depth; extern unsigned int max_bfs_queue_depth; -extern unsigned long max_lock_class_idx; - -extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; -extern unsigned long lock_classes_in_use[]; #ifdef CONFIG_PROVE_LOCKING extern unsigned long lockdep_count_forward_deps(struct lock_class *); @@ -208,6 +205,7 @@ struct lockdep_stats { }; DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats); +extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; #define __debug_atomic_inc(ptr) \ this_cpu_inc(lockdep_stats.ptr); diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c index ccb5292d1e1944bae1150d14f4103588aea1b1f5..02ef87f50df29c2a53dbf7b27320e1001fe09e33 100644 --- a/kernel/locking/lockdep_proc.c +++ b/kernel/locking/lockdep_proc.c @@ -24,33 +24,14 @@ #include "lockdep_internals.h" -/* - * Since iteration of lock_classes is done without holding the lockdep lock, - * it is not safe to iterate all_lock_classes list directly as the iteration - * may branch off to free_lock_classes or the zapped list. Iteration is done - * directly on the lock_classes array by checking the lock_classes_in_use - * bitmap and max_lock_class_idx. - */ -#define iterate_lock_classes(idx, class) \ - for (idx = 0, class = lock_classes; idx <= max_lock_class_idx; \ - idx++, class++) - static void *l_next(struct seq_file *m, void *v, loff_t *pos) { - struct lock_class *class = v; - - ++class; - *pos = class - lock_classes; - return (*pos > max_lock_class_idx) ? NULL : class; + return seq_list_next(v, &all_lock_classes, pos); } static void *l_start(struct seq_file *m, loff_t *pos) { - unsigned long idx = *pos; - - if (idx > max_lock_class_idx) - return NULL; - return lock_classes + idx; + return seq_list_start_head(&all_lock_classes, *pos); } static void l_stop(struct seq_file *m, void *v) @@ -76,16 +57,14 @@ static void print_name(struct seq_file *m, struct lock_class *class) static int l_show(struct seq_file *m, void *v) { - struct lock_class *class = v; + struct lock_class *class = list_entry(v, struct lock_class, lock_entry); struct lock_list *entry; char usage[LOCK_USAGE_CHARS]; - int idx = class - lock_classes; - if (v == lock_classes) + if (v == &all_lock_classes) { seq_printf(m, "all lock classes:\n"); - - if (!test_bit(idx, lock_classes_in_use)) return 0; + } seq_printf(m, "%p", class->key); #ifdef CONFIG_DEBUG_LOCKDEP @@ -239,11 +218,8 @@ static int lockdep_stats_show(struct seq_file *m, void *v) #ifdef CONFIG_PROVE_LOCKING struct lock_class *class; - unsigned long idx; - iterate_lock_classes(idx, class) { - if (!test_bit(idx, lock_classes_in_use)) - continue; + list_for_each_entry(class, &all_lock_classes, lock_entry) { if (class->usage_mask == 0) nr_unused++; @@ -276,7 +252,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v) sum_forward_deps += lockdep_count_forward_deps(class); } - #ifdef CONFIG_DEBUG_LOCKDEP DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused); #endif @@ -368,8 +343,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v) seq_printf(m, " max bfs queue depth: %11u\n", max_bfs_queue_depth); #endif - seq_printf(m, " max lock class index: %11lu\n", - max_lock_class_idx); lockdep_stats_debug_show(m); seq_printf(m, " debug_locks: %11u\n", debug_locks); @@ -647,16 +620,12 @@ static int lock_stat_open(struct inode *inode, struct file *file) if (!res) { struct lock_stat_data *iter = data->stats; struct seq_file *m = file->private_data; - unsigned long idx; - iterate_lock_classes(idx, class) { - if (!test_bit(idx, lock_classes_in_use)) - continue; + list_for_each_entry(class, &all_lock_classes, lock_entry) { iter->class = class; iter->stats = lock_stats(class); iter++; } - data->iter_end = iter; sort(data->stats, data->iter_end - data->stats, @@ -674,7 +643,6 @@ static ssize_t lock_stat_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct lock_class *class; - unsigned long idx; char c; if (count) { @@ -684,11 +652,8 @@ static ssize_t lock_stat_write(struct file *file, const char __user *buf, if (c != '0') return count; - iterate_lock_classes(idx, class) { - if (!test_bit(idx, lock_classes_in_use)) - continue; + list_for_each_entry(class, &all_lock_classes, lock_entry) clear_lock_stats(class); - } } return count; } diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 731aca37637dc3949308e47dcc9d817e89b88583..b13fe337fa51e179c8ea51670c696038822b7b76 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1323,7 +1323,7 @@ static int __init resumedelay_setup(char *str) int rc = kstrtouint(str, 0, &resume_delay); if (rc) - pr_warn("resumedelay: bad option string '%s'\n", str); + return rc; return 1; } diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index be480ae5cb2aa1da01379025ff4f862bbb2aef94..e1ed58adb69e480b8537bf4a37b2d2e1f23be9b2 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -157,22 +157,22 @@ static int __init setup_test_suspend(char *value) value++; suspend_type = strsep(&value, ","); if (!suspend_type) - return 1; + return 0; repeat = strsep(&value, ","); if (repeat) { if (kstrtou32(repeat, 0, &test_repeat_count_max)) - return 1; + return 0; } for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) if (!strcmp(pm_labels[i], suspend_type)) { test_state_label = pm_labels[i]; - return 1; + return 0; } printk(warn_bad_state, suspend_type); - return 1; + return 0; } __setup("test_suspend", setup_test_suspend); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 3a1af08a3636ac3e8aaf30707ecb182a1f3f298c..db4a07651bc1ddc304d2f9628fa89a3621b3aa01 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -149,10 +149,8 @@ static int __control_devkmsg(char *str) static int __init control_devkmsg(char *str) { - if (__control_devkmsg(str) < 0) { - pr_warn("printk.devkmsg: bad option string '%s'\n", str); + if (__control_devkmsg(str) < 0) return 1; - } /* * Set sysctl string accordingly: @@ -171,7 +169,7 @@ static int __init control_devkmsg(char *str) */ devkmsg_log |= DEVKMSG_LOG_MASK_LOCK; - return 1; + return 0; } __setup("printk.devkmsg=", control_devkmsg); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index d99f73f83bf5fbcaf80c2832fc9bdb10dc9b77b9..eb4d04cb3aaf55914befc3a346ef7411b452ee4a 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -370,26 +370,6 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) return !err; } -static int check_ptrace_options(unsigned long data) -{ - if (data & ~(unsigned long)PTRACE_O_MASK) - return -EINVAL; - - if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { - if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || - !IS_ENABLED(CONFIG_SECCOMP)) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || - current->ptrace & PT_SUSPEND_SECCOMP) - return -EPERM; - } - return 0; -} - static int ptrace_attach(struct task_struct *task, long request, unsigned long addr, unsigned long flags) @@ -401,16 +381,8 @@ static int ptrace_attach(struct task_struct *task, long request, if (seize) { if (addr != 0) goto out; - /* - * This duplicates the check in check_ptrace_options() because - * ptrace_attach() and ptrace_setoptions() have historically - * used different error codes for unknown ptrace options. - */ if (flags & ~(unsigned long)PTRACE_O_MASK) goto out; - retval = check_ptrace_options(flags); - if (retval) - return retval; flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT); } else { flags = PT_PTRACED; @@ -683,11 +655,22 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds static int ptrace_setoptions(struct task_struct *child, unsigned long data) { unsigned flags; - int ret; - ret = check_ptrace_options(data); - if (ret) - return ret; + if (data & ~(unsigned long)PTRACE_O_MASK) + return -EINVAL; + + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { + if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || + !IS_ENABLED(CONFIG_SECCOMP)) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || + current->ptrace & PT_SUSPEND_SECCOMP) + return -EPERM; + } /* Avoid intermediate state when all opts are cleared */ flags = child->ptrace; diff --git a/kernel/rcu/Kconfig b/kernel/rcu/Kconfig index b71e21f73c40364e3fb78b03a5a30cab22e192ea..97bfe2a891dbc9766329ed1f4fa61c1f2b25b83e 100644 --- a/kernel/rcu/Kconfig +++ b/kernel/rcu/Kconfig @@ -212,6 +212,20 @@ config RCU_BOOST_DELAY Accept the default if unsure. +config RCU_EXP_KTHREAD + bool "Perform RCU expedited work in a real-time kthread" + depends on RCU_BOOST && RCU_EXPERT + default !PREEMPT_RT && NR_CPUS <= 32 + help + Use this option to further reduce the latencies of expedited + grace periods at the expense of being more disruptive. + + This option is disabled by default on PREEMPT_RT=y kernels which + disable expedited grace periods after boot by unconditionally + setting rcupdate.rcu_normal_after_boot=1. + + Accept the default if unsure. + config RCU_NOCB_CPU bool "Offload RCU callback processing from boot-selected CPUs" depends on TREE_RCU diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index fcf95d1eec69ab1bb70612bae2d59a410bdc43c6..7befcfae5fb5ac84d55988f122d90bd903fdfa47 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -524,7 +524,12 @@ int rcu_get_gp_kthreads_prio(void); void rcu_fwd_progress_check(unsigned long j); void rcu_force_quiescent_state(void); extern struct workqueue_struct *rcu_gp_wq; +#ifdef CONFIG_RCU_EXP_KTHREAD +extern struct kthread_worker *rcu_exp_gp_kworker; +extern struct kthread_worker *rcu_exp_par_gp_kworker; +#else /* !CONFIG_RCU_EXP_KTHREAD */ extern struct workqueue_struct *rcu_par_gp_wq; +#endif /* CONFIG_RCU_EXP_KTHREAD */ #endif /* #else #ifdef CONFIG_TINY_RCU */ #ifdef CONFIG_RCU_NOCB_CPU diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 1628dcb6e45a8eaf9b0918ce323308c641179ae8..5b5f80ad0e7aaa1463d89000993ca5efe7ad4a69 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4234,6 +4234,51 @@ static int rcu_pm_notify(struct notifier_block *self, return NOTIFY_OK; } +#ifdef CONFIG_RCU_EXP_KTHREAD +struct kthread_worker *rcu_exp_gp_kworker; +struct kthread_worker *rcu_exp_par_gp_kworker; + +static void __init rcu_start_exp_gp_kworkers(void) +{ + const char *par_gp_kworker_name = "rcu_exp_par_gp_kthread_worker"; + const char *gp_kworker_name = "rcu_exp_gp_kthread_worker"; + struct sched_param param = { .sched_priority = kthread_prio }; + + rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name); + if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) { + pr_err("Failed to create %s!\n", gp_kworker_name); + return; + } + + rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name); + if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) { + pr_err("Failed to create %s!\n", par_gp_kworker_name); + kthread_destroy_worker(rcu_exp_gp_kworker); + return; + } + + sched_setscheduler_nocheck(rcu_exp_gp_kworker->task, SCHED_FIFO, ¶m); + sched_setscheduler_nocheck(rcu_exp_par_gp_kworker->task, SCHED_FIFO, + ¶m); +} + +static inline void rcu_alloc_par_gp_wq(void) +{ +} +#else /* !CONFIG_RCU_EXP_KTHREAD */ +struct workqueue_struct *rcu_par_gp_wq; + +static void __init rcu_start_exp_gp_kworkers(void) +{ +} + +static inline void rcu_alloc_par_gp_wq(void) +{ + rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0); + WARN_ON(!rcu_par_gp_wq); +} +#endif /* CONFIG_RCU_EXP_KTHREAD */ + /* * Spawn the kthreads that handle RCU's grace periods. */ @@ -4279,6 +4324,8 @@ static int __init rcu_spawn_gp_kthread(void) rcu_spawn_nocb_kthreads(); rcu_spawn_boost_kthreads(); rcu_spawn_core_kthreads(); + /* Create kthread worker for expedited GPs */ + rcu_start_exp_gp_kworkers(); return 0; } early_initcall(rcu_spawn_gp_kthread); @@ -4501,7 +4548,6 @@ static void __init rcu_dump_rcu_node_tree(void) } struct workqueue_struct *rcu_gp_wq; -struct workqueue_struct *rcu_par_gp_wq; static void __init kfree_rcu_batch_init(void) { @@ -4554,8 +4600,7 @@ void __init rcu_init(void) /* Create workqueue for expedited GPs and for Tree SRCU. */ rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0); WARN_ON(!rcu_gp_wq); - rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0); - WARN_ON(!rcu_par_gp_wq); + rcu_alloc_par_gp_wq(); srcu_init(); /* Fill in default value for rcutree.qovld boot parameter. */ diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index e4f66b8f7c470109d30ab62458b8ee5b2d736262..12432de6c92039bb6f7b5e33d72975bac430002d 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -23,7 +24,11 @@ /* Communicate arguments to a workqueue handler. */ struct rcu_exp_work { unsigned long rew_s; +#ifdef CONFIG_RCU_EXP_KTHREAD + struct kthread_work rew_work; +#else struct work_struct rew_work; +#endif /* CONFIG_RCU_EXP_KTHREAD */ }; /* RCU's kthread states for tracing. */ diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index 6aeb5f517ce2c7ba2980230f6dc46ca629a43ebf..bde4080a936f11aed2f36c60a81bad6acc5f9ae6 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -334,15 +334,13 @@ fastpath: * Select the CPUs within the specified rcu_node that the upcoming * expedited grace period needs to wait for. */ -static void sync_rcu_exp_select_node_cpus(struct work_struct *wp) +static void __sync_rcu_exp_select_node_cpus(struct rcu_exp_work *rewp) { int cpu; unsigned long flags; unsigned long mask_ofl_test; unsigned long mask_ofl_ipi; int ret; - struct rcu_exp_work *rewp = - container_of(wp, struct rcu_exp_work, rew_work); struct rcu_node *rnp = container_of(rewp, struct rcu_node, rew); raw_spin_lock_irqsave_rcu_node(rnp, flags); @@ -417,13 +415,119 @@ retry_ipi: rcu_report_exp_cpu_mult(rnp, mask_ofl_test, false); } +static void rcu_exp_sel_wait_wake(unsigned long s); + +#ifdef CONFIG_RCU_EXP_KTHREAD +static void sync_rcu_exp_select_node_cpus(struct kthread_work *wp) +{ + struct rcu_exp_work *rewp = + container_of(wp, struct rcu_exp_work, rew_work); + + __sync_rcu_exp_select_node_cpus(rewp); +} + +static inline bool rcu_gp_par_worker_started(void) +{ + return !!READ_ONCE(rcu_exp_par_gp_kworker); +} + +static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp) +{ + kthread_init_work(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus); + /* + * Use rcu_exp_par_gp_kworker, because flushing a work item from + * another work item on the same kthread worker can result in + * deadlock. + */ + kthread_queue_work(rcu_exp_par_gp_kworker, &rnp->rew.rew_work); +} + +static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp) +{ + kthread_flush_work(&rnp->rew.rew_work); +} + +/* + * Work-queue handler to drive an expedited grace period forward. + */ +static void wait_rcu_exp_gp(struct kthread_work *wp) +{ + struct rcu_exp_work *rewp; + + rewp = container_of(wp, struct rcu_exp_work, rew_work); + rcu_exp_sel_wait_wake(rewp->rew_s); +} + +static inline void synchronize_rcu_expedited_queue_work(struct rcu_exp_work *rew) +{ + kthread_init_work(&rew->rew_work, wait_rcu_exp_gp); + kthread_queue_work(rcu_exp_gp_kworker, &rew->rew_work); +} + +static inline void synchronize_rcu_expedited_destroy_work(struct rcu_exp_work *rew) +{ +} +#else /* !CONFIG_RCU_EXP_KTHREAD */ +static void sync_rcu_exp_select_node_cpus(struct work_struct *wp) +{ + struct rcu_exp_work *rewp = + container_of(wp, struct rcu_exp_work, rew_work); + + __sync_rcu_exp_select_node_cpus(rewp); +} + +static inline bool rcu_gp_par_worker_started(void) +{ + return !!READ_ONCE(rcu_par_gp_wq); +} + +static inline void sync_rcu_exp_select_cpus_queue_work(struct rcu_node *rnp) +{ + int cpu = find_next_bit(&rnp->ffmask, BITS_PER_LONG, -1); + + INIT_WORK(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus); + /* If all offline, queue the work on an unbound CPU. */ + if (unlikely(cpu > rnp->grphi - rnp->grplo)) + cpu = WORK_CPU_UNBOUND; + else + cpu += rnp->grplo; + queue_work_on(cpu, rcu_par_gp_wq, &rnp->rew.rew_work); +} + +static inline void sync_rcu_exp_select_cpus_flush_work(struct rcu_node *rnp) +{ + flush_work(&rnp->rew.rew_work); +} + +/* + * Work-queue handler to drive an expedited grace period forward. + */ +static void wait_rcu_exp_gp(struct work_struct *wp) +{ + struct rcu_exp_work *rewp; + + rewp = container_of(wp, struct rcu_exp_work, rew_work); + rcu_exp_sel_wait_wake(rewp->rew_s); +} + +static inline void synchronize_rcu_expedited_queue_work(struct rcu_exp_work *rew) +{ + INIT_WORK_ONSTACK(&rew->rew_work, wait_rcu_exp_gp); + queue_work(rcu_gp_wq, &rew->rew_work); +} + +static inline void synchronize_rcu_expedited_destroy_work(struct rcu_exp_work *rew) +{ + destroy_work_on_stack(&rew->rew_work); +} +#endif /* CONFIG_RCU_EXP_KTHREAD */ + /* * Select the nodes that the upcoming expedited grace period needs * to wait for. */ static void sync_rcu_exp_select_cpus(void) { - int cpu; struct rcu_node *rnp; trace_rcu_exp_grace_period(rcu_state.name, rcu_exp_gp_seq_endval(), TPS("reset")); @@ -435,28 +539,21 @@ static void sync_rcu_exp_select_cpus(void) rnp->exp_need_flush = false; if (!READ_ONCE(rnp->expmask)) continue; /* Avoid early boot non-existent wq. */ - if (!READ_ONCE(rcu_par_gp_wq) || + if (!rcu_gp_par_worker_started() || rcu_scheduler_active != RCU_SCHEDULER_RUNNING || rcu_is_last_leaf_node(rnp)) { - /* No workqueues yet or last leaf, do direct call. */ + /* No worker started yet or last leaf, do direct call. */ sync_rcu_exp_select_node_cpus(&rnp->rew.rew_work); continue; } - INIT_WORK(&rnp->rew.rew_work, sync_rcu_exp_select_node_cpus); - cpu = find_next_bit(&rnp->ffmask, BITS_PER_LONG, -1); - /* If all offline, queue the work on an unbound CPU. */ - if (unlikely(cpu > rnp->grphi - rnp->grplo)) - cpu = WORK_CPU_UNBOUND; - else - cpu += rnp->grplo; - queue_work_on(cpu, rcu_par_gp_wq, &rnp->rew.rew_work); + sync_rcu_exp_select_cpus_queue_work(rnp); rnp->exp_need_flush = true; } - /* Wait for workqueue jobs (if any) to complete. */ + /* Wait for jobs (if any) to complete. */ rcu_for_each_leaf_node(rnp) if (rnp->exp_need_flush) - flush_work(&rnp->rew.rew_work); + sync_rcu_exp_select_cpus_flush_work(rnp); } /* @@ -619,17 +716,6 @@ static void rcu_exp_sel_wait_wake(unsigned long s) rcu_exp_wait_wake(s); } -/* - * Work-queue handler to drive an expedited grace period forward. - */ -static void wait_rcu_exp_gp(struct work_struct *wp) -{ - struct rcu_exp_work *rewp; - - rewp = container_of(wp, struct rcu_exp_work, rew_work); - rcu_exp_sel_wait_wake(rewp->rew_s); -} - #ifdef CONFIG_PREEMPT_RCU /* @@ -845,20 +931,19 @@ void synchronize_rcu_expedited(void) } else { /* Marshall arguments & schedule the expedited grace period. */ rew.rew_s = s; - INIT_WORK_ONSTACK(&rew.rew_work, wait_rcu_exp_gp); - queue_work(rcu_gp_wq, &rew.rew_work); + synchronize_rcu_expedited_queue_work(&rew); } /* Wait for expedited grace period to complete. */ rnp = rcu_get_root(); wait_event(rnp->exp_wq[rcu_seq_ctr(s) & 0x3], sync_exp_work_done(s)); - smp_mb(); /* Workqueue actions happen before return. */ + smp_mb(); /* Work actions happen before return. */ /* Let the next expedited grace period start. */ mutex_unlock(&rcu_state.exp_mutex); if (likely(!boottime)) - destroy_work_on_stack(&rew.rew_work); + synchronize_rcu_expedited_destroy_work(&rew); } EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index f5ba0740f9b504995637cef51f22a1ae7db2f867..39e8f78182a8558f03466e7179c05ddc340b9ec3 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -541,7 +541,6 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags) /* Unboost if we were boosted. */ if (IS_ENABLED(CONFIG_RCU_BOOST) && drop_boost_mutex) rt_mutex_futex_unlock(&rnp->boost_mtx); - } else { local_irq_restore(flags); } diff --git a/kernel/rseq.c b/kernel/rseq.c index 6ca29dddceabc7e96e8495d6a3c9b50c71eb81c4..0077713bf2400126caacd3f8900143adab5edea3 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -120,13 +120,8 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) u32 sig; int ret; -#ifdef CONFIG_64BIT - if (get_user(ptr, &t->rseq->rseq_cs)) + if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr))) return -EFAULT; -#else - if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr))) - return -EFAULT; -#endif if (!ptr) { memset(rseq_cs, 0, sizeof(*rseq_cs)); return 0; @@ -209,13 +204,9 @@ static int clear_rseq_cs(struct task_struct *t) * * Set rseq_cs to NULL. */ -#ifdef CONFIG_64BIT - return put_user(0UL, &t->rseq->rseq_cs); -#else - if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs))) + if (clear_user(&t->rseq->rseq_cs.ptr64, sizeof(t->rseq->rseq_cs.ptr64))) return -EFAULT; return 0; -#endif } /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index ad3bc6b0ae065e846635066e7516b8ee58ded1a8..507ed2aed0e8ee8d581ddfe8de13e867e40fb290 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -39,7 +39,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp); -EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_thermal_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_cpu_capacity_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp); @@ -4004,6 +4003,7 @@ context_switch(struct rq *rq, struct task_struct *prev, * finish_task_switch()'s mmdrop(). */ switch_mm_irqs_off(prev->active_mm, next->mm, next); + lru_gen_use_mm(next->mm); if (!prev->mm) { // from kernel /* will mmdrop() in finish_task_switch(). */ diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index f799bcb36071cf39e4c575cb95f54abee60d9f25..9c95334d857e29824087c430e1c08d81c1b70580 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -910,15 +910,25 @@ void print_numa_stats(struct seq_file *m, int node, unsigned long tsf, static void sched_show_numa(struct task_struct *p, struct seq_file *m) { #ifdef CONFIG_NUMA_BALANCING + struct mempolicy *pol; + if (p->mm) P(mm->numa_scan_seq); + task_lock(p); + pol = p->mempolicy; + if (pol && !(pol->flags & MPOL_F_MORON)) + pol = NULL; + mpol_get(pol); + task_unlock(p); + P(numa_pages_migrated); P(numa_preferred_nid); P(total_numa_faults); SEQ_printf(m, "current_node=%d, numa_group_id=%d\n", task_node(p), task_numa_group_id(p)); show_numa_stats(p, m); + mpol_put(pol); #endif } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 4d478fe31f98b65179953b244db6aad992c65463..ff561e3763f4b6ad1c4605e8460c88e713541fc2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3763,6 +3763,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se)); } + trace_android_rvh_attach_entity_load_avg(cfs_rq, se); + enqueue_load_avg(cfs_rq, se); cfs_rq->avg.util_avg += se->avg.util_avg; cfs_rq->avg.util_sum += se->avg.util_sum; @@ -3786,6 +3788,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s */ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { + trace_android_rvh_detach_entity_load_avg(cfs_rq, se); + dequeue_load_avg(cfs_rq, se); sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg); sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum); @@ -3825,6 +3829,8 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s decayed = update_cfs_rq_load_avg(now, cfs_rq); decayed |= propagate_entity_load_avg(se); + trace_android_rvh_update_load_avg(now, cfs_rq, se); + if (!se->avg.last_update_time && (flags & DO_ATTACH)) { /* @@ -3896,6 +3902,8 @@ static void remove_entity_load_avg(struct sched_entity *se) sync_entity_load_avg(se); + trace_android_rvh_remove_entity_load_avg(cfs_rq, se); + raw_spin_lock_irqsave(&cfs_rq->removed.lock, flags); ++cfs_rq->removed.nr; cfs_rq->removed.util_avg += se->avg.util_avg; @@ -8108,6 +8116,8 @@ static bool __update_blocked_fair(struct rq *rq, bool *done) bool decayed = false; int cpu = cpu_of(rq); + trace_android_rvh_update_blocked_fair(rq); + /* * Iterates the task_group tree in a bottom up fashion, see * list_add_leaf_cfs_rq() for details. diff --git a/kernel/sched/pelt.c b/kernel/sched/pelt.c index cd54fab42cf4eb7a8794440365866fb0ce993aca..e15a2fad146ef61a6e92db5e8c4b3373fca667af 100644 --- a/kernel/sched/pelt.c +++ b/kernel/sched/pelt.c @@ -30,6 +30,7 @@ int pelt_load_avg_period = PELT32_LOAD_AVG_PERIOD; int pelt_load_avg_max = PELT32_LOAD_AVG_MAX; +EXPORT_SYMBOL_GPL(pelt_load_avg_max); const u32 *pelt_runnable_avg_yN_inv = pelt32_runnable_avg_yN_inv; static int __init set_pelt(char *str) @@ -216,9 +217,8 @@ accumulate_sum(u64 delta, struct sched_avg *sa, * load_avg = u_0` + y*(u_0 + u_1*y + u_2*y^2 + ... ) * = u_0 + u_1*y + u_2*y^2 + ... [re-labeling u_i --> u_{i+1}] */ -static __always_inline int -___update_load_sum(u64 now, struct sched_avg *sa, - unsigned long load, unsigned long runnable, int running) +int ___update_load_sum(u64 now, struct sched_avg *sa, + unsigned long load, unsigned long runnable, int running) { u64 delta; @@ -268,6 +268,7 @@ ___update_load_sum(u64 now, struct sched_avg *sa, return 1; } +EXPORT_SYMBOL_GPL(___update_load_sum); /* * When syncing *_avg with *_sum, we must take into account the current @@ -293,8 +294,7 @@ ___update_load_sum(u64 now, struct sched_avg *sa, * the period_contrib of cfs_rq when updating the sched_avg of a sched_entity * if it's more convenient. */ -static __always_inline void -___update_load_avg(struct sched_avg *sa, unsigned long load) +void ___update_load_avg(struct sched_avg *sa, unsigned long load) { u32 divider = get_pelt_divider(sa); @@ -305,6 +305,7 @@ ___update_load_avg(struct sched_avg *sa, unsigned long load) sa->runnable_avg = div_u64(sa->runnable_sum, divider); WRITE_ONCE(sa->util_avg, sa->util_sum / divider); } +EXPORT_SYMBOL_GPL(___update_load_avg); /* * sched_entity: diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index d7e73977b0aed27659ce581da69bdf28d9a68bd6..3e1866534db52091dfff129398efa4dcb4b1b30b 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1685,6 +1685,7 @@ static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool f */ if (rq->curr->sched_class != &rt_sched_class) update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 0); + trace_android_rvh_update_rt_rq_load_avg(rq_clock_pelt(rq), rq, p, 0); rt_queue_push_tasks(rq); } @@ -1737,6 +1738,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) update_curr_rt(rq); update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1); + trace_android_rvh_update_rt_rq_load_avg(rq_clock_pelt(rq), rq, p, 1); /* * The previous task needs to be made eligible for pushing @@ -2500,6 +2502,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) update_curr_rt(rq); update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1); + trace_android_rvh_update_rt_rq_load_avg(rq_clock_pelt(rq), rq, p, 1); watchdog(rq, p); diff --git a/kernel/scs.c b/kernel/scs.c index b83bc9251f996ee3d5d109b7eebd0af041e1ae92..b7e1b096d90601bfb2dc6a2a3646c2928d22dc1d 100644 --- a/kernel/scs.c +++ b/kernel/scs.c @@ -32,15 +32,19 @@ static void *__scs_alloc(int node) for (i = 0; i < NR_CACHED_SCS; i++) { s = this_cpu_xchg(scs_cache[i], NULL); if (s) { - kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_NONE); + s = kasan_unpoison_vmalloc(s, SCS_SIZE, + KASAN_VMALLOC_PROT_NORMAL); memset(s, 0, SCS_SIZE); - return s; + goto out; } } - return __vmalloc_node_range(SCS_SIZE, 1, VMALLOC_START, VMALLOC_END, + s = __vmalloc_node_range(SCS_SIZE, 1, VMALLOC_START, VMALLOC_END, GFP_SCS, PAGE_KERNEL, 0, node, __builtin_return_address(0)); + +out: + return kasan_reset_tag(s); } void *scs_alloc(int node) @@ -78,7 +82,7 @@ void scs_free(void *s) if (this_cpu_cmpxchg(scs_cache[i], 0, s) == NULL) return; - kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_NONE); + kasan_unpoison_vmalloc(s, SCS_SIZE, KASAN_VMALLOC_PROT_NORMAL); vfree_atomic(s); } diff --git a/kernel/sys.c b/kernel/sys.c index ccfb6f05303e3e8dc5758fce06fce4d8adb4775e..b9c690c534345df91030b6fcc3d8cc305e7e5189 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -2298,15 +2299,16 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr, { struct mm_struct *mm = current->mm; const char __user *uname; - char *name, *pch; + struct anon_vma_name *anon_name = NULL; int error; switch (opt) { case PR_SET_VMA_ANON_NAME: uname = (const char __user *)arg; if (uname) { - name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN); + char *name, *pch; + name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN); if (IS_ERR(name)) return PTR_ERR(name); @@ -2316,15 +2318,18 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr, return -EINVAL; } } - } else { - /* Reset the name */ - name = NULL; + /* anon_vma has its own copy */ + anon_name = anon_vma_name_alloc(name); + kfree(name); + if (!anon_name) + return -ENOMEM; + } mmap_write_lock(mm); - error = madvise_set_anon_name(mm, addr, size, name); + error = madvise_set_anon_name(mm, addr, size, anon_name); mmap_write_unlock(mm); - kfree(name); + anon_vma_name_put(anon_name); break; default: error = -EINVAL; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index ed71c41410472cd7615f1d43091e5eeb30ac8cfd..1535065a7d76ad96c129e91d87f9f8909d5c1b1a 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -2053,26 +2053,44 @@ unsigned long msleep_interruptible(unsigned int msecs) EXPORT_SYMBOL(msleep_interruptible); /** - * usleep_range - Sleep for an approximate time - * @min: Minimum time in usecs to sleep - * @max: Maximum time in usecs to sleep + * usleep_range_state - Sleep for an approximate time in a given state + * @min: Minimum time in usecs to sleep + * @max: Maximum time in usecs to sleep + * @state: State of the current task that will be while sleeping * * In non-atomic context where the exact wakeup time is flexible, use - * usleep_range() instead of udelay(). The sleep improves responsiveness + * usleep_range_state() instead of udelay(). The sleep improves responsiveness * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces * power usage by allowing hrtimers to take advantage of an already- * scheduled interrupt instead of scheduling a new one just for this sleep. */ -void __sched usleep_range(unsigned long min, unsigned long max) +void __sched usleep_range_state(unsigned long min, unsigned long max, + unsigned int state) { ktime_t exp = ktime_add_us(ktime_get(), min); u64 delta = (u64)(max - min) * NSEC_PER_USEC; for (;;) { - __set_current_state(TASK_UNINTERRUPTIBLE); + __set_current_state(state); /* Do not return before the requested sleep time has elapsed */ if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS)) break; } } + +/** + * usleep_range - Sleep for an approximate time + * @min: Minimum time in usecs to sleep + * @max: Maximum time in usecs to sleep + * + * In non-atomic context where the exact wakeup time is flexible, use + * usleep_range() instead of udelay(). The sleep improves responsiveness + * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces + * power usage by allowing hrtimers to take advantage of an already- + * scheduled interrupt instead of scheduling a new one just for this sleep. + */ +void __sched usleep_range(unsigned long min, unsigned long max) +{ + usleep_range_state(min, max, TASK_UNINTERRUPTIBLE); +} EXPORT_SYMBOL(usleep_range); diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c index 249ed32591449d88b59e5eea1cc321514429717c..e3f144d9602617c5b6a77d35799dc1c0d4e1988e 100644 --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -274,7 +274,7 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) return 0; error_p: - while (--i >= 0) + for (i = 0; i < nr_pages; i++) __free_page(pages[i]); kfree(pages); error: @@ -373,7 +373,6 @@ static void __put_watch_queue(struct kref *kref) for (i = 0; i < wqueue->nr_pages; i++) __free_page(wqueue->notes[i]); - kfree(wqueue->notes); bitmap_free(wqueue->notes_bitmap); wfilter = rcu_access_pointer(wqueue->filter); @@ -399,7 +398,6 @@ static void free_watch(struct rcu_head *rcu) put_watch_queue(rcu_access_pointer(watch->queue)); atomic_dec(&watch->cred->user->nr_watches); put_cred(watch->cred); - kfree(watch); } static void __put_watch(struct kref *kref) diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c index 71e5c58530996edfc098834fcaaf53630c169ec5..0dd434e40487cf9ef032932369280fc3300520ad 100644 --- a/lib/kunit/try-catch.c +++ b/lib/kunit/try-catch.c @@ -52,7 +52,7 @@ static unsigned long kunit_test_timeout(void) * If tests timeout due to exceeding sysctl_hung_task_timeout_secs, * the task will be killed and an oops generated. */ - return 300 * msecs_to_jiffies(MSEC_PER_SEC); /* 5 min */ + return 300 * MSEC_PER_SEC; /* 5 min */ } void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index 4fb7700a741bdf289eda14ff0d2a6d27c9b8ea10..a4c7cd74cff589dcedc2efc57fa6238ea5e00006 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -4,8 +4,6 @@ # from userspace. # -pound := \# - CC = gcc OPTFLAGS = -O2 # Adjust as desired CFLAGS = -I.. -I ../../../include -g $(OPTFLAGS) @@ -44,7 +42,7 @@ else ifeq ($(HAS_NEON),yes) OBJS += neon.o neon1.o neon2.o neon4.o neon8.o recov_neon.o recov_neon_inner.o CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1 else - HAS_ALTIVEC := $(shell printf '$(pound)include \nvector int a;\n' |\ + HAS_ALTIVEC := $(shell printf '\#include \nvector int a;\n' |\ gcc -c -x c - >/dev/null && rm ./-.o && echo yes) ifeq ($(HAS_ALTIVEC),yes) CFLAGS += -I../../../arch/powerpc/include diff --git a/lib/raid6/test/test.c b/lib/raid6/test/test.c index 841a55242abaaede1c37746be8754567b5d3c270..a3cf071941ab42e7b9438f8c50c46a876a914008 100644 --- a/lib/raid6/test/test.c +++ b/lib/raid6/test/test.c @@ -19,6 +19,7 @@ #define NDISKS 16 /* Including P and Q */ const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); +struct raid6_calls raid6_call; char *dataptrs[NDISKS]; char data[NDISKS][PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 7d3c5111bbfc5ce747ba07528a3fabf16ccb5ff1..4de52eb5b93b6c911edbb75c7be9c09fdb360a93 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -37,7 +37,7 @@ void *kasan_ptr_result; int kasan_int_result; static struct kunit_resource resource; -static struct kunit_kasan_expectation fail_data; +static struct kunit_kasan_status test_status; static bool multishot; /* @@ -54,58 +54,63 @@ static int kasan_test_init(struct kunit *test) } multishot = kasan_save_enable_multi_shot(); - fail_data.report_found = false; + test_status.report_found = false; + test_status.sync_fault = false; kunit_add_named_resource(test, NULL, NULL, &resource, - "kasan_data", &fail_data); + "kasan_status", &test_status); return 0; } static void kasan_test_exit(struct kunit *test) { kasan_restore_multi_shot(multishot); - KUNIT_EXPECT_FALSE(test, fail_data.report_found); + KUNIT_EXPECT_FALSE(test, test_status.report_found); } /** * KUNIT_EXPECT_KASAN_FAIL() - check that the executed expression produces a * KASAN report; causes a test failure otherwise. This relies on a KUnit - * resource named "kasan_data". Do not use this name for KUnit resources + * resource named "kasan_status". Do not use this name for KUnit resources * outside of KASAN tests. * - * For hardware tag-based KASAN in sync mode, when a tag fault happens, tag + * For hardware tag-based KASAN, when a synchronous tag fault happens, tag * checking is auto-disabled. When this happens, this test handler reenables * tag checking. As tag checking can be only disabled or enabled per CPU, * this handler disables migration (preemption). * - * Since the compiler doesn't see that the expression can change the fail_data + * Since the compiler doesn't see that the expression can change the test_status * fields, it can reorder or optimize away the accesses to those fields. * Use READ/WRITE_ONCE() for the accesses and compiler barriers around the * expression to prevent that. * - * In between KUNIT_EXPECT_KASAN_FAIL checks, fail_data.report_found is kept as - * false. This allows detecting KASAN reports that happen outside of the checks - * by asserting !fail_data.report_found at the start of KUNIT_EXPECT_KASAN_FAIL - * and in kasan_test_exit. + * In between KUNIT_EXPECT_KASAN_FAIL checks, test_status.report_found is kept + * as false. This allows detecting KASAN reports that happen outside of the + * checks by asserting !test_status.report_found at the start of + * KUNIT_EXPECT_KASAN_FAIL and in kasan_test_exit. */ #define KUNIT_EXPECT_KASAN_FAIL(test, expression) do { \ if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ kasan_sync_fault_possible()) \ migrate_disable(); \ - KUNIT_EXPECT_FALSE(test, READ_ONCE(fail_data.report_found)); \ + KUNIT_EXPECT_FALSE(test, READ_ONCE(test_status.report_found)); \ barrier(); \ expression; \ barrier(); \ - if (!READ_ONCE(fail_data.report_found)) { \ + if (kasan_async_fault_possible()) \ + kasan_force_async_fault(); \ + if (!READ_ONCE(test_status.report_found)) { \ KUNIT_FAIL(test, KUNIT_SUBTEST_INDENT "KASAN failure " \ "expected in \"" #expression \ "\", but none occurred"); \ } \ - if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) { \ - if (READ_ONCE(fail_data.report_found)) \ - kasan_enable_tagging_sync(); \ + if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ + kasan_sync_fault_possible()) { \ + if (READ_ONCE(test_status.report_found) && \ + READ_ONCE(test_status.sync_fault)) \ + kasan_enable_tagging(); \ migrate_enable(); \ } \ - WRITE_ONCE(fail_data.report_found, false); \ + WRITE_ONCE(test_status.report_found, false); \ } while (0) #define KASAN_TEST_NEEDS_CONFIG_ON(test, config) do { \ @@ -1062,7 +1067,6 @@ static void kmalloc_double_kzfree(struct kunit *test) static void vmalloc_helpers_tags(struct kunit *test) { void *ptr; - int rv; /* This test is intended for tag-based modes. */ KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC); @@ -1080,11 +1084,17 @@ static void vmalloc_helpers_tags(struct kunit *test) KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr)); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr)); - /* Make sure vmalloc'ed memory permissions can be changed. */ - rv = set_memory_ro((unsigned long)ptr, 1); - KUNIT_ASSERT_GE(test, rv, 0); - rv = set_memory_rw((unsigned long)ptr, 1); - KUNIT_ASSERT_GE(test, rv, 0); +#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST) + { + int rv; + + /* Make sure vmalloc'ed memory permissions can be changed. */ + rv = set_memory_ro((unsigned long)ptr, 1); + KUNIT_ASSERT_GE(test, rv, 0); + rv = set_memory_rw((unsigned long)ptr, 1); + KUNIT_ASSERT_GE(test, rv, 0); + } +#endif vfree(ptr); } diff --git a/lib/test_kmod.c b/lib/test_kmod.c index c637f6b5053a902650a5babcafd07f685af5ae9e..eab52770070d63d4266f4054ac2583e896ba9804 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c @@ -1155,7 +1155,6 @@ static struct kmod_test_device *register_test_dev_kmod(void) if (ret) { pr_err("could not register misc device: %d\n", ret); free_test_dev_kmod(test_dev); - test_dev = NULL; goto out; } diff --git a/lib/test_lockup.c b/lib/test_lockup.c index 78a630bbd03dfac16a45141953cba13c6a1a7e39..5359e2d1a2f24cf0584fe1ae498fd0f7167b3952 100644 --- a/lib/test_lockup.c +++ b/lib/test_lockup.c @@ -417,14 +417,9 @@ static bool test_kernel_ptr(unsigned long addr, int size) return false; /* should be at least readable kernel address */ - if (!IS_ENABLED(CONFIG_ALTERNATE_USER_ADDRESS_SPACE) && - (access_ok((void __user *)ptr, 1) || - access_ok((void __user *)ptr + size - 1, 1))) { - pr_err("user space ptr invalid in kernel: %#lx\n", addr); - return true; - } - - if (get_kernel_nofault(buf, ptr) || + if (access_ok(ptr, 1) || + access_ok(ptr + size - 1, 1) || + get_kernel_nofault(buf, ptr) || get_kernel_nofault(buf, ptr + size - 1)) { pr_err("invalid kernel ptr: %#lx\n", addr); return true; @@ -600,5 +595,6 @@ static int __init test_lockup_init(void) module_init(test_lockup_init); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_AUTHOR("Konstantin Khlebnikov "); MODULE_DESCRIPTION("Test module to generate lockups"); diff --git a/lib/test_xarray.c b/lib/test_xarray.c index e77d4856442c3f750434e37819e13688d210048e..8b1c318189ce801a0935133b4882556fede5bfd2 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -1463,25 +1463,6 @@ unlock: XA_BUG_ON(xa, !xa_empty(xa)); } -static noinline void check_create_range_5(struct xarray *xa, - unsigned long index, unsigned int order) -{ - XA_STATE_ORDER(xas, xa, index, order); - unsigned int i; - - xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL); - - for (i = 0; i < order + 10; i++) { - do { - xas_lock(&xas); - xas_create_range(&xas); - xas_unlock(&xas); - } while (xas_nomem(&xas, GFP_KERNEL)); - } - - xa_destroy(xa); -} - static noinline void check_create_range(struct xarray *xa) { unsigned int order; @@ -1509,9 +1490,6 @@ static noinline void check_create_range(struct xarray *xa) check_create_range_4(xa, (3U << order) + 1, order); check_create_range_4(xa, (3U << order) - 1, order); check_create_range_4(xa, (1U << 24) + 1, order); - - check_create_range_5(xa, 0, order); - check_create_range_5(xa, (1U << order), order); } check_create_range_3(); diff --git a/lib/xarray.c b/lib/xarray.c index 75da19a7a93348ae94e1608ef75261b27024a029..ed775dee1074c99e798ab55a56eaa73754783b76 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -722,8 +722,6 @@ void xas_create_range(struct xa_state *xas) for (;;) { struct xa_node *node = xas->xa_node; - if (node->shift >= shift) - break; xas->xa_node = xa_parent_locked(xas->xa, node); xas->xa_offset = node->offset - 1; if (node->offset != 0) @@ -1080,7 +1078,6 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order) xa_mk_node(child)); if (xa_is_value(curr)) values--; - xas_update(xas, child); } else { unsigned int canon = offset - xas->xa_sibs; @@ -1095,7 +1092,6 @@ void xas_split(struct xa_state *xas, void *entry, unsigned int order) } while (offset-- > xas->xa_offset); node->nr_values += values; - xas_update(xas, node); } EXPORT_SYMBOL_GPL(xas_split); #endif diff --git a/mm/Kconfig b/mm/Kconfig index 7853ccc1c935996c4bdde8b5fb961c8a08a5c1cf..27cdf23dd46ed61d0c90e241be0bec0ff9a639ff 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -756,10 +756,18 @@ config DEFERRED_STRUCT_PAGE_INIT lifetime of the system until these kthreads finish the initialisation. +config PAGE_IDLE_FLAG + bool + select PAGE_EXTENSION if !64BIT + help + This adds PG_idle and PG_young flags to 'struct page'. PTE Accessed + bit writers can set the state of the bit in the flags so that PTE + Accessed bit readers may avoid disturbance. + config IDLE_PAGE_TRACKING bool "Enable idle page tracking" depends on SYSFS && MMU - select PAGE_EXTENSION if !64BIT + select PAGE_IDLE_FLAG help This feature allows to estimate the amount of user pages that have not been touched during a given period of time. This information can @@ -907,4 +915,32 @@ config ANON_VMA_NAME area from being merged with adjacent virtual memory areas due to the difference in their name. +# multi-gen LRU { +config LRU_GEN + bool "Multi-Gen LRU" + depends on MMU + # the following options can use up the spare bits in page flags + depends on !MAXSMP && (64BIT || !SPARSEMEM || SPARSEMEM_VMEMMAP) + help + A high performance LRU implementation to overcommit memory. See + Documentation/admin-guide/mm/multigen_lru.rst for details. + +config LRU_GEN_ENABLED + bool "Enable by default" + depends on LRU_GEN + help + This option enables the multi-gen LRU by default. + +config LRU_GEN_STATS + bool "Full stats for debugging" + depends on LRU_GEN + help + Do not enable this option unless you plan to look at historical stats + from evicted generations for debugging purpose. + + This option has a per-memcg and per-node memory overhead. +# } + +source "mm/damon/Kconfig" + endmenu diff --git a/mm/Makefile b/mm/Makefile index 8de8651da06955c10562b2a6b258a05b20244267..b90583a89fb5a865e124c6724061c387de7ea703 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_USERFAULTFD) += userfaultfd.o obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o +obj-$(CONFIG_DAMON) += damon/ obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o obj-$(CONFIG_PERCPU_STATS) += percpu-stats.o obj-$(CONFIG_ZONE_DEVICE) += memremap.o diff --git a/mm/compaction.c b/mm/compaction.c index c1a02788282b3464e7c0605cd47176ab6659ed3e..6650f5968f26119a4208ff94da5bac08bf57e0b1 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1034,7 +1034,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, low_pfn += compound_nr(page) - 1; /* Successfully isolated */ - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON + page_is_file_lru(page), thp_nr_pages(page)); diff --git a/mm/damon/Kconfig b/mm/damon/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..5bcf05851ad078305362f897d958e2d3f3dd0167 --- /dev/null +++ b/mm/damon/Kconfig @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "Data Access Monitoring" + +config DAMON + bool "DAMON: Data Access Monitoring Framework" + help + This builds a framework that allows kernel subsystems to monitor + access frequency of each memory region. The information can be useful + for performance-centric DRAM level memory management. + + See https://damonitor.github.io/doc/html/latest-damon/index.html for + more information. + +config DAMON_KUNIT_TEST + bool "Test for damon" if !KUNIT_ALL_TESTS + depends on DAMON && KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the DAMON Kunit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + +config DAMON_VADDR + bool "Data access monitoring primitives for virtual address spaces" + depends on DAMON && MMU + select PAGE_IDLE_FLAG + help + This builds the default data access monitoring primitives for DAMON + that work for virtual address spaces. + +config DAMON_PADDR + bool "Data access monitoring primitives for the physical address space" + depends on DAMON && MMU + select PAGE_IDLE_FLAG + help + This builds the default data access monitoring primitives for DAMON + that works for the physical address space. + +config DAMON_VADDR_KUNIT_TEST + bool "Test for DAMON primitives" if !KUNIT_ALL_TESTS + depends on DAMON_VADDR && KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the DAMON virtual addresses primitives Kunit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + +config DAMON_DBGFS + bool "DAMON debugfs interface" + depends on DAMON_VADDR && DAMON_PADDR && DEBUG_FS + help + This builds the debugfs interface for DAMON. The user space admins + can use the interface for arbitrary data access monitoring. + + If unsure, say N. + +config DAMON_DBGFS_KUNIT_TEST + bool "Test for damon debugfs interface" if !KUNIT_ALL_TESTS + depends on DAMON_DBGFS && KUNIT=y + default KUNIT_ALL_TESTS + help + This builds the DAMON debugfs interface Kunit test suite. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation. + + If unsure, say N. + +config DAMON_RECLAIM + bool "Build DAMON-based reclaim (DAMON_RECLAIM)" + depends on DAMON_PADDR + help + This builds the DAMON-based reclamation subsystem. It finds pages + that not accessed for a long time (cold) using DAMON and reclaim + those. + + This is suggested to be used as a proactive and lightweight + reclamation under light memory pressure, while the traditional page + scanning-based reclamation is used for heavy pressure. + +endmenu diff --git a/mm/damon/Makefile b/mm/damon/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f7d5ac377a2bb5551e9fe60882b961825d4f492f --- /dev/null +++ b/mm/damon/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DAMON) := core.o +obj-$(CONFIG_DAMON_VADDR) += prmtv-common.o vaddr.o +obj-$(CONFIG_DAMON_PADDR) += prmtv-common.o paddr.o +obj-$(CONFIG_DAMON_DBGFS) += dbgfs.o +obj-$(CONFIG_DAMON_RECLAIM) += reclaim.o diff --git a/mm/damon/core-test.h b/mm/damon/core-test.h new file mode 100644 index 0000000000000000000000000000000000000000..7008c3735e99f1d486109aeb8d9b3ccfbf68b6fb --- /dev/null +++ b/mm/damon/core-test.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Data Access Monitor Unit Tests + * + * Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Author: SeongJae Park + */ + +#ifdef CONFIG_DAMON_KUNIT_TEST + +#ifndef _DAMON_CORE_TEST_H +#define _DAMON_CORE_TEST_H + +#include + +static void damon_test_regions(struct kunit *test) +{ + struct damon_region *r; + struct damon_target *t; + + r = damon_new_region(1, 2); + KUNIT_EXPECT_EQ(test, 1ul, r->ar.start); + KUNIT_EXPECT_EQ(test, 2ul, r->ar.end); + KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); + + t = damon_new_target(42); + KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); + + damon_add_region(r, t); + KUNIT_EXPECT_EQ(test, 1u, damon_nr_regions(t)); + + damon_del_region(r, t); + KUNIT_EXPECT_EQ(test, 0u, damon_nr_regions(t)); + + damon_free_target(t); +} + +static unsigned int nr_damon_targets(struct damon_ctx *ctx) +{ + struct damon_target *t; + unsigned int nr_targets = 0; + + damon_for_each_target(t, ctx) + nr_targets++; + + return nr_targets; +} + +static void damon_test_target(struct kunit *test) +{ + struct damon_ctx *c = damon_new_ctx(); + struct damon_target *t; + + t = damon_new_target(42); + KUNIT_EXPECT_EQ(test, 42ul, t->id); + KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); + + damon_add_target(c, t); + KUNIT_EXPECT_EQ(test, 1u, nr_damon_targets(c)); + + damon_destroy_target(t); + KUNIT_EXPECT_EQ(test, 0u, nr_damon_targets(c)); + + damon_destroy_ctx(c); +} + +/* + * Test kdamond_reset_aggregated() + * + * DAMON checks access to each region and aggregates this information as the + * access frequency of each region. In detail, it increases '->nr_accesses' of + * regions that an access has confirmed. 'kdamond_reset_aggregated()' flushes + * the aggregated information ('->nr_accesses' of each regions) to the result + * buffer. As a result of the flushing, the '->nr_accesses' of regions are + * initialized to zero. + */ +static void damon_test_aggregate(struct kunit *test) +{ + struct damon_ctx *ctx = damon_new_ctx(); + unsigned long target_ids[] = {1, 2, 3}; + unsigned long saddr[][3] = {{10, 20, 30}, {5, 42, 49}, {13, 33, 55} }; + unsigned long eaddr[][3] = {{15, 27, 40}, {31, 45, 55}, {23, 44, 66} }; + unsigned long accesses[][3] = {{42, 95, 84}, {10, 20, 30}, {0, 1, 2} }; + struct damon_target *t; + struct damon_region *r; + int it, ir; + + damon_set_targets(ctx, target_ids, 3); + + it = 0; + damon_for_each_target(t, ctx) { + for (ir = 0; ir < 3; ir++) { + r = damon_new_region(saddr[it][ir], eaddr[it][ir]); + r->nr_accesses = accesses[it][ir]; + damon_add_region(r, t); + } + it++; + } + kdamond_reset_aggregated(ctx); + it = 0; + damon_for_each_target(t, ctx) { + ir = 0; + /* '->nr_accesses' should be zeroed */ + damon_for_each_region(r, t) { + KUNIT_EXPECT_EQ(test, 0u, r->nr_accesses); + ir++; + } + /* regions should be preserved */ + KUNIT_EXPECT_EQ(test, 3, ir); + it++; + } + /* targets also should be preserved */ + KUNIT_EXPECT_EQ(test, 3, it); + + damon_destroy_ctx(ctx); +} + +static void damon_test_split_at(struct kunit *test) +{ + struct damon_ctx *c = damon_new_ctx(); + struct damon_target *t; + struct damon_region *r; + + t = damon_new_target(42); + r = damon_new_region(0, 100); + damon_add_region(r, t); + damon_split_region_at(c, t, r, 25); + KUNIT_EXPECT_EQ(test, r->ar.start, 0ul); + KUNIT_EXPECT_EQ(test, r->ar.end, 25ul); + + r = damon_next_region(r); + KUNIT_EXPECT_EQ(test, r->ar.start, 25ul); + KUNIT_EXPECT_EQ(test, r->ar.end, 100ul); + + damon_free_target(t); + damon_destroy_ctx(c); +} + +static void damon_test_merge_two(struct kunit *test) +{ + struct damon_target *t; + struct damon_region *r, *r2, *r3; + int i; + + t = damon_new_target(42); + r = damon_new_region(0, 100); + r->nr_accesses = 10; + damon_add_region(r, t); + r2 = damon_new_region(100, 300); + r2->nr_accesses = 20; + damon_add_region(r2, t); + + damon_merge_two_regions(t, r, r2); + KUNIT_EXPECT_EQ(test, r->ar.start, 0ul); + KUNIT_EXPECT_EQ(test, r->ar.end, 300ul); + KUNIT_EXPECT_EQ(test, r->nr_accesses, 16u); + + i = 0; + damon_for_each_region(r3, t) { + KUNIT_EXPECT_PTR_EQ(test, r, r3); + i++; + } + KUNIT_EXPECT_EQ(test, i, 1); + + damon_free_target(t); +} + +static struct damon_region *__nth_region_of(struct damon_target *t, int idx) +{ + struct damon_region *r; + unsigned int i = 0; + + damon_for_each_region(r, t) { + if (i++ == idx) + return r; + } + + return NULL; +} + +static void damon_test_merge_regions_of(struct kunit *test) +{ + struct damon_target *t; + struct damon_region *r; + unsigned long sa[] = {0, 100, 114, 122, 130, 156, 170, 184}; + unsigned long ea[] = {100, 112, 122, 130, 156, 170, 184, 230}; + unsigned int nrs[] = {0, 0, 10, 10, 20, 30, 1, 2}; + + unsigned long saddrs[] = {0, 114, 130, 156, 170}; + unsigned long eaddrs[] = {112, 130, 156, 170, 230}; + int i; + + t = damon_new_target(42); + for (i = 0; i < ARRAY_SIZE(sa); i++) { + r = damon_new_region(sa[i], ea[i]); + r->nr_accesses = nrs[i]; + damon_add_region(r, t); + } + + damon_merge_regions_of(t, 9, 9999); + /* 0-112, 114-130, 130-156, 156-170 */ + KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 5u); + for (i = 0; i < 5; i++) { + r = __nth_region_of(t, i); + KUNIT_EXPECT_EQ(test, r->ar.start, saddrs[i]); + KUNIT_EXPECT_EQ(test, r->ar.end, eaddrs[i]); + } + damon_free_target(t); +} + +static void damon_test_split_regions_of(struct kunit *test) +{ + struct damon_ctx *c = damon_new_ctx(); + struct damon_target *t; + struct damon_region *r; + + t = damon_new_target(42); + r = damon_new_region(0, 22); + damon_add_region(r, t); + damon_split_regions_of(c, t, 2); + KUNIT_EXPECT_LE(test, damon_nr_regions(t), 2u); + damon_free_target(t); + + t = damon_new_target(42); + r = damon_new_region(0, 220); + damon_add_region(r, t); + damon_split_regions_of(c, t, 4); + KUNIT_EXPECT_LE(test, damon_nr_regions(t), 4u); + damon_free_target(t); + damon_destroy_ctx(c); +} + +static struct kunit_case damon_test_cases[] = { + KUNIT_CASE(damon_test_target), + KUNIT_CASE(damon_test_regions), + KUNIT_CASE(damon_test_aggregate), + KUNIT_CASE(damon_test_split_at), + KUNIT_CASE(damon_test_merge_two), + KUNIT_CASE(damon_test_merge_regions_of), + KUNIT_CASE(damon_test_split_regions_of), + {}, +}; + +static struct kunit_suite damon_test_suite = { + .name = "damon", + .test_cases = damon_test_cases, +}; +kunit_test_suite(damon_test_suite); + +#endif /* _DAMON_CORE_TEST_H */ + +#endif /* CONFIG_DAMON_KUNIT_TEST */ diff --git a/mm/damon/core.c b/mm/damon/core.c new file mode 100644 index 0000000000000000000000000000000000000000..1dd153c31c9e2b8e5fd6bc7d608f830e768f9c1e --- /dev/null +++ b/mm/damon/core.c @@ -0,0 +1,1075 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Data Access Monitor + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon: " fmt + +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#ifdef CONFIG_DAMON_KUNIT_TEST +#undef DAMON_MIN_REGION +#define DAMON_MIN_REGION 1 +#endif + +static DEFINE_MUTEX(damon_lock); +static int nr_running_ctxs; + +/* + * Construct a damon_region struct + * + * Returns the pointer to the new struct if success, or NULL otherwise + */ +struct damon_region *damon_new_region(unsigned long start, unsigned long end) +{ + struct damon_region *region; + + region = kmalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return NULL; + + region->ar.start = start; + region->ar.end = end; + region->nr_accesses = 0; + INIT_LIST_HEAD(®ion->list); + + region->age = 0; + region->last_nr_accesses = 0; + + return region; +} + +void damon_add_region(struct damon_region *r, struct damon_target *t) +{ + list_add_tail(&r->list, &t->regions_list); + t->nr_regions++; +} + +static void damon_del_region(struct damon_region *r, struct damon_target *t) +{ + list_del(&r->list); + t->nr_regions--; +} + +static void damon_free_region(struct damon_region *r) +{ + kfree(r); +} + +void damon_destroy_region(struct damon_region *r, struct damon_target *t) +{ + damon_del_region(r, t); + damon_free_region(r); +} + +struct damos *damon_new_scheme( + unsigned long min_sz_region, unsigned long max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damos_action action, struct damos_quota *quota, + struct damos_watermarks *wmarks) +{ + struct damos *scheme; + + scheme = kmalloc(sizeof(*scheme), GFP_KERNEL); + if (!scheme) + return NULL; + scheme->min_sz_region = min_sz_region; + scheme->max_sz_region = max_sz_region; + scheme->min_nr_accesses = min_nr_accesses; + scheme->max_nr_accesses = max_nr_accesses; + scheme->min_age_region = min_age_region; + scheme->max_age_region = max_age_region; + scheme->action = action; + scheme->stat = (struct damos_stat){}; + INIT_LIST_HEAD(&scheme->list); + + scheme->quota.ms = quota->ms; + scheme->quota.sz = quota->sz; + scheme->quota.reset_interval = quota->reset_interval; + scheme->quota.weight_sz = quota->weight_sz; + scheme->quota.weight_nr_accesses = quota->weight_nr_accesses; + scheme->quota.weight_age = quota->weight_age; + scheme->quota.total_charged_sz = 0; + scheme->quota.total_charged_ns = 0; + scheme->quota.esz = 0; + scheme->quota.charged_sz = 0; + scheme->quota.charged_from = 0; + scheme->quota.charge_target_from = NULL; + scheme->quota.charge_addr_from = 0; + + scheme->wmarks.metric = wmarks->metric; + scheme->wmarks.interval = wmarks->interval; + scheme->wmarks.high = wmarks->high; + scheme->wmarks.mid = wmarks->mid; + scheme->wmarks.low = wmarks->low; + scheme->wmarks.activated = true; + + return scheme; +} + +void damon_add_scheme(struct damon_ctx *ctx, struct damos *s) +{ + list_add_tail(&s->list, &ctx->schemes); +} + +static void damon_del_scheme(struct damos *s) +{ + list_del(&s->list); +} + +static void damon_free_scheme(struct damos *s) +{ + kfree(s); +} + +void damon_destroy_scheme(struct damos *s) +{ + damon_del_scheme(s); + damon_free_scheme(s); +} + +/* + * Construct a damon_target struct + * + * Returns the pointer to the new struct if success, or NULL otherwise + */ +struct damon_target *damon_new_target(unsigned long id) +{ + struct damon_target *t; + + t = kmalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return NULL; + + t->id = id; + t->nr_regions = 0; + INIT_LIST_HEAD(&t->regions_list); + + return t; +} + +void damon_add_target(struct damon_ctx *ctx, struct damon_target *t) +{ + list_add_tail(&t->list, &ctx->adaptive_targets); +} + +bool damon_targets_empty(struct damon_ctx *ctx) +{ + return list_empty(&ctx->adaptive_targets); +} + +static void damon_del_target(struct damon_target *t) +{ + list_del(&t->list); +} + +void damon_free_target(struct damon_target *t) +{ + struct damon_region *r, *next; + + damon_for_each_region_safe(r, next, t) + damon_free_region(r); + kfree(t); +} + +void damon_destroy_target(struct damon_target *t) +{ + damon_del_target(t); + damon_free_target(t); +} + +unsigned int damon_nr_regions(struct damon_target *t) +{ + return t->nr_regions; +} + +struct damon_ctx *damon_new_ctx(void) +{ + struct damon_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->sample_interval = 5 * 1000; + ctx->aggr_interval = 100 * 1000; + ctx->primitive_update_interval = 60 * 1000 * 1000; + + ktime_get_coarse_ts64(&ctx->last_aggregation); + ctx->last_primitive_update = ctx->last_aggregation; + + mutex_init(&ctx->kdamond_lock); + + ctx->min_nr_regions = 10; + ctx->max_nr_regions = 1000; + + INIT_LIST_HEAD(&ctx->adaptive_targets); + INIT_LIST_HEAD(&ctx->schemes); + + return ctx; +} + +static void damon_destroy_targets(struct damon_ctx *ctx) +{ + struct damon_target *t, *next_t; + + if (ctx->primitive.cleanup) { + ctx->primitive.cleanup(ctx); + return; + } + + damon_for_each_target_safe(t, next_t, ctx) + damon_destroy_target(t); +} + +void damon_destroy_ctx(struct damon_ctx *ctx) +{ + struct damos *s, *next_s; + + damon_destroy_targets(ctx); + + damon_for_each_scheme_safe(s, next_s, ctx) + damon_destroy_scheme(s); + + kfree(ctx); +} + +/** + * damon_set_targets() - Set monitoring targets. + * @ctx: monitoring context + * @ids: array of target ids + * @nr_ids: number of entries in @ids + * + * This function should not be called while the kdamond is running. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_set_targets(struct damon_ctx *ctx, + unsigned long *ids, ssize_t nr_ids) +{ + ssize_t i; + struct damon_target *t, *next; + + damon_destroy_targets(ctx); + + for (i = 0; i < nr_ids; i++) { + t = damon_new_target(ids[i]); + if (!t) { + /* The caller should do cleanup of the ids itself */ + damon_for_each_target_safe(t, next, ctx) + damon_destroy_target(t); + return -ENOMEM; + } + damon_add_target(ctx, t); + } + + return 0; +} + +/** + * damon_set_attrs() - Set attributes for the monitoring. + * @ctx: monitoring context + * @sample_int: time interval between samplings + * @aggr_int: time interval between aggregations + * @primitive_upd_int: time interval between monitoring primitive updates + * @min_nr_reg: minimal number of regions + * @max_nr_reg: maximum number of regions + * + * This function should not be called while the kdamond is running. + * Every time interval is in micro-seconds. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int, + unsigned long aggr_int, unsigned long primitive_upd_int, + unsigned long min_nr_reg, unsigned long max_nr_reg) +{ + if (min_nr_reg < 3) + return -EINVAL; + if (min_nr_reg > max_nr_reg) + return -EINVAL; + + ctx->sample_interval = sample_int; + ctx->aggr_interval = aggr_int; + ctx->primitive_update_interval = primitive_upd_int; + ctx->min_nr_regions = min_nr_reg; + ctx->max_nr_regions = max_nr_reg; + + return 0; +} + +/** + * damon_set_schemes() - Set data access monitoring based operation schemes. + * @ctx: monitoring context + * @schemes: array of the schemes + * @nr_schemes: number of entries in @schemes + * + * This function should not be called while the kdamond of the context is + * running. + * + * Return: 0 if success, or negative error code otherwise. + */ +int damon_set_schemes(struct damon_ctx *ctx, struct damos **schemes, + ssize_t nr_schemes) +{ + struct damos *s, *next; + ssize_t i; + + damon_for_each_scheme_safe(s, next, ctx) + damon_destroy_scheme(s); + for (i = 0; i < nr_schemes; i++) + damon_add_scheme(ctx, schemes[i]); + return 0; +} + +/** + * damon_nr_running_ctxs() - Return number of currently running contexts. + */ +int damon_nr_running_ctxs(void) +{ + int nr_ctxs; + + mutex_lock(&damon_lock); + nr_ctxs = nr_running_ctxs; + mutex_unlock(&damon_lock); + + return nr_ctxs; +} + +/* Returns the size upper limit for each monitoring region */ +static unsigned long damon_region_sz_limit(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + unsigned long sz = 0; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) + sz += r->ar.end - r->ar.start; + } + + if (ctx->min_nr_regions) + sz /= ctx->min_nr_regions; + if (sz < DAMON_MIN_REGION) + sz = DAMON_MIN_REGION; + + return sz; +} + +static int kdamond_fn(void *data); + +/* + * __damon_start() - Starts monitoring with given context. + * @ctx: monitoring context + * + * This function should be called while damon_lock is hold. + * + * Return: 0 on success, negative error code otherwise. + */ +static int __damon_start(struct damon_ctx *ctx) +{ + int err = -EBUSY; + + mutex_lock(&ctx->kdamond_lock); + if (!ctx->kdamond) { + err = 0; + ctx->kdamond = kthread_run(kdamond_fn, ctx, "kdamond.%d", + nr_running_ctxs); + if (IS_ERR(ctx->kdamond)) { + err = PTR_ERR(ctx->kdamond); + ctx->kdamond = NULL; + } + } + mutex_unlock(&ctx->kdamond_lock); + + return err; +} + +/** + * damon_start() - Starts the monitorings for a given group of contexts. + * @ctxs: an array of the pointers for contexts to start monitoring + * @nr_ctxs: size of @ctxs + * + * This function starts a group of monitoring threads for a group of monitoring + * contexts. One thread per each context is created and run in parallel. The + * caller should handle synchronization between the threads by itself. If a + * group of threads that created by other 'damon_start()' call is currently + * running, this function does nothing but returns -EBUSY. + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_start(struct damon_ctx **ctxs, int nr_ctxs) +{ + int i; + int err = 0; + + mutex_lock(&damon_lock); + if (nr_running_ctxs) { + mutex_unlock(&damon_lock); + return -EBUSY; + } + + for (i = 0; i < nr_ctxs; i++) { + err = __damon_start(ctxs[i]); + if (err) + break; + nr_running_ctxs++; + } + mutex_unlock(&damon_lock); + + return err; +} + +/* + * __damon_stop() - Stops monitoring of given context. + * @ctx: monitoring context + * + * Return: 0 on success, negative error code otherwise. + */ +static int __damon_stop(struct damon_ctx *ctx) +{ + struct task_struct *tsk; + + mutex_lock(&ctx->kdamond_lock); + tsk = ctx->kdamond; + if (tsk) { + get_task_struct(tsk); + mutex_unlock(&ctx->kdamond_lock); + kthread_stop(tsk); + put_task_struct(tsk); + return 0; + } + mutex_unlock(&ctx->kdamond_lock); + + return -EPERM; +} + +/** + * damon_stop() - Stops the monitorings for a given group of contexts. + * @ctxs: an array of the pointers for contexts to stop monitoring + * @nr_ctxs: size of @ctxs + * + * Return: 0 on success, negative error code otherwise. + */ +int damon_stop(struct damon_ctx **ctxs, int nr_ctxs) +{ + int i, err = 0; + + for (i = 0; i < nr_ctxs; i++) { + /* nr_running_ctxs is decremented in kdamond_fn */ + err = __damon_stop(ctxs[i]); + if (err) + return err; + } + + return err; +} + +/* + * damon_check_reset_time_interval() - Check if a time interval is elapsed. + * @baseline: the time to check whether the interval has elapsed since + * @interval: the time interval (microseconds) + * + * See whether the given time interval has passed since the given baseline + * time. If so, it also updates the baseline to current time for next check. + * + * Return: true if the time interval has passed, or false otherwise. + */ +static bool damon_check_reset_time_interval(struct timespec64 *baseline, + unsigned long interval) +{ + struct timespec64 now; + + ktime_get_coarse_ts64(&now); + if ((timespec64_to_ns(&now) - timespec64_to_ns(baseline)) < + interval * 1000) + return false; + *baseline = now; + return true; +} + +/* + * Check whether it is time to flush the aggregated information + */ +static bool kdamond_aggregate_interval_passed(struct damon_ctx *ctx) +{ + return damon_check_reset_time_interval(&ctx->last_aggregation, + ctx->aggr_interval); +} + +/* + * Reset the aggregated monitoring results ('nr_accesses' of each region). + */ +static void kdamond_reset_aggregated(struct damon_ctx *c) +{ + struct damon_target *t; + unsigned int ti = 0; /* target's index */ + + damon_for_each_target(t, c) { + struct damon_region *r; + + damon_for_each_region(r, t) { + trace_damon_aggregated(t, ti, r, damon_nr_regions(t)); + r->last_nr_accesses = r->nr_accesses; + r->nr_accesses = 0; + } + ti++; + } +} + +static void damon_split_region_at(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + unsigned long sz_r); + +static bool __damos_valid_target(struct damon_region *r, struct damos *s) +{ + unsigned long sz; + + sz = r->ar.end - r->ar.start; + return s->min_sz_region <= sz && sz <= s->max_sz_region && + s->min_nr_accesses <= r->nr_accesses && + r->nr_accesses <= s->max_nr_accesses && + s->min_age_region <= r->age && r->age <= s->max_age_region; +} + +static bool damos_valid_target(struct damon_ctx *c, struct damon_target *t, + struct damon_region *r, struct damos *s) +{ + bool ret = __damos_valid_target(r, s); + + if (!ret || !s->quota.esz || !c->primitive.get_scheme_score) + return ret; + + return c->primitive.get_scheme_score(c, t, r, s) >= s->quota.min_score; +} + +static void damon_do_apply_schemes(struct damon_ctx *c, + struct damon_target *t, + struct damon_region *r) +{ + struct damos *s; + + damon_for_each_scheme(s, c) { + struct damos_quota *quota = &s->quota; + unsigned long sz = r->ar.end - r->ar.start; + struct timespec64 begin, end; + unsigned long sz_applied = 0; + + if (!s->wmarks.activated) + continue; + + /* Check the quota */ + if (quota->esz && quota->charged_sz >= quota->esz) + continue; + + /* Skip previously charged regions */ + if (quota->charge_target_from) { + if (t != quota->charge_target_from) + continue; + if (r == damon_last_region(t)) { + quota->charge_target_from = NULL; + quota->charge_addr_from = 0; + continue; + } + if (quota->charge_addr_from && + r->ar.end <= quota->charge_addr_from) + continue; + + if (quota->charge_addr_from && r->ar.start < + quota->charge_addr_from) { + sz = ALIGN_DOWN(quota->charge_addr_from - + r->ar.start, DAMON_MIN_REGION); + if (!sz) { + if (r->ar.end - r->ar.start <= + DAMON_MIN_REGION) + continue; + sz = DAMON_MIN_REGION; + } + damon_split_region_at(c, t, r, sz); + r = damon_next_region(r); + sz = r->ar.end - r->ar.start; + } + quota->charge_target_from = NULL; + quota->charge_addr_from = 0; + } + + if (!damos_valid_target(c, t, r, s)) + continue; + + /* Apply the scheme */ + if (c->primitive.apply_scheme) { + if (quota->esz && + quota->charged_sz + sz > quota->esz) { + sz = ALIGN_DOWN(quota->esz - quota->charged_sz, + DAMON_MIN_REGION); + if (!sz) + goto update_stat; + damon_split_region_at(c, t, r, sz); + } + ktime_get_coarse_ts64(&begin); + sz_applied = c->primitive.apply_scheme(c, t, r, s); + ktime_get_coarse_ts64(&end); + quota->total_charged_ns += timespec64_to_ns(&end) - + timespec64_to_ns(&begin); + quota->charged_sz += sz; + if (quota->esz && quota->charged_sz >= quota->esz) { + quota->charge_target_from = t; + quota->charge_addr_from = r->ar.end + 1; + } + } + if (s->action != DAMOS_STAT) + r->age = 0; + +update_stat: + s->stat.nr_tried++; + s->stat.sz_tried += sz; + if (sz_applied) + s->stat.nr_applied++; + s->stat.sz_applied += sz_applied; + } +} + +/* Shouldn't be called if quota->ms and quota->sz are zero */ +static void damos_set_effective_quota(struct damos_quota *quota) +{ + unsigned long throughput; + unsigned long esz; + + if (!quota->ms) { + quota->esz = quota->sz; + return; + } + + if (quota->total_charged_ns) + throughput = quota->total_charged_sz * 1000000 / + quota->total_charged_ns; + else + throughput = PAGE_SIZE * 1024; + esz = throughput * quota->ms; + + if (quota->sz && quota->sz < esz) + esz = quota->sz; + quota->esz = esz; +} + +static void kdamond_apply_schemes(struct damon_ctx *c) +{ + struct damon_target *t; + struct damon_region *r, *next_r; + struct damos *s; + + damon_for_each_scheme(s, c) { + struct damos_quota *quota = &s->quota; + unsigned long cumulated_sz; + unsigned int score, max_score = 0; + + if (!s->wmarks.activated) + continue; + + if (!quota->ms && !quota->sz) + continue; + + /* New charge window starts */ + if (time_after_eq(jiffies, quota->charged_from + + msecs_to_jiffies( + quota->reset_interval))) { + if (quota->esz && quota->charged_sz >= quota->esz) + s->stat.qt_exceeds++; + quota->total_charged_sz += quota->charged_sz; + quota->charged_from = jiffies; + quota->charged_sz = 0; + damos_set_effective_quota(quota); + } + + if (!c->primitive.get_scheme_score) + continue; + + /* Fill up the score histogram */ + memset(quota->histogram, 0, sizeof(quota->histogram)); + damon_for_each_target(t, c) { + damon_for_each_region(r, t) { + if (!__damos_valid_target(r, s)) + continue; + score = c->primitive.get_scheme_score( + c, t, r, s); + quota->histogram[score] += + r->ar.end - r->ar.start; + if (score > max_score) + max_score = score; + } + } + + /* Set the min score limit */ + for (cumulated_sz = 0, score = max_score; ; score--) { + cumulated_sz += quota->histogram[score]; + if (cumulated_sz >= quota->esz || !score) + break; + } + quota->min_score = score; + } + + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next_r, t) + damon_do_apply_schemes(c, t, r); + } +} + +static inline unsigned long sz_damon_region(struct damon_region *r) +{ + return r->ar.end - r->ar.start; +} + +/* + * Merge two adjacent regions into one region + */ +static void damon_merge_two_regions(struct damon_target *t, + struct damon_region *l, struct damon_region *r) +{ + unsigned long sz_l = sz_damon_region(l), sz_r = sz_damon_region(r); + + l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) / + (sz_l + sz_r); + l->age = (l->age * sz_l + r->age * sz_r) / (sz_l + sz_r); + l->ar.end = r->ar.end; + damon_destroy_region(r, t); +} + +/* + * Merge adjacent regions having similar access frequencies + * + * t target affected by this merge operation + * thres '->nr_accesses' diff threshold for the merge + * sz_limit size upper limit of each region + */ +static void damon_merge_regions_of(struct damon_target *t, unsigned int thres, + unsigned long sz_limit) +{ + struct damon_region *r, *prev = NULL, *next; + + damon_for_each_region_safe(r, next, t) { + if (abs(r->nr_accesses - r->last_nr_accesses) > thres) + r->age = 0; + else + r->age++; + + if (prev && prev->ar.end == r->ar.start && + abs(prev->nr_accesses - r->nr_accesses) <= thres && + sz_damon_region(prev) + sz_damon_region(r) <= sz_limit) + damon_merge_two_regions(t, prev, r); + else + prev = r; + } +} + +/* + * Merge adjacent regions having similar access frequencies + * + * threshold '->nr_accesses' diff threshold for the merge + * sz_limit size upper limit of each region + * + * This function merges monitoring target regions which are adjacent and their + * access frequencies are similar. This is for minimizing the monitoring + * overhead under the dynamically changeable access pattern. If a merge was + * unnecessarily made, later 'kdamond_split_regions()' will revert it. + */ +static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold, + unsigned long sz_limit) +{ + struct damon_target *t; + + damon_for_each_target(t, c) + damon_merge_regions_of(t, threshold, sz_limit); +} + +/* + * Split a region in two + * + * r the region to be split + * sz_r size of the first sub-region that will be made + */ +static void damon_split_region_at(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + unsigned long sz_r) +{ + struct damon_region *new; + + new = damon_new_region(r->ar.start + sz_r, r->ar.end); + if (!new) + return; + + r->ar.end = new->ar.start; + + new->age = r->age; + new->last_nr_accesses = r->last_nr_accesses; + + damon_insert_region(new, r, damon_next_region(r), t); +} + +/* Split every region in the given target into 'nr_subs' regions */ +static void damon_split_regions_of(struct damon_ctx *ctx, + struct damon_target *t, int nr_subs) +{ + struct damon_region *r, *next; + unsigned long sz_region, sz_sub = 0; + int i; + + damon_for_each_region_safe(r, next, t) { + sz_region = r->ar.end - r->ar.start; + + for (i = 0; i < nr_subs - 1 && + sz_region > 2 * DAMON_MIN_REGION; i++) { + /* + * Randomly select size of left sub-region to be at + * least 10 percent and at most 90% of original region + */ + sz_sub = ALIGN_DOWN(damon_rand(1, 10) * + sz_region / 10, DAMON_MIN_REGION); + /* Do not allow blank region */ + if (sz_sub == 0 || sz_sub >= sz_region) + continue; + + damon_split_region_at(ctx, t, r, sz_sub); + sz_region = sz_sub; + } + } +} + +/* + * Split every target region into randomly-sized small regions + * + * This function splits every target region into random-sized small regions if + * current total number of the regions is equal or smaller than half of the + * user-specified maximum number of regions. This is for maximizing the + * monitoring accuracy under the dynamically changeable access patterns. If a + * split was unnecessarily made, later 'kdamond_merge_regions()' will revert + * it. + */ +static void kdamond_split_regions(struct damon_ctx *ctx) +{ + struct damon_target *t; + unsigned int nr_regions = 0; + static unsigned int last_nr_regions; + int nr_subregions = 2; + + damon_for_each_target(t, ctx) + nr_regions += damon_nr_regions(t); + + if (nr_regions > ctx->max_nr_regions / 2) + return; + + /* Maybe the middle of the region has different access frequency */ + if (last_nr_regions == nr_regions && + nr_regions < ctx->max_nr_regions / 3) + nr_subregions = 3; + + damon_for_each_target(t, ctx) + damon_split_regions_of(ctx, t, nr_subregions); + + last_nr_regions = nr_regions; +} + +/* + * Check whether it is time to check and apply the target monitoring regions + * + * Returns true if it is. + */ +static bool kdamond_need_update_primitive(struct damon_ctx *ctx) +{ + return damon_check_reset_time_interval(&ctx->last_primitive_update, + ctx->primitive_update_interval); +} + +/* + * Check whether current monitoring should be stopped + * + * The monitoring is stopped when either the user requested to stop, or all + * monitoring targets are invalid. + * + * Returns true if need to stop current monitoring. + */ +static bool kdamond_need_stop(struct damon_ctx *ctx) +{ + struct damon_target *t; + + if (kthread_should_stop()) + return true; + + if (!ctx->primitive.target_valid) + return false; + + damon_for_each_target(t, ctx) { + if (ctx->primitive.target_valid(t)) + return false; + } + + return true; +} + +static unsigned long damos_wmark_metric_value(enum damos_wmark_metric metric) +{ + struct sysinfo i; + + switch (metric) { + case DAMOS_WMARK_FREE_MEM_RATE: + si_meminfo(&i); + return i.freeram * 1000 / i.totalram; + default: + break; + } + return -EINVAL; +} + +/* + * Returns zero if the scheme is active. Else, returns time to wait for next + * watermark check in micro-seconds. + */ +static unsigned long damos_wmark_wait_us(struct damos *scheme) +{ + unsigned long metric; + + if (scheme->wmarks.metric == DAMOS_WMARK_NONE) + return 0; + + metric = damos_wmark_metric_value(scheme->wmarks.metric); + /* higher than high watermark or lower than low watermark */ + if (metric > scheme->wmarks.high || scheme->wmarks.low > metric) { + if (scheme->wmarks.activated) + pr_debug("deactivate a scheme (%d) for %s wmark\n", + scheme->action, + metric > scheme->wmarks.high ? + "high" : "low"); + scheme->wmarks.activated = false; + return scheme->wmarks.interval; + } + + /* inactive and higher than middle watermark */ + if ((scheme->wmarks.high >= metric && metric >= scheme->wmarks.mid) && + !scheme->wmarks.activated) + return scheme->wmarks.interval; + + if (!scheme->wmarks.activated) + pr_debug("activate a scheme (%d)\n", scheme->action); + scheme->wmarks.activated = true; + return 0; +} + +static void kdamond_usleep(unsigned long usecs) +{ + /* See Documentation/timers/timers-howto.rst for the thresholds */ + if (usecs > 20 * USEC_PER_MSEC) + schedule_timeout_idle(usecs_to_jiffies(usecs)); + else + usleep_idle_range(usecs, usecs + 1); +} + +/* Returns negative error code if it's not activated but should return */ +static int kdamond_wait_activation(struct damon_ctx *ctx) +{ + struct damos *s; + unsigned long wait_time; + unsigned long min_wait_time = 0; + + while (!kdamond_need_stop(ctx)) { + damon_for_each_scheme(s, ctx) { + wait_time = damos_wmark_wait_us(s); + if (!min_wait_time || wait_time < min_wait_time) + min_wait_time = wait_time; + } + if (!min_wait_time) + return 0; + + kdamond_usleep(min_wait_time); + } + return -EBUSY; +} + +/* + * The monitoring daemon that runs as a kernel thread + */ +static int kdamond_fn(void *data) +{ + struct damon_ctx *ctx = (struct damon_ctx *)data; + struct damon_target *t; + struct damon_region *r, *next; + unsigned int max_nr_accesses = 0; + unsigned long sz_limit = 0; + bool done = false; + + pr_debug("kdamond (%d) starts\n", current->pid); + + if (ctx->primitive.init) + ctx->primitive.init(ctx); + if (ctx->callback.before_start && ctx->callback.before_start(ctx)) + done = true; + + sz_limit = damon_region_sz_limit(ctx); + + while (!kdamond_need_stop(ctx) && !done) { + if (kdamond_wait_activation(ctx)) + continue; + + if (ctx->primitive.prepare_access_checks) + ctx->primitive.prepare_access_checks(ctx); + if (ctx->callback.after_sampling && + ctx->callback.after_sampling(ctx)) + done = true; + + kdamond_usleep(ctx->sample_interval); + + if (ctx->primitive.check_accesses) + max_nr_accesses = ctx->primitive.check_accesses(ctx); + + if (kdamond_aggregate_interval_passed(ctx)) { + kdamond_merge_regions(ctx, + max_nr_accesses / 10, + sz_limit); + if (ctx->callback.after_aggregation && + ctx->callback.after_aggregation(ctx)) + done = true; + kdamond_apply_schemes(ctx); + kdamond_reset_aggregated(ctx); + kdamond_split_regions(ctx); + if (ctx->primitive.reset_aggregated) + ctx->primitive.reset_aggregated(ctx); + } + + if (kdamond_need_update_primitive(ctx)) { + if (ctx->primitive.update) + ctx->primitive.update(ctx); + sz_limit = damon_region_sz_limit(ctx); + } + } + damon_for_each_target(t, ctx) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + + if (ctx->callback.before_terminate) + ctx->callback.before_terminate(ctx); + if (ctx->primitive.cleanup) + ctx->primitive.cleanup(ctx); + + pr_debug("kdamond (%d) finishes\n", current->pid); + mutex_lock(&ctx->kdamond_lock); + ctx->kdamond = NULL; + mutex_unlock(&ctx->kdamond_lock); + + mutex_lock(&damon_lock); + nr_running_ctxs--; + mutex_unlock(&damon_lock); + + return 0; +} + +#include "core-test.h" diff --git a/mm/damon/dbgfs-test.h b/mm/damon/dbgfs-test.h new file mode 100644 index 0000000000000000000000000000000000000000..86b9f9528231efb52bfe1b791aaaffeb01315492 --- /dev/null +++ b/mm/damon/dbgfs-test.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DAMON Debugfs Interface Unit Tests + * + * Author: SeongJae Park + */ + +#ifdef CONFIG_DAMON_DBGFS_KUNIT_TEST + +#ifndef _DAMON_DBGFS_TEST_H +#define _DAMON_DBGFS_TEST_H + +#include + +static void damon_dbgfs_test_str_to_target_ids(struct kunit *test) +{ + char *question; + unsigned long *answers; + unsigned long expected[] = {12, 35, 46}; + ssize_t nr_integers = 0, i; + + question = "123"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)1, nr_integers); + KUNIT_EXPECT_EQ(test, 123ul, answers[0]); + kfree(answers); + + question = "123abc"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)1, nr_integers); + KUNIT_EXPECT_EQ(test, 123ul, answers[0]); + kfree(answers); + + question = "a123"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)0, nr_integers); + kfree(answers); + + question = "12 35"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)2, nr_integers); + for (i = 0; i < nr_integers; i++) + KUNIT_EXPECT_EQ(test, expected[i], answers[i]); + kfree(answers); + + question = "12 35 46"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)3, nr_integers); + for (i = 0; i < nr_integers; i++) + KUNIT_EXPECT_EQ(test, expected[i], answers[i]); + kfree(answers); + + question = "12 35 abc 46"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)2, nr_integers); + for (i = 0; i < 2; i++) + KUNIT_EXPECT_EQ(test, expected[i], answers[i]); + kfree(answers); + + question = ""; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)0, nr_integers); + kfree(answers); + + question = "\n"; + answers = str_to_target_ids(question, strlen(question), + &nr_integers); + KUNIT_EXPECT_EQ(test, (ssize_t)0, nr_integers); + kfree(answers); +} + +static void damon_dbgfs_test_set_targets(struct kunit *test) +{ + struct damon_ctx *ctx = dbgfs_new_ctx(); + unsigned long ids[] = {1, 2, 3}; + char buf[64]; + + /* Make DAMON consider target id as plain number */ + ctx->primitive.target_valid = NULL; + ctx->primitive.cleanup = NULL; + + damon_set_targets(ctx, ids, 3); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "1 2 3\n"); + + damon_set_targets(ctx, NULL, 0); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "\n"); + + damon_set_targets(ctx, (unsigned long []){1, 2}, 2); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "1 2\n"); + + damon_set_targets(ctx, (unsigned long []){2}, 1); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "2\n"); + + damon_set_targets(ctx, NULL, 0); + sprint_target_ids(ctx, buf, 64); + KUNIT_EXPECT_STREQ(test, (char *)buf, "\n"); + + dbgfs_destroy_ctx(ctx); +} + +static void damon_dbgfs_test_set_init_regions(struct kunit *test) +{ + struct damon_ctx *ctx = damon_new_ctx(); + unsigned long ids[] = {1, 2, 3}; + /* Each line represents one region in `` `` */ + char * const valid_inputs[] = {"2 10 20\n 2 20 30\n2 35 45", + "2 10 20\n", + "2 10 20\n1 39 59\n1 70 134\n 2 20 25\n", + ""}; + /* Reading the file again will show sorted, clean output */ + char * const valid_expects[] = {"2 10 20\n2 20 30\n2 35 45\n", + "2 10 20\n", + "1 39 59\n1 70 134\n2 10 20\n2 20 25\n", + ""}; + char * const invalid_inputs[] = {"4 10 20\n", /* target not exists */ + "2 10 20\n 2 14 26\n", /* regions overlap */ + "1 10 20\n2 30 40\n 1 5 8"}; /* not sorted by address */ + char *input, *expect; + int i, rc; + char buf[256]; + + damon_set_targets(ctx, ids, 3); + + /* Put valid inputs and check the results */ + for (i = 0; i < ARRAY_SIZE(valid_inputs); i++) { + input = valid_inputs[i]; + expect = valid_expects[i]; + + rc = set_init_regions(ctx, input, strnlen(input, 256)); + KUNIT_EXPECT_EQ(test, rc, 0); + + memset(buf, 0, 256); + sprint_init_regions(ctx, buf, 256); + + KUNIT_EXPECT_STREQ(test, (char *)buf, expect); + } + /* Put invalid inputs and check the return error code */ + for (i = 0; i < ARRAY_SIZE(invalid_inputs); i++) { + input = invalid_inputs[i]; + pr_info("input: %s\n", input); + rc = set_init_regions(ctx, input, strnlen(input, 256)); + KUNIT_EXPECT_EQ(test, rc, -EINVAL); + + memset(buf, 0, 256); + sprint_init_regions(ctx, buf, 256); + + KUNIT_EXPECT_STREQ(test, (char *)buf, ""); + } + + damon_set_targets(ctx, NULL, 0); + damon_destroy_ctx(ctx); +} + +static struct kunit_case damon_test_cases[] = { + KUNIT_CASE(damon_dbgfs_test_str_to_target_ids), + KUNIT_CASE(damon_dbgfs_test_set_targets), + KUNIT_CASE(damon_dbgfs_test_set_init_regions), + {}, +}; + +static struct kunit_suite damon_test_suite = { + .name = "damon-dbgfs", + .test_cases = damon_test_cases, +}; +kunit_test_suite(damon_test_suite); + +#endif /* _DAMON_TEST_H */ + +#endif /* CONFIG_DAMON_KUNIT_TEST */ diff --git a/mm/damon/dbgfs.c b/mm/damon/dbgfs.c new file mode 100644 index 0000000000000000000000000000000000000000..5b899601e56c3fd13b434d118ea0e50cb7ab73ff --- /dev/null +++ b/mm/damon/dbgfs.c @@ -0,0 +1,990 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Debugfs Interface + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-dbgfs: " fmt + +#include +#include +#include +#include +#include +#include +#include + +static struct damon_ctx **dbgfs_ctxs; +static int dbgfs_nr_ctxs; +static struct dentry **dbgfs_dirs; +static DEFINE_MUTEX(damon_dbgfs_lock); + +/* + * Returns non-empty string on success, negative error code otherwise. + */ +static char *user_input_str(const char __user *buf, size_t count, loff_t *ppos) +{ + char *kbuf; + ssize_t ret; + + /* We do not accept continuous write */ + if (*ppos) + return ERR_PTR(-EINVAL); + + kbuf = kmalloc(count + 1, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return ERR_PTR(-ENOMEM); + + ret = simple_write_to_buffer(kbuf, count + 1, ppos, buf, count); + if (ret != count) { + kfree(kbuf); + return ERR_PTR(-EIO); + } + kbuf[ret] = '\0'; + + return kbuf; +} + +static ssize_t dbgfs_attrs_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char kbuf[128]; + int ret; + + mutex_lock(&ctx->kdamond_lock); + ret = scnprintf(kbuf, ARRAY_SIZE(kbuf), "%lu %lu %lu %lu %lu\n", + ctx->sample_interval, ctx->aggr_interval, + ctx->primitive_update_interval, ctx->min_nr_regions, + ctx->max_nr_regions); + mutex_unlock(&ctx->kdamond_lock); + + return simple_read_from_buffer(buf, count, ppos, kbuf, ret); +} + +static ssize_t dbgfs_attrs_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + unsigned long s, a, r, minr, maxr; + char *kbuf; + ssize_t ret; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + if (sscanf(kbuf, "%lu %lu %lu %lu %lu", + &s, &a, &r, &minr, &maxr) != 5) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + ret = damon_set_attrs(ctx, s, a, r, minr, maxr); + if (!ret) + ret = count; +unlock_out: + mutex_unlock(&ctx->kdamond_lock); +out: + kfree(kbuf); + return ret; +} + +static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len) +{ + struct damos *s; + int written = 0; + int rc; + + damon_for_each_scheme(s, c) { + rc = scnprintf(&buf[written], len - written, + "%lu %lu %u %u %u %u %d %lu %lu %lu %u %u %u %d %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", + s->min_sz_region, s->max_sz_region, + s->min_nr_accesses, s->max_nr_accesses, + s->min_age_region, s->max_age_region, + s->action, + s->quota.ms, s->quota.sz, + s->quota.reset_interval, + s->quota.weight_sz, + s->quota.weight_nr_accesses, + s->quota.weight_age, + s->wmarks.metric, s->wmarks.interval, + s->wmarks.high, s->wmarks.mid, s->wmarks.low, + s->stat.nr_tried, s->stat.sz_tried, + s->stat.nr_applied, s->stat.sz_applied, + s->stat.qt_exceeds); + if (!rc) + return -ENOMEM; + + written += rc; + } + return written; +} + +static ssize_t dbgfs_schemes_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + len = sprint_schemes(ctx, kbuf, count); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static void free_schemes_arr(struct damos **schemes, ssize_t nr_schemes) +{ + ssize_t i; + + for (i = 0; i < nr_schemes; i++) + kfree(schemes[i]); + kfree(schemes); +} + +static bool damos_action_valid(int action) +{ + switch (action) { + case DAMOS_WILLNEED: + case DAMOS_COLD: + case DAMOS_PAGEOUT: + case DAMOS_HUGEPAGE: + case DAMOS_NOHUGEPAGE: + case DAMOS_STAT: + return true; + default: + return false; + } +} + +/* + * Converts a string into an array of struct damos pointers + * + * Returns an array of struct damos pointers that converted if the conversion + * success, or NULL otherwise. + */ +static struct damos **str_to_schemes(const char *str, ssize_t len, + ssize_t *nr_schemes) +{ + struct damos *scheme, **schemes; + const int max_nr_schemes = 256; + int pos = 0, parsed, ret; + unsigned long min_sz, max_sz; + unsigned int min_nr_a, max_nr_a, min_age, max_age; + unsigned int action; + + schemes = kmalloc_array(max_nr_schemes, sizeof(scheme), + GFP_KERNEL); + if (!schemes) + return NULL; + + *nr_schemes = 0; + while (pos < len && *nr_schemes < max_nr_schemes) { + struct damos_quota quota = {}; + struct damos_watermarks wmarks; + + ret = sscanf(&str[pos], + "%lu %lu %u %u %u %u %u %lu %lu %lu %u %u %u %u %lu %lu %lu %lu%n", + &min_sz, &max_sz, &min_nr_a, &max_nr_a, + &min_age, &max_age, &action, "a.ms, + "a.sz, "a.reset_interval, + "a.weight_sz, "a.weight_nr_accesses, + "a.weight_age, &wmarks.metric, + &wmarks.interval, &wmarks.high, &wmarks.mid, + &wmarks.low, &parsed); + if (ret != 18) + break; + if (!damos_action_valid(action)) + goto fail; + + if (min_sz > max_sz || min_nr_a > max_nr_a || min_age > max_age) + goto fail; + + if (wmarks.high < wmarks.mid || wmarks.high < wmarks.low || + wmarks.mid < wmarks.low) + goto fail; + + pos += parsed; + scheme = damon_new_scheme(min_sz, max_sz, min_nr_a, max_nr_a, + min_age, max_age, action, "a, &wmarks); + if (!scheme) + goto fail; + + schemes[*nr_schemes] = scheme; + *nr_schemes += 1; + } + return schemes; +fail: + free_schemes_arr(schemes, *nr_schemes); + return NULL; +} + +static ssize_t dbgfs_schemes_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + struct damos **schemes; + ssize_t nr_schemes = 0, ret; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + schemes = str_to_schemes(kbuf, count, &nr_schemes); + if (!schemes) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + ret = damon_set_schemes(ctx, schemes, nr_schemes); + if (!ret) { + ret = count; + nr_schemes = 0; + } + +unlock_out: + mutex_unlock(&ctx->kdamond_lock); + free_schemes_arr(schemes, nr_schemes); +out: + kfree(kbuf); + return ret; +} + +static inline bool targetid_is_pid(const struct damon_ctx *ctx) +{ + return ctx->primitive.target_valid == damon_va_target_valid; +} + +static ssize_t sprint_target_ids(struct damon_ctx *ctx, char *buf, ssize_t len) +{ + struct damon_target *t; + unsigned long id; + int written = 0; + int rc; + + damon_for_each_target(t, ctx) { + id = t->id; + if (targetid_is_pid(ctx)) + /* Show pid numbers to debugfs users */ + id = (unsigned long)pid_vnr((struct pid *)id); + + rc = scnprintf(&buf[written], len - written, "%lu ", id); + if (!rc) + return -ENOMEM; + written += rc; + } + if (written) + written -= 1; + written += scnprintf(&buf[written], len - written, "\n"); + return written; +} + +static ssize_t dbgfs_target_ids_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + ssize_t len; + char ids_buf[320]; + + mutex_lock(&ctx->kdamond_lock); + len = sprint_target_ids(ctx, ids_buf, 320); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + return len; + + return simple_read_from_buffer(buf, count, ppos, ids_buf, len); +} + +/* + * Converts a string into an array of unsigned long integers + * + * Returns an array of unsigned long integers if the conversion success, or + * NULL otherwise. + */ +static unsigned long *str_to_target_ids(const char *str, ssize_t len, + ssize_t *nr_ids) +{ + unsigned long *ids; + const int max_nr_ids = 32; + unsigned long id; + int pos = 0, parsed, ret; + + *nr_ids = 0; + ids = kmalloc_array(max_nr_ids, sizeof(id), GFP_KERNEL); + if (!ids) + return NULL; + while (*nr_ids < max_nr_ids && pos < len) { + ret = sscanf(&str[pos], "%lu%n", &id, &parsed); + pos += parsed; + if (ret != 1) + break; + ids[*nr_ids] = id; + *nr_ids += 1; + } + + return ids; +} + +static void dbgfs_put_pids(unsigned long *ids, int nr_ids) +{ + int i; + + for (i = 0; i < nr_ids; i++) + put_pid((struct pid *)ids[i]); +} + +static ssize_t dbgfs_target_ids_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + struct damon_target *t, *next_t; + bool id_is_pid = true; + char *kbuf; + unsigned long *targets; + ssize_t nr_targets; + ssize_t ret; + int i; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + if (!strncmp(kbuf, "paddr\n", count)) { + id_is_pid = false; + /* target id is meaningless here, but we set it just for fun */ + scnprintf(kbuf, count, "42 "); + } + + targets = str_to_target_ids(kbuf, count, &nr_targets); + if (!targets) { + ret = -ENOMEM; + goto out; + } + + if (id_is_pid) { + for (i = 0; i < nr_targets; i++) { + targets[i] = (unsigned long)find_get_pid( + (int)targets[i]); + if (!targets[i]) { + dbgfs_put_pids(targets, i); + ret = -EINVAL; + goto free_targets_out; + } + } + } + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + if (id_is_pid) + dbgfs_put_pids(targets, nr_targets); + ret = -EBUSY; + goto unlock_out; + } + + /* remove previously set targets */ + damon_for_each_target_safe(t, next_t, ctx) { + if (targetid_is_pid(ctx)) + put_pid((struct pid *)t->id); + damon_destroy_target(t); + } + + /* Configure the context for the address space type */ + if (id_is_pid) + damon_va_set_primitives(ctx); + else + damon_pa_set_primitives(ctx); + + ret = damon_set_targets(ctx, targets, nr_targets); + if (ret) { + if (id_is_pid) + dbgfs_put_pids(targets, nr_targets); + } else { + ret = count; + } + +unlock_out: + mutex_unlock(&ctx->kdamond_lock); +free_targets_out: + kfree(targets); +out: + kfree(kbuf); + return ret; +} + +static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len) +{ + struct damon_target *t; + struct damon_region *r; + int written = 0; + int rc; + + damon_for_each_target(t, c) { + damon_for_each_region(r, t) { + rc = scnprintf(&buf[written], len - written, + "%lu %lu %lu\n", + t->id, r->ar.start, r->ar.end); + if (!rc) + return -ENOMEM; + written += rc; + } + } + return written; +} + +static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + mutex_unlock(&ctx->kdamond_lock); + len = -EBUSY; + goto out; + } + + len = sprint_init_regions(ctx, kbuf, count); + mutex_unlock(&ctx->kdamond_lock); + if (len < 0) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static int add_init_region(struct damon_ctx *c, + unsigned long target_id, struct damon_addr_range *ar) +{ + struct damon_target *t; + struct damon_region *r, *prev; + unsigned long id; + int rc = -EINVAL; + + if (ar->start >= ar->end) + return -EINVAL; + + damon_for_each_target(t, c) { + id = t->id; + if (targetid_is_pid(c)) + id = (unsigned long)pid_vnr((struct pid *)id); + if (id == target_id) { + r = damon_new_region(ar->start, ar->end); + if (!r) + return -ENOMEM; + damon_add_region(r, t); + if (damon_nr_regions(t) > 1) { + prev = damon_prev_region(r); + if (prev->ar.end > r->ar.start) { + damon_destroy_region(r, t); + return -EINVAL; + } + } + rc = 0; + } + } + return rc; +} + +static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len) +{ + struct damon_target *t; + struct damon_region *r, *next; + int pos = 0, parsed, ret; + unsigned long target_id; + struct damon_addr_range ar; + int err; + + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + + while (pos < len) { + ret = sscanf(&str[pos], "%lu %lu %lu%n", + &target_id, &ar.start, &ar.end, &parsed); + if (ret != 3) + break; + err = add_init_region(c, target_id, &ar); + if (err) + goto fail; + pos += parsed; + } + + return 0; + +fail: + damon_for_each_target(t, c) { + damon_for_each_region_safe(r, next, t) + damon_destroy_region(r, t); + } + return err; +} + +static ssize_t dbgfs_init_regions_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t ret = count; + int err; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) { + ret = -EBUSY; + goto unlock_out; + } + + err = set_init_regions(ctx, kbuf, ret); + if (err) + ret = err; + +unlock_out: + mutex_unlock(&ctx->kdamond_lock); + kfree(kbuf); + return ret; +} + +static ssize_t dbgfs_kdamond_pid_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = file->private_data; + char *kbuf; + ssize_t len; + + kbuf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); + if (!kbuf) + return -ENOMEM; + + mutex_lock(&ctx->kdamond_lock); + if (ctx->kdamond) + len = scnprintf(kbuf, count, "%d\n", ctx->kdamond->pid); + else + len = scnprintf(kbuf, count, "none\n"); + mutex_unlock(&ctx->kdamond_lock); + if (!len) + goto out; + len = simple_read_from_buffer(buf, count, ppos, kbuf, len); + +out: + kfree(kbuf); + return len; +} + +static int damon_dbgfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return nonseekable_open(inode, file); +} + +static const struct file_operations attrs_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_attrs_read, + .write = dbgfs_attrs_write, +}; + +static const struct file_operations schemes_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_schemes_read, + .write = dbgfs_schemes_write, +}; + +static const struct file_operations target_ids_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_target_ids_read, + .write = dbgfs_target_ids_write, +}; + +static const struct file_operations init_regions_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_init_regions_read, + .write = dbgfs_init_regions_write, +}; + +static const struct file_operations kdamond_pid_fops = { + .open = damon_dbgfs_open, + .read = dbgfs_kdamond_pid_read, +}; + +static void dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx) +{ + const char * const file_names[] = {"attrs", "schemes", "target_ids", + "init_regions", "kdamond_pid"}; + const struct file_operations *fops[] = {&attrs_fops, &schemes_fops, + &target_ids_fops, &init_regions_fops, &kdamond_pid_fops}; + int i; + + for (i = 0; i < ARRAY_SIZE(file_names); i++) + debugfs_create_file(file_names[i], 0600, dir, ctx, fops[i]); +} + +static void dbgfs_before_terminate(struct damon_ctx *ctx) +{ + struct damon_target *t, *next; + + if (!targetid_is_pid(ctx)) + return; + + mutex_lock(&ctx->kdamond_lock); + damon_for_each_target_safe(t, next, ctx) { + put_pid((struct pid *)t->id); + damon_destroy_target(t); + } + mutex_unlock(&ctx->kdamond_lock); +} + +static struct damon_ctx *dbgfs_new_ctx(void) +{ + struct damon_ctx *ctx; + + ctx = damon_new_ctx(); + if (!ctx) + return NULL; + + damon_va_set_primitives(ctx); + ctx->callback.before_terminate = dbgfs_before_terminate; + return ctx; +} + +static void dbgfs_destroy_ctx(struct damon_ctx *ctx) +{ + damon_destroy_ctx(ctx); +} + +/* + * Make a context of @name and create a debugfs directory for it. + * + * This function should be called while holding damon_dbgfs_lock. + * + * Returns 0 on success, negative error code otherwise. + */ +static int dbgfs_mk_context(char *name) +{ + struct dentry *root, **new_dirs, *new_dir; + struct damon_ctx **new_ctxs, *new_ctx; + + if (damon_nr_running_ctxs()) + return -EBUSY; + + new_ctxs = krealloc(dbgfs_ctxs, sizeof(*dbgfs_ctxs) * + (dbgfs_nr_ctxs + 1), GFP_KERNEL); + if (!new_ctxs) + return -ENOMEM; + dbgfs_ctxs = new_ctxs; + + new_dirs = krealloc(dbgfs_dirs, sizeof(*dbgfs_dirs) * + (dbgfs_nr_ctxs + 1), GFP_KERNEL); + if (!new_dirs) + return -ENOMEM; + dbgfs_dirs = new_dirs; + + root = dbgfs_dirs[0]; + if (!root) + return -ENOENT; + + new_dir = debugfs_create_dir(name, root); + dbgfs_dirs[dbgfs_nr_ctxs] = new_dir; + + new_ctx = dbgfs_new_ctx(); + if (!new_ctx) { + debugfs_remove(new_dir); + dbgfs_dirs[dbgfs_nr_ctxs] = NULL; + return -ENOMEM; + } + + dbgfs_ctxs[dbgfs_nr_ctxs] = new_ctx; + dbgfs_fill_ctx_dir(dbgfs_dirs[dbgfs_nr_ctxs], + dbgfs_ctxs[dbgfs_nr_ctxs]); + dbgfs_nr_ctxs++; + + return 0; +} + +static ssize_t dbgfs_mk_context_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *kbuf; + char *ctx_name; + ssize_t ret; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + ctx_name = kmalloc(count + 1, GFP_KERNEL); + if (!ctx_name) { + kfree(kbuf); + return -ENOMEM; + } + + /* Trim white space */ + if (sscanf(kbuf, "%s", ctx_name) != 1) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&damon_dbgfs_lock); + ret = dbgfs_mk_context(ctx_name); + if (!ret) + ret = count; + mutex_unlock(&damon_dbgfs_lock); + +out: + kfree(kbuf); + kfree(ctx_name); + return ret; +} + +/* + * Remove a context of @name and its debugfs directory. + * + * This function should be called while holding damon_dbgfs_lock. + * + * Return 0 on success, negative error code otherwise. + */ +static int dbgfs_rm_context(char *name) +{ + struct dentry *root, *dir, **new_dirs; + struct damon_ctx **new_ctxs; + int i, j; + + if (damon_nr_running_ctxs()) + return -EBUSY; + + root = dbgfs_dirs[0]; + if (!root) + return -ENOENT; + + dir = debugfs_lookup(name, root); + if (!dir) + return -ENOENT; + + new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs), + GFP_KERNEL); + if (!new_dirs) + return -ENOMEM; + + new_ctxs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_ctxs), + GFP_KERNEL); + if (!new_ctxs) { + kfree(new_dirs); + return -ENOMEM; + } + + for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) { + if (dbgfs_dirs[i] == dir) { + debugfs_remove(dbgfs_dirs[i]); + dbgfs_destroy_ctx(dbgfs_ctxs[i]); + continue; + } + new_dirs[j] = dbgfs_dirs[i]; + new_ctxs[j++] = dbgfs_ctxs[i]; + } + + kfree(dbgfs_dirs); + kfree(dbgfs_ctxs); + + dbgfs_dirs = new_dirs; + dbgfs_ctxs = new_ctxs; + dbgfs_nr_ctxs--; + + return 0; +} + +static ssize_t dbgfs_rm_context_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *kbuf; + ssize_t ret; + char *ctx_name; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + ctx_name = kmalloc(count + 1, GFP_KERNEL); + if (!ctx_name) { + kfree(kbuf); + return -ENOMEM; + } + + /* Trim white space */ + if (sscanf(kbuf, "%s", ctx_name) != 1) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&damon_dbgfs_lock); + ret = dbgfs_rm_context(ctx_name); + if (!ret) + ret = count; + mutex_unlock(&damon_dbgfs_lock); + +out: + kfree(kbuf); + kfree(ctx_name); + return ret; +} + +static ssize_t dbgfs_monitor_on_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + char monitor_on_buf[5]; + bool monitor_on = damon_nr_running_ctxs() != 0; + int len; + + len = scnprintf(monitor_on_buf, 5, monitor_on ? "on\n" : "off\n"); + + return simple_read_from_buffer(buf, count, ppos, monitor_on_buf, len); +} + +static ssize_t dbgfs_monitor_on_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + ssize_t ret; + char *kbuf; + + kbuf = user_input_str(buf, count, ppos); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + /* Remove white space */ + if (sscanf(kbuf, "%s", kbuf) != 1) { + kfree(kbuf); + return -EINVAL; + } + + mutex_lock(&damon_dbgfs_lock); + if (!strncmp(kbuf, "on", count)) { + int i; + + for (i = 0; i < dbgfs_nr_ctxs; i++) { + if (damon_targets_empty(dbgfs_ctxs[i])) { + kfree(kbuf); + mutex_unlock(&damon_dbgfs_lock); + return -EINVAL; + } + } + ret = damon_start(dbgfs_ctxs, dbgfs_nr_ctxs); + } else if (!strncmp(kbuf, "off", count)) { + ret = damon_stop(dbgfs_ctxs, dbgfs_nr_ctxs); + } else { + ret = -EINVAL; + } + mutex_unlock(&damon_dbgfs_lock); + + if (!ret) + ret = count; + kfree(kbuf); + return ret; +} + +static const struct file_operations mk_contexts_fops = { + .write = dbgfs_mk_context_write, +}; + +static const struct file_operations rm_contexts_fops = { + .write = dbgfs_rm_context_write, +}; + +static const struct file_operations monitor_on_fops = { + .read = dbgfs_monitor_on_read, + .write = dbgfs_monitor_on_write, +}; + +static int __init __damon_dbgfs_init(void) +{ + struct dentry *dbgfs_root; + const char * const file_names[] = {"mk_contexts", "rm_contexts", + "monitor_on"}; + const struct file_operations *fops[] = {&mk_contexts_fops, + &rm_contexts_fops, &monitor_on_fops}; + int i; + + dbgfs_root = debugfs_create_dir("damon", NULL); + + for (i = 0; i < ARRAY_SIZE(file_names); i++) + debugfs_create_file(file_names[i], 0600, dbgfs_root, NULL, + fops[i]); + dbgfs_fill_ctx_dir(dbgfs_root, dbgfs_ctxs[0]); + + dbgfs_dirs = kmalloc_array(1, sizeof(dbgfs_root), GFP_KERNEL); + if (!dbgfs_dirs) { + debugfs_remove(dbgfs_root); + return -ENOMEM; + } + dbgfs_dirs[0] = dbgfs_root; + + return 0; +} + +/* + * Functions for the initialization + */ + +static int __init damon_dbgfs_init(void) +{ + int rc = -ENOMEM; + + mutex_lock(&damon_dbgfs_lock); + dbgfs_ctxs = kmalloc(sizeof(*dbgfs_ctxs), GFP_KERNEL); + if (!dbgfs_ctxs) + goto out; + dbgfs_ctxs[0] = dbgfs_new_ctx(); + if (!dbgfs_ctxs[0]) { + kfree(dbgfs_ctxs); + goto out; + } + dbgfs_nr_ctxs = 1; + + rc = __damon_dbgfs_init(); + if (rc) { + kfree(dbgfs_ctxs[0]); + kfree(dbgfs_ctxs); + pr_err("%s: dbgfs init failed\n", __func__); + } + +out: + mutex_unlock(&damon_dbgfs_lock); + return rc; +} + +module_init(damon_dbgfs_init); + +#include "dbgfs-test.h" diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c new file mode 100644 index 0000000000000000000000000000000000000000..5e8244f65a1a243291cc4c060366589c43486522 --- /dev/null +++ b/mm/damon/paddr.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Primitives for The Physical Address Space + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-pa: " fmt + +#include +#include +#include +#include +#include + +#include "../internal.h" +#include "prmtv-common.h" + +static bool __damon_pa_mkold(struct page *page, struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; + + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) + damon_ptep_mkold(pvmw.pte, vma->vm_mm, addr); + else + damon_pmdp_mkold(pvmw.pmd, vma->vm_mm, addr); + } + return true; +} + +static void damon_pa_mkold(unsigned long paddr) +{ + struct page *page = damon_get_page(PHYS_PFN(paddr)); + struct rmap_walk_control rwc = { + .rmap_one = __damon_pa_mkold, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page) + return; + + if (!page_mapped(page) || !page_rmapping(page)) { + set_page_idle(page); + goto out; + } + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) + goto out; + + rmap_walk(page, &rwc); + + if (need_lock) + unlock_page(page); + +out: + put_page(page); +} + +static void __damon_pa_prepare_access_check(struct damon_ctx *ctx, + struct damon_region *r) +{ + r->sampling_addr = damon_rand(r->ar.start, r->ar.end); + + damon_pa_mkold(r->sampling_addr); +} + +static void damon_pa_prepare_access_checks(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) + __damon_pa_prepare_access_check(ctx, r); + } +} + +struct damon_pa_access_chk_result { + unsigned long page_sz; + bool accessed; +}; + +static bool __damon_pa_young(struct page *page, struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct damon_pa_access_chk_result *result = arg; + struct page_vma_mapped_walk pvmw = { + .page = page, + .vma = vma, + .address = addr, + }; + + result->accessed = false; + result->page_sz = PAGE_SIZE; + while (page_vma_mapped_walk(&pvmw)) { + addr = pvmw.address; + if (pvmw.pte) { + result->accessed = pte_young(*pvmw.pte) || + !page_is_idle(page) || + mmu_notifier_test_young(vma->vm_mm, addr); + } else { +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + result->accessed = pmd_young(*pvmw.pmd) || + !page_is_idle(page) || + mmu_notifier_test_young(vma->vm_mm, addr); + result->page_sz = ((1UL) << HPAGE_PMD_SHIFT); +#else + WARN_ON_ONCE(1); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + } + if (result->accessed) { + page_vma_mapped_walk_done(&pvmw); + break; + } + } + + /* If accessed, stop walking */ + return !result->accessed; +} + +static bool damon_pa_young(unsigned long paddr, unsigned long *page_sz) +{ + struct page *page = damon_get_page(PHYS_PFN(paddr)); + struct damon_pa_access_chk_result result = { + .page_sz = PAGE_SIZE, + .accessed = false, + }; + struct rmap_walk_control rwc = { + .arg = &result, + .rmap_one = __damon_pa_young, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page) + return false; + + if (!page_mapped(page) || !page_rmapping(page)) { + if (page_is_idle(page)) + result.accessed = false; + else + result.accessed = true; + put_page(page); + goto out; + } + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) { + put_page(page); + return NULL; + } + + rmap_walk(page, &rwc); + + if (need_lock) + unlock_page(page); + put_page(page); + +out: + *page_sz = result.page_sz; + return result.accessed; +} + +static void __damon_pa_check_access(struct damon_ctx *ctx, + struct damon_region *r) +{ + static unsigned long last_addr; + static unsigned long last_page_sz = PAGE_SIZE; + static bool last_accessed; + + /* If the region is in the last checked page, reuse the result */ + if (ALIGN_DOWN(last_addr, last_page_sz) == + ALIGN_DOWN(r->sampling_addr, last_page_sz)) { + if (last_accessed) + r->nr_accesses++; + return; + } + + last_accessed = damon_pa_young(r->sampling_addr, &last_page_sz); + if (last_accessed) + r->nr_accesses++; + + last_addr = r->sampling_addr; +} + +static unsigned int damon_pa_check_accesses(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct damon_region *r; + unsigned int max_nr_accesses = 0; + + damon_for_each_target(t, ctx) { + damon_for_each_region(r, t) { + __damon_pa_check_access(ctx, r); + max_nr_accesses = max(r->nr_accesses, max_nr_accesses); + } + } + + return max_nr_accesses; +} + +bool damon_pa_target_valid(void *t) +{ + return true; +} + +static unsigned long damon_pa_apply_scheme(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + unsigned long addr, applied; + LIST_HEAD(page_list); + + if (scheme->action != DAMOS_PAGEOUT) + return 0; + + for (addr = r->ar.start; addr < r->ar.end; addr += PAGE_SIZE) { + struct page *page = damon_get_page(PHYS_PFN(addr)); + + if (!page) + continue; + + ClearPageReferenced(page); + test_and_clear_page_young(page); + if (isolate_lru_page(page)) { + put_page(page); + continue; + } + if (PageUnevictable(page)) { + putback_lru_page(page); + } else { + list_add(&page->lru, &page_list); + put_page(page); + } + } + applied = reclaim_pages(&page_list); + cond_resched(); + return applied * PAGE_SIZE; +} + +static int damon_pa_scheme_score(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + switch (scheme->action) { + case DAMOS_PAGEOUT: + return damon_pageout_score(context, r, scheme); + default: + break; + } + + return DAMOS_MAX_SCORE; +} + +void damon_pa_set_primitives(struct damon_ctx *ctx) +{ + ctx->primitive.init = NULL; + ctx->primitive.update = NULL; + ctx->primitive.prepare_access_checks = damon_pa_prepare_access_checks; + ctx->primitive.check_accesses = damon_pa_check_accesses; + ctx->primitive.reset_aggregated = NULL; + ctx->primitive.target_valid = damon_pa_target_valid; + ctx->primitive.cleanup = NULL; + ctx->primitive.apply_scheme = damon_pa_apply_scheme; + ctx->primitive.get_scheme_score = damon_pa_scheme_score; +} diff --git a/mm/damon/prmtv-common.c b/mm/damon/prmtv-common.c new file mode 100644 index 0000000000000000000000000000000000000000..92a04f5831d6bdab339e472c4fafa1da932c4630 --- /dev/null +++ b/mm/damon/prmtv-common.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common Primitives for Data Access Monitoring + * + * Author: SeongJae Park + */ + +#include +#include +#include +#include + +#include "prmtv-common.h" + +/* + * Get an online page for a pfn if it's in the LRU list. Otherwise, returns + * NULL. + * + * The body of this function is stolen from the 'page_idle_get_page()'. We + * steal rather than reuse it because the code is quite simple. + */ +struct page *damon_get_page(unsigned long pfn) +{ + struct page *page = pfn_to_online_page(pfn); + + if (!page || !PageLRU(page) || !get_page_unless_zero(page)) + return NULL; + + if (unlikely(!PageLRU(page))) { + put_page(page); + page = NULL; + } + return page; +} + +void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr) +{ + bool referenced = false; + struct page *page = damon_get_page(pte_pfn(*pte)); + + if (!page) + return; + + if (pte_young(*pte)) { + referenced = true; + *pte = pte_mkold(*pte); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, addr + PAGE_SIZE)) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +} + +void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr) +{ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + bool referenced = false; + struct page *page = damon_get_page(pmd_pfn(*pmd)); + + if (!page) + return; + + if (pmd_young(*pmd)) { + referenced = true; + *pmd = pmd_mkold(*pmd); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, + addr + ((1UL) << HPAGE_PMD_SHIFT))) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +} + +#define DAMON_MAX_SUBSCORE (100) +#define DAMON_MAX_AGE_IN_LOG (32) + +int damon_pageout_score(struct damon_ctx *c, struct damon_region *r, + struct damos *s) +{ + unsigned int max_nr_accesses; + int freq_subscore; + unsigned int age_in_sec; + int age_in_log, age_subscore; + unsigned int freq_weight = s->quota.weight_nr_accesses; + unsigned int age_weight = s->quota.weight_age; + int hotness; + + max_nr_accesses = c->aggr_interval / c->sample_interval; + freq_subscore = r->nr_accesses * DAMON_MAX_SUBSCORE / max_nr_accesses; + + age_in_sec = (unsigned long)r->age * c->aggr_interval / 1000000; + for (age_in_log = 0; age_in_log < DAMON_MAX_AGE_IN_LOG && age_in_sec; + age_in_log++, age_in_sec >>= 1) + ; + + /* If frequency is 0, higher age means it's colder */ + if (freq_subscore == 0) + age_in_log *= -1; + + /* + * Now age_in_log is in [-DAMON_MAX_AGE_IN_LOG, DAMON_MAX_AGE_IN_LOG]. + * Scale it to be in [0, 100] and set it as age subscore. + */ + age_in_log += DAMON_MAX_AGE_IN_LOG; + age_subscore = age_in_log * DAMON_MAX_SUBSCORE / + DAMON_MAX_AGE_IN_LOG / 2; + + hotness = (freq_weight * freq_subscore + age_weight * age_subscore); + if (freq_weight + age_weight) + hotness /= freq_weight + age_weight; + /* + * Transform it to fit in [0, DAMOS_MAX_SCORE] + */ + hotness = hotness * DAMOS_MAX_SCORE / DAMON_MAX_SUBSCORE; + + /* Return coldness of the region */ + return DAMOS_MAX_SCORE - hotness; +} diff --git a/mm/damon/prmtv-common.h b/mm/damon/prmtv-common.h new file mode 100644 index 0000000000000000000000000000000000000000..e790cb5f8fe05913ef868bd41743604c91d4aacf --- /dev/null +++ b/mm/damon/prmtv-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common Primitives for Data Access Monitoring + * + * Author: SeongJae Park + */ + +#include + +struct page *damon_get_page(unsigned long pfn); + +void damon_ptep_mkold(pte_t *pte, struct mm_struct *mm, unsigned long addr); +void damon_pmdp_mkold(pmd_t *pmd, struct mm_struct *mm, unsigned long addr); + +int damon_pageout_score(struct damon_ctx *c, struct damon_region *r, + struct damos *s); diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c new file mode 100644 index 0000000000000000000000000000000000000000..183d4f3b4fde7f4e78b97c445d9fed0c1533d908 --- /dev/null +++ b/mm/damon/reclaim.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON-based page reclamation + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-reclaim: " fmt + +#include +#include +#include +#include +#include + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "damon_reclaim." + +/* + * Enable or disable DAMON_RECLAIM. + * + * You can enable DAMON_RCLAIM by setting the value of this parameter as ``Y``. + * Setting it as ``N`` disables DAMON_RECLAIM. Note that DAMON_RECLAIM could + * do no real monitoring and reclamation due to the watermarks-based activation + * condition. Refer to below descriptions for the watermarks parameter for + * this. + */ +static bool enabled __read_mostly; + +/* + * Time threshold for cold memory regions identification in microseconds. + * + * If a memory region is not accessed for this or longer time, DAMON_RECLAIM + * identifies the region as cold, and reclaims. 120 seconds by default. + */ +static unsigned long min_age __read_mostly = 120000000; +module_param(min_age, ulong, 0600); + +/* + * Limit of time for trying the reclamation in milliseconds. + * + * DAMON_RECLAIM tries to use only up to this time within a time window + * (quota_reset_interval_ms) for trying reclamation of cold pages. This can be + * used for limiting CPU consumption of DAMON_RECLAIM. If the value is zero, + * the limit is disabled. + * + * 10 ms by default. + */ +static unsigned long quota_ms __read_mostly = 10; +module_param(quota_ms, ulong, 0600); + +/* + * Limit of size of memory for the reclamation in bytes. + * + * DAMON_RECLAIM charges amount of memory which it tried to reclaim within a + * time window (quota_reset_interval_ms) and makes no more than this limit is + * tried. This can be used for limiting consumption of CPU and IO. If this + * value is zero, the limit is disabled. + * + * 128 MiB by default. + */ +static unsigned long quota_sz __read_mostly = 128 * 1024 * 1024; +module_param(quota_sz, ulong, 0600); + +/* + * The time/size quota charge reset interval in milliseconds. + * + * The charge reset interval for the quota of time (quota_ms) and size + * (quota_sz). That is, DAMON_RECLAIM does not try reclamation for more than + * quota_ms milliseconds or quota_sz bytes within quota_reset_interval_ms + * milliseconds. + * + * 1 second by default. + */ +static unsigned long quota_reset_interval_ms __read_mostly = 1000; +module_param(quota_reset_interval_ms, ulong, 0600); + +/* + * The watermarks check time interval in microseconds. + * + * Minimal time to wait before checking the watermarks, when DAMON_RECLAIM is + * enabled but inactive due to its watermarks rule. 5 seconds by default. + */ +static unsigned long wmarks_interval __read_mostly = 5000000; +module_param(wmarks_interval, ulong, 0600); + +/* + * Free memory rate (per thousand) for the high watermark. + * + * If free memory of the system in bytes per thousand bytes is higher than + * this, DAMON_RECLAIM becomes inactive, so it does nothing but periodically + * checks the watermarks. 500 (50%) by default. + */ +static unsigned long wmarks_high __read_mostly = 500; +module_param(wmarks_high, ulong, 0600); + +/* + * Free memory rate (per thousand) for the middle watermark. + * + * If free memory of the system in bytes per thousand bytes is between this and + * the low watermark, DAMON_RECLAIM becomes active, so starts the monitoring + * and the reclaiming. 400 (40%) by default. + */ +static unsigned long wmarks_mid __read_mostly = 400; +module_param(wmarks_mid, ulong, 0600); + +/* + * Free memory rate (per thousand) for the low watermark. + * + * If free memory of the system in bytes per thousand bytes is lower than this, + * DAMON_RECLAIM becomes inactive, so it does nothing but periodically checks + * the watermarks. In the case, the system falls back to the LRU-based page + * granularity reclamation logic. 200 (20%) by default. + */ +static unsigned long wmarks_low __read_mostly = 200; +module_param(wmarks_low, ulong, 0600); + +/* + * Sampling interval for the monitoring in microseconds. + * + * The sampling interval of DAMON for the cold memory monitoring. Please refer + * to the DAMON documentation for more detail. 5 ms by default. + */ +static unsigned long sample_interval __read_mostly = 5000; +module_param(sample_interval, ulong, 0600); + +/* + * Aggregation interval for the monitoring in microseconds. + * + * The aggregation interval of DAMON for the cold memory monitoring. Please + * refer to the DAMON documentation for more detail. 100 ms by default. + */ +static unsigned long aggr_interval __read_mostly = 100000; +module_param(aggr_interval, ulong, 0600); + +/* + * Minimum number of monitoring regions. + * + * The minimal number of monitoring regions of DAMON for the cold memory + * monitoring. This can be used to set lower-bound of the monitoring quality. + * But, setting this too high could result in increased monitoring overhead. + * Please refer to the DAMON documentation for more detail. 10 by default. + */ +static unsigned long min_nr_regions __read_mostly = 10; +module_param(min_nr_regions, ulong, 0600); + +/* + * Maximum number of monitoring regions. + * + * The maximum number of monitoring regions of DAMON for the cold memory + * monitoring. This can be used to set upper-bound of the monitoring overhead. + * However, setting this too low could result in bad monitoring quality. + * Please refer to the DAMON documentation for more detail. 1000 by default. + */ +static unsigned long max_nr_regions __read_mostly = 1000; +module_param(max_nr_regions, ulong, 0600); + +/* + * Start of the target memory region in physical address. + * + * The start physical address of memory region that DAMON_RECLAIM will do work + * against. By default, biggest System RAM is used as the region. + */ +static unsigned long monitor_region_start __read_mostly; +module_param(monitor_region_start, ulong, 0600); + +/* + * End of the target memory region in physical address. + * + * The end physical address of memory region that DAMON_RECLAIM will do work + * against. By default, biggest System RAM is used as the region. + */ +static unsigned long monitor_region_end __read_mostly; +module_param(monitor_region_end, ulong, 0600); + +/* + * PID of the DAMON thread + * + * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread. + * Else, -1. + */ +static int kdamond_pid __read_mostly = -1; +module_param(kdamond_pid, int, 0400); + +/* + * Number of memory regions that tried to be reclaimed. + */ +static unsigned long nr_reclaim_tried_regions __read_mostly; +module_param(nr_reclaim_tried_regions, ulong, 0400); + +/* + * Total bytes of memory regions that tried to be reclaimed. + */ +static unsigned long bytes_reclaim_tried_regions __read_mostly; +module_param(bytes_reclaim_tried_regions, ulong, 0400); + +/* + * Number of memory regions that successfully be reclaimed. + */ +static unsigned long nr_reclaimed_regions __read_mostly; +module_param(nr_reclaimed_regions, ulong, 0400); + +/* + * Total bytes of memory regions that successfully be reclaimed. + */ +static unsigned long bytes_reclaimed_regions __read_mostly; +module_param(bytes_reclaimed_regions, ulong, 0400); + +/* + * Number of times that the time/space quota limits have exceeded + */ +static unsigned long nr_quota_exceeds __read_mostly; +module_param(nr_quota_exceeds, ulong, 0400); + +static struct damon_ctx *ctx; +static struct damon_target *target; + +struct damon_reclaim_ram_walk_arg { + unsigned long start; + unsigned long end; +}; + +static int walk_system_ram(struct resource *res, void *arg) +{ + struct damon_reclaim_ram_walk_arg *a = arg; + + if (a->end - a->start < res->end - res->start) { + a->start = res->start; + a->end = res->end; + } + return 0; +} + +/* + * Find biggest 'System RAM' resource and store its start and end address in + * @start and @end, respectively. If no System RAM is found, returns false. + */ +static bool get_monitoring_region(unsigned long *start, unsigned long *end) +{ + struct damon_reclaim_ram_walk_arg arg = {}; + + walk_system_ram_res(0, ULONG_MAX, &arg, walk_system_ram); + if (arg.end <= arg.start) + return false; + + *start = arg.start; + *end = arg.end; + return true; +} + +static struct damos *damon_reclaim_new_scheme(void) +{ + struct damos_watermarks wmarks = { + .metric = DAMOS_WMARK_FREE_MEM_RATE, + .interval = wmarks_interval, + .high = wmarks_high, + .mid = wmarks_mid, + .low = wmarks_low, + }; + struct damos_quota quota = { + /* + * Do not try reclamation for more than quota_ms milliseconds + * or quota_sz bytes within quota_reset_interval_ms. + */ + .ms = quota_ms, + .sz = quota_sz, + .reset_interval = quota_reset_interval_ms, + /* Within the quota, page out older regions first. */ + .weight_sz = 0, + .weight_nr_accesses = 0, + .weight_age = 1 + }; + struct damos *scheme = damon_new_scheme( + /* Find regions having PAGE_SIZE or larger size */ + PAGE_SIZE, ULONG_MAX, + /* and not accessed at all */ + 0, 0, + /* for min_age or more micro-seconds, and */ + min_age / aggr_interval, UINT_MAX, + /* page out those, as soon as found */ + DAMOS_PAGEOUT, + /* under the quota. */ + "a, + /* (De)activate this according to the watermarks. */ + &wmarks); + + return scheme; +} + +static int damon_reclaim_turn(bool on) +{ + struct damon_region *region; + struct damos *scheme; + int err; + + if (!on) { + err = damon_stop(&ctx, 1); + if (!err) + kdamond_pid = -1; + return err; + } + + err = damon_set_attrs(ctx, sample_interval, aggr_interval, 0, + min_nr_regions, max_nr_regions); + if (err) + return err; + + if (monitor_region_start > monitor_region_end) + return -EINVAL; + if (!monitor_region_start && !monitor_region_end && + !get_monitoring_region(&monitor_region_start, + &monitor_region_end)) + return -EINVAL; + /* DAMON will free this on its own when finish monitoring */ + region = damon_new_region(monitor_region_start, monitor_region_end); + if (!region) + return -ENOMEM; + damon_add_region(region, target); + + /* Will be freed by 'damon_set_schemes()' below */ + scheme = damon_reclaim_new_scheme(); + if (!scheme) { + err = -ENOMEM; + goto free_region_out; + } + err = damon_set_schemes(ctx, &scheme, 1); + if (err) + goto free_scheme_out; + + err = damon_start(&ctx, 1); + if (!err) { + kdamond_pid = ctx->kdamond->pid; + return 0; + } + +free_scheme_out: + damon_destroy_scheme(scheme); +free_region_out: + damon_destroy_region(region, target); + return err; +} + +#define ENABLE_CHECK_INTERVAL_MS 1000 +static struct delayed_work damon_reclaim_timer; +static void damon_reclaim_timer_fn(struct work_struct *work) +{ + static bool last_enabled; + bool now_enabled; + + now_enabled = enabled; + if (last_enabled != now_enabled) { + if (!damon_reclaim_turn(now_enabled)) + last_enabled = now_enabled; + else + enabled = last_enabled; + } + + if (enabled) + schedule_delayed_work(&damon_reclaim_timer, + msecs_to_jiffies(ENABLE_CHECK_INTERVAL_MS)); +} +static DECLARE_DELAYED_WORK(damon_reclaim_timer, damon_reclaim_timer_fn); + +static int enabled_store(const char *val, + const struct kernel_param *kp) +{ + int rc = param_set_bool(val, kp); + + if (rc < 0) + return rc; + + if (enabled) + schedule_delayed_work(&damon_reclaim_timer, 0); + + return 0; +} + +static const struct kernel_param_ops enabled_param_ops = { + .set = enabled_store, + .get = param_get_bool, +}; + +module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); +MODULE_PARM_DESC(enabled, + "Enable or disable DAMON_RECLAIM (default: disabled)"); + +static int damon_reclaim_after_aggregation(struct damon_ctx *c) +{ + struct damos *s; + + /* update the stats parameter */ + damon_for_each_scheme(s, c) { + nr_reclaim_tried_regions = s->stat.nr_tried; + bytes_reclaim_tried_regions = s->stat.sz_tried; + nr_reclaimed_regions = s->stat.nr_applied; + bytes_reclaimed_regions = s->stat.sz_applied; + nr_quota_exceeds = s->stat.qt_exceeds; + } + return 0; +} + +static int __init damon_reclaim_init(void) +{ + ctx = damon_new_ctx(); + if (!ctx) + return -ENOMEM; + + damon_pa_set_primitives(ctx); + ctx->callback.after_aggregation = damon_reclaim_after_aggregation; + + /* 4242 means nothing but fun */ + target = damon_new_target(4242); + if (!target) { + damon_destroy_ctx(ctx); + return -ENOMEM; + } + damon_add_target(ctx, target); + + schedule_delayed_work(&damon_reclaim_timer, 0); + return 0; +} + +module_init(damon_reclaim_init); diff --git a/mm/damon/vaddr-test.h b/mm/damon/vaddr-test.h new file mode 100644 index 0000000000000000000000000000000000000000..6a1b9272ea123a1f2991ad632daf17ef0b173c76 --- /dev/null +++ b/mm/damon/vaddr-test.h @@ -0,0 +1,324 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Data Access Monitor Unit Tests + * + * Copyright 2019 Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Author: SeongJae Park + */ + +#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST + +#ifndef _DAMON_VADDR_TEST_H +#define _DAMON_VADDR_TEST_H + +#include + +static void __link_vmas(struct vm_area_struct *vmas, ssize_t nr_vmas) +{ + int i, j; + unsigned long largest_gap, gap; + + if (!nr_vmas) + return; + + for (i = 0; i < nr_vmas - 1; i++) { + vmas[i].vm_next = &vmas[i + 1]; + + vmas[i].vm_rb.rb_left = NULL; + vmas[i].vm_rb.rb_right = &vmas[i + 1].vm_rb; + + largest_gap = 0; + for (j = i; j < nr_vmas; j++) { + if (j == 0) + continue; + gap = vmas[j].vm_start - vmas[j - 1].vm_end; + if (gap > largest_gap) + largest_gap = gap; + } + vmas[i].rb_subtree_gap = largest_gap; + } + vmas[i].vm_next = NULL; + vmas[i].vm_rb.rb_right = NULL; + vmas[i].rb_subtree_gap = 0; +} + +/* + * Test __damon_va_three_regions() function + * + * In case of virtual memory address spaces monitoring, DAMON converts the + * complex and dynamic memory mappings of each target task to three + * discontiguous regions which cover every mapped areas. However, the three + * regions should not include the two biggest unmapped areas in the original + * mapping, because the two biggest areas are normally the areas between 1) + * heap and the mmap()-ed regions, and 2) the mmap()-ed regions and stack. + * Because these two unmapped areas are very huge but obviously never accessed, + * covering the region is just a waste. + * + * '__damon_va_three_regions() receives an address space of a process. It + * first identifies the start of mappings, end of mappings, and the two biggest + * unmapped areas. After that, based on the information, it constructs the + * three regions and returns. For more detail, refer to the comment of + * 'damon_init_regions_of()' function definition in 'mm/damon.c' file. + * + * For example, suppose virtual address ranges of 10-20, 20-25, 200-210, + * 210-220, 300-305, and 307-330 (Other comments represent this mappings in + * more short form: 10-20-25, 200-210-220, 300-305, 307-330) of a process are + * mapped. To cover every mappings, the three regions should start with 10, + * and end with 305. The process also has three unmapped areas, 25-200, + * 220-300, and 305-307. Among those, 25-200 and 220-300 are the biggest two + * unmapped areas, and thus it should be converted to three regions of 10-25, + * 200-220, and 300-330. + */ +static void damon_test_three_regions_in_vmas(struct kunit *test) +{ + struct damon_addr_range regions[3] = {0,}; + /* 10-20-25, 200-210-220, 300-305, 307-330 */ + struct vm_area_struct vmas[] = { + (struct vm_area_struct) {.vm_start = 10, .vm_end = 20}, + (struct vm_area_struct) {.vm_start = 20, .vm_end = 25}, + (struct vm_area_struct) {.vm_start = 200, .vm_end = 210}, + (struct vm_area_struct) {.vm_start = 210, .vm_end = 220}, + (struct vm_area_struct) {.vm_start = 300, .vm_end = 305}, + (struct vm_area_struct) {.vm_start = 307, .vm_end = 330}, + }; + + __link_vmas(vmas, 6); + + __damon_va_three_regions(&vmas[0], regions); + + KUNIT_EXPECT_EQ(test, 10ul, regions[0].start); + KUNIT_EXPECT_EQ(test, 25ul, regions[0].end); + KUNIT_EXPECT_EQ(test, 200ul, regions[1].start); + KUNIT_EXPECT_EQ(test, 220ul, regions[1].end); + KUNIT_EXPECT_EQ(test, 300ul, regions[2].start); + KUNIT_EXPECT_EQ(test, 330ul, regions[2].end); +} + +static struct damon_region *__nth_region_of(struct damon_target *t, int idx) +{ + struct damon_region *r; + unsigned int i = 0; + + damon_for_each_region(r, t) { + if (i++ == idx) + return r; + } + + return NULL; +} + +/* + * Test 'damon_va_apply_three_regions()' + * + * test kunit object + * regions an array containing start/end addresses of current + * monitoring target regions + * nr_regions the number of the addresses in 'regions' + * three_regions The three regions that need to be applied now + * expected start/end addresses of monitoring target regions that + * 'three_regions' are applied + * nr_expected the number of addresses in 'expected' + * + * The memory mapping of the target processes changes dynamically. To follow + * the change, DAMON periodically reads the mappings, simplifies it to the + * three regions, and updates the monitoring target regions to fit in the three + * regions. The update of current target regions is the role of + * 'damon_va_apply_three_regions()'. + * + * This test passes the given target regions and the new three regions that + * need to be applied to the function and check whether it updates the regions + * as expected. + */ +static void damon_do_test_apply_three_regions(struct kunit *test, + unsigned long *regions, int nr_regions, + struct damon_addr_range *three_regions, + unsigned long *expected, int nr_expected) +{ + struct damon_target *t; + struct damon_region *r; + int i; + + t = damon_new_target(42); + for (i = 0; i < nr_regions / 2; i++) { + r = damon_new_region(regions[i * 2], regions[i * 2 + 1]); + damon_add_region(r, t); + } + + damon_va_apply_three_regions(t, three_regions); + + for (i = 0; i < nr_expected / 2; i++) { + r = __nth_region_of(t, i); + KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]); + KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]); + } +} + +/* + * This function test most common case where the three big regions are only + * slightly changed. Target regions should adjust their boundary (10-20-30, + * 50-55, 70-80, 90-100) to fit with the new big regions or remove target + * regions (57-79) that now out of the three regions. + */ +static void damon_test_apply_three_regions1(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-27, 45-55, 73-104 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 27}, + (struct damon_addr_range){.start = 45, .end = 55}, + (struct damon_addr_range){.start = 73, .end = 104} }; + /* 5-20-27, 45-55, 73-80-90-104 */ + unsigned long expected[] = {5, 20, 20, 27, 45, 55, + 73, 80, 80, 90, 90, 104}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +/* + * Test slightly bigger change. Similar to above, but the second big region + * now require two target regions (50-55, 57-59) to be removed. + */ +static void damon_test_apply_three_regions2(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-27, 56-57, 65-104 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 27}, + (struct damon_addr_range){.start = 56, .end = 57}, + (struct damon_addr_range){.start = 65, .end = 104} }; + /* 5-20-27, 56-57, 65-80-90-104 */ + unsigned long expected[] = {5, 20, 20, 27, 56, 57, + 65, 80, 80, 90, 90, 104}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +/* + * Test a big change. The second big region has totally freed and mapped to + * different area (50-59 -> 61-63). The target regions which were in the old + * second big region (50-55-57-59) should be removed and new target region + * covering the second big region (61-63) should be created. + */ +static void damon_test_apply_three_regions3(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-27, 61-63, 65-104 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 27}, + (struct damon_addr_range){.start = 61, .end = 63}, + (struct damon_addr_range){.start = 65, .end = 104} }; + /* 5-20-27, 61-63, 65-80-90-104 */ + unsigned long expected[] = {5, 20, 20, 27, 61, 63, + 65, 80, 80, 90, 90, 104}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +/* + * Test another big change. Both of the second and third big regions (50-59 + * and 70-100) has totally freed and mapped to different area (30-32 and + * 65-68). The target regions which were in the old second and third big + * regions should now be removed and new target regions covering the new second + * and third big regions should be created. + */ +static void damon_test_apply_three_regions4(struct kunit *test) +{ + /* 10-20-30, 50-55-57-59, 70-80-90-100 */ + unsigned long regions[] = {10, 20, 20, 30, 50, 55, 55, 57, 57, 59, + 70, 80, 80, 90, 90, 100}; + /* 5-7, 30-32, 65-68 */ + struct damon_addr_range new_three_regions[3] = { + (struct damon_addr_range){.start = 5, .end = 7}, + (struct damon_addr_range){.start = 30, .end = 32}, + (struct damon_addr_range){.start = 65, .end = 68} }; + /* expect 5-7, 30-32, 65-68 */ + unsigned long expected[] = {5, 7, 30, 32, 65, 68}; + + damon_do_test_apply_three_regions(test, regions, ARRAY_SIZE(regions), + new_three_regions, expected, ARRAY_SIZE(expected)); +} + +static void damon_test_split_evenly_fail(struct kunit *test, + unsigned long start, unsigned long end, unsigned int nr_pieces) +{ + struct damon_target *t = damon_new_target(42); + struct damon_region *r = damon_new_region(start, end); + + damon_add_region(r, t); + KUNIT_EXPECT_EQ(test, + damon_va_evenly_split_region(t, r, nr_pieces), -EINVAL); + KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u); + + damon_for_each_region(r, t) { + KUNIT_EXPECT_EQ(test, r->ar.start, start); + KUNIT_EXPECT_EQ(test, r->ar.end, end); + } + + damon_free_target(t); +} + +static void damon_test_split_evenly_succ(struct kunit *test, + unsigned long start, unsigned long end, unsigned int nr_pieces) +{ + struct damon_target *t = damon_new_target(42); + struct damon_region *r = damon_new_region(start, end); + unsigned long expected_width = (end - start) / nr_pieces; + unsigned long i = 0; + + damon_add_region(r, t); + KUNIT_EXPECT_EQ(test, + damon_va_evenly_split_region(t, r, nr_pieces), 0); + KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_pieces); + + damon_for_each_region(r, t) { + if (i == nr_pieces - 1) + break; + KUNIT_EXPECT_EQ(test, + r->ar.start, start + i++ * expected_width); + KUNIT_EXPECT_EQ(test, r->ar.end, start + i * expected_width); + } + KUNIT_EXPECT_EQ(test, r->ar.start, start + i * expected_width); + KUNIT_EXPECT_EQ(test, r->ar.end, end); + damon_free_target(t); +} + +static void damon_test_split_evenly(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5), + -EINVAL); + + damon_test_split_evenly_fail(test, 0, 100, 0); + damon_test_split_evenly_succ(test, 0, 100, 10); + damon_test_split_evenly_succ(test, 5, 59, 5); + damon_test_split_evenly_fail(test, 5, 6, 2); +} + +static struct kunit_case damon_test_cases[] = { + KUNIT_CASE(damon_test_three_regions_in_vmas), + KUNIT_CASE(damon_test_apply_three_regions1), + KUNIT_CASE(damon_test_apply_three_regions2), + KUNIT_CASE(damon_test_apply_three_regions3), + KUNIT_CASE(damon_test_apply_three_regions4), + KUNIT_CASE(damon_test_split_evenly), + {}, +}; + +static struct kunit_suite damon_test_suite = { + .name = "damon-primitives", + .test_cases = damon_test_cases, +}; +kunit_test_suite(damon_test_suite); + +#endif /* _DAMON_VADDR_TEST_H */ + +#endif /* CONFIG_DAMON_VADDR_KUNIT_TEST */ diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c new file mode 100644 index 0000000000000000000000000000000000000000..89b6468da2b9b0d595a34bbcf4ded9231f80c2ad --- /dev/null +++ b/mm/damon/vaddr.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DAMON Primitives for Virtual Address Spaces + * + * Author: SeongJae Park + */ + +#define pr_fmt(fmt) "damon-va: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "prmtv-common.h" + +#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST +#undef DAMON_MIN_REGION +#define DAMON_MIN_REGION 1 +#endif + +/* + * 't->id' should be the pointer to the relevant 'struct pid' having reference + * count. Caller must put the returned task, unless it is NULL. + */ +static inline struct task_struct *damon_get_task_struct(struct damon_target *t) +{ + return get_pid_task((struct pid *)t->id, PIDTYPE_PID); +} + +/* + * Get the mm_struct of the given target + * + * Caller _must_ put the mm_struct after use, unless it is NULL. + * + * Returns the mm_struct of the target on success, NULL on failure + */ +static struct mm_struct *damon_get_mm(struct damon_target *t) +{ + struct task_struct *task; + struct mm_struct *mm; + + task = damon_get_task_struct(t); + if (!task) + return NULL; + + mm = get_task_mm(task); + put_task_struct(task); + return mm; +} + +/* + * Functions for the initial monitoring target regions construction + */ + +/* + * Size-evenly split a region into 'nr_pieces' small regions + * + * Returns 0 on success, or negative error code otherwise. + */ +static int damon_va_evenly_split_region(struct damon_target *t, + struct damon_region *r, unsigned int nr_pieces) +{ + unsigned long sz_orig, sz_piece, orig_end; + struct damon_region *n = NULL, *next; + unsigned long start; + + if (!r || !nr_pieces) + return -EINVAL; + + orig_end = r->ar.end; + sz_orig = r->ar.end - r->ar.start; + sz_piece = ALIGN_DOWN(sz_orig / nr_pieces, DAMON_MIN_REGION); + + if (!sz_piece) + return -EINVAL; + + r->ar.end = r->ar.start + sz_piece; + next = damon_next_region(r); + for (start = r->ar.end; start + sz_piece <= orig_end; + start += sz_piece) { + n = damon_new_region(start, start + sz_piece); + if (!n) + return -ENOMEM; + damon_insert_region(n, r, next, t); + r = n; + } + /* complement last region for possible rounding error */ + if (n) + n->ar.end = orig_end; + + return 0; +} + +static unsigned long sz_range(struct damon_addr_range *r) +{ + return r->end - r->start; +} + +/* + * Find three regions separated by two biggest unmapped regions + * + * vma the head vma of the target address space + * regions an array of three address ranges that results will be saved + * + * This function receives an address space and finds three regions in it which + * separated by the two biggest unmapped regions in the space. Please refer to + * below comments of '__damon_va_init_regions()' function to know why this is + * necessary. + * + * Returns 0 if success, or negative error code otherwise. + */ +static int __damon_va_three_regions(struct vm_area_struct *vma, + struct damon_addr_range regions[3]) +{ + struct damon_addr_range gap = {0}, first_gap = {0}, second_gap = {0}; + struct vm_area_struct *last_vma = NULL; + unsigned long start = 0; + struct rb_root rbroot; + + /* Find two biggest gaps so that first_gap > second_gap > others */ + for (; vma; vma = vma->vm_next) { + if (!last_vma) { + start = vma->vm_start; + goto next; + } + + if (vma->rb_subtree_gap <= sz_range(&second_gap)) { + rbroot.rb_node = &vma->vm_rb; + vma = rb_entry(rb_last(&rbroot), + struct vm_area_struct, vm_rb); + goto next; + } + + gap.start = last_vma->vm_end; + gap.end = vma->vm_start; + if (sz_range(&gap) > sz_range(&second_gap)) { + swap(gap, second_gap); + if (sz_range(&second_gap) > sz_range(&first_gap)) + swap(second_gap, first_gap); + } +next: + last_vma = vma; + } + + if (!sz_range(&second_gap) || !sz_range(&first_gap)) + return -EINVAL; + + /* Sort the two biggest gaps by address */ + if (first_gap.start > second_gap.start) + swap(first_gap, second_gap); + + /* Store the result */ + regions[0].start = ALIGN(start, DAMON_MIN_REGION); + regions[0].end = ALIGN(first_gap.start, DAMON_MIN_REGION); + regions[1].start = ALIGN(first_gap.end, DAMON_MIN_REGION); + regions[1].end = ALIGN(second_gap.start, DAMON_MIN_REGION); + regions[2].start = ALIGN(second_gap.end, DAMON_MIN_REGION); + regions[2].end = ALIGN(last_vma->vm_end, DAMON_MIN_REGION); + + return 0; +} + +/* + * Get the three regions in the given target (task) + * + * Returns 0 on success, negative error code otherwise. + */ +static int damon_va_three_regions(struct damon_target *t, + struct damon_addr_range regions[3]) +{ + struct mm_struct *mm; + int rc; + + mm = damon_get_mm(t); + if (!mm) + return -EINVAL; + + mmap_read_lock(mm); + rc = __damon_va_three_regions(mm->mmap, regions); + mmap_read_unlock(mm); + + mmput(mm); + return rc; +} + +/* + * Initialize the monitoring target regions for the given target (task) + * + * t the given target + * + * Because only a number of small portions of the entire address space + * is actually mapped to the memory and accessed, monitoring the unmapped + * regions is wasteful. That said, because we can deal with small noises, + * tracking every mapping is not strictly required but could even incur a high + * overhead if the mapping frequently changes or the number of mappings is + * high. The adaptive regions adjustment mechanism will further help to deal + * with the noise by simply identifying the unmapped areas as a region that + * has no access. Moreover, applying the real mappings that would have many + * unmapped areas inside will make the adaptive mechanism quite complex. That + * said, too huge unmapped areas inside the monitoring target should be removed + * to not take the time for the adaptive mechanism. + * + * For the reason, we convert the complex mappings to three distinct regions + * that cover every mapped area of the address space. Also the two gaps + * between the three regions are the two biggest unmapped areas in the given + * address space. In detail, this function first identifies the start and the + * end of the mappings and the two biggest unmapped areas of the address space. + * Then, it constructs the three regions as below: + * + * [mappings[0]->start, big_two_unmapped_areas[0]->start) + * [big_two_unmapped_areas[0]->end, big_two_unmapped_areas[1]->start) + * [big_two_unmapped_areas[1]->end, mappings[nr_mappings - 1]->end) + * + * As usual memory map of processes is as below, the gap between the heap and + * the uppermost mmap()-ed region, and the gap between the lowermost mmap()-ed + * region and the stack will be two biggest unmapped regions. Because these + * gaps are exceptionally huge areas in usual address space, excluding these + * two biggest unmapped regions will be sufficient to make a trade-off. + * + * + * + * + * (other mmap()-ed regions and small unmapped regions) + * + * + * + */ +static void __damon_va_init_regions(struct damon_ctx *ctx, + struct damon_target *t) +{ + struct damon_target *ti; + struct damon_region *r; + struct damon_addr_range regions[3]; + unsigned long sz = 0, nr_pieces; + int i, tidx = 0; + + if (damon_va_three_regions(t, regions)) { + damon_for_each_target(ti, ctx) { + if (ti == t) + break; + tidx++; + } + pr_debug("Failed to get three regions of %dth target\n", tidx); + return; + } + + for (i = 0; i < 3; i++) + sz += regions[i].end - regions[i].start; + if (ctx->min_nr_regions) + sz /= ctx->min_nr_regions; + if (sz < DAMON_MIN_REGION) + sz = DAMON_MIN_REGION; + + /* Set the initial three regions of the target */ + for (i = 0; i < 3; i++) { + r = damon_new_region(regions[i].start, regions[i].end); + if (!r) { + pr_err("%d'th init region creation failed\n", i); + return; + } + damon_add_region(r, t); + + nr_pieces = (regions[i].end - regions[i].start) / sz; + damon_va_evenly_split_region(t, r, nr_pieces); + } +} + +/* Initialize '->regions_list' of every target (task) */ +static void damon_va_init(struct damon_ctx *ctx) +{ + struct damon_target *t; + + damon_for_each_target(t, ctx) { + /* the user may set the target regions as they want */ + if (!damon_nr_regions(t)) + __damon_va_init_regions(ctx, t); + } +} + +/* + * Functions for the dynamic monitoring target regions update + */ + +/* + * Check whether a region is intersecting an address range + * + * Returns true if it is. + */ +static bool damon_intersect(struct damon_region *r, + struct damon_addr_range *re) +{ + return !(r->ar.end <= re->start || re->end <= r->ar.start); +} + +/* + * Update damon regions for the three big regions of the given target + * + * t the given target + * bregions the three big regions of the target + */ +static void damon_va_apply_three_regions(struct damon_target *t, + struct damon_addr_range bregions[3]) +{ + struct damon_region *r, *next; + unsigned int i; + + /* Remove regions which are not in the three big regions now */ + damon_for_each_region_safe(r, next, t) { + for (i = 0; i < 3; i++) { + if (damon_intersect(r, &bregions[i])) + break; + } + if (i == 3) + damon_destroy_region(r, t); + } + + /* Adjust intersecting regions to fit with the three big regions */ + for (i = 0; i < 3; i++) { + struct damon_region *first = NULL, *last; + struct damon_region *newr; + struct damon_addr_range *br; + + br = &bregions[i]; + /* Get the first and last regions which intersects with br */ + damon_for_each_region(r, t) { + if (damon_intersect(r, br)) { + if (!first) + first = r; + last = r; + } + if (r->ar.start >= br->end) + break; + } + if (!first) { + /* no damon_region intersects with this big region */ + newr = damon_new_region( + ALIGN_DOWN(br->start, + DAMON_MIN_REGION), + ALIGN(br->end, DAMON_MIN_REGION)); + if (!newr) + continue; + damon_insert_region(newr, damon_prev_region(r), r, t); + } else { + first->ar.start = ALIGN_DOWN(br->start, + DAMON_MIN_REGION); + last->ar.end = ALIGN(br->end, DAMON_MIN_REGION); + } + } +} + +/* + * Update regions for current memory mappings + */ +static void damon_va_update(struct damon_ctx *ctx) +{ + struct damon_addr_range three_regions[3]; + struct damon_target *t; + + damon_for_each_target(t, ctx) { + if (damon_va_three_regions(t, three_regions)) + continue; + damon_va_apply_three_regions(t, three_regions); + } +} + +static int damon_mkold_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pte_t *pte; + spinlock_t *ptl; + + if (pmd_huge(*pmd)) { + ptl = pmd_lock(walk->mm, pmd); + if (pmd_huge(*pmd)) { + damon_pmdp_mkold(pmd, walk->mm, addr); + spin_unlock(ptl); + return 0; + } + spin_unlock(ptl); + } + + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + return 0; + pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (!pte_present(*pte)) + goto out; + damon_ptep_mkold(pte, walk->mm, addr); +out: + pte_unmap_unlock(pte, ptl); + return 0; +} + +#ifdef CONFIG_HUGETLB_PAGE +static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm, + struct vm_area_struct *vma, unsigned long addr) +{ + bool referenced = false; + pte_t entry = huge_ptep_get(pte); + struct page *page = pte_page(entry); + + if (!page) + return; + + get_page(page); + + if (pte_young(entry)) { + referenced = true; + entry = pte_mkold(entry); + huge_ptep_set_access_flags(vma, addr, pte, entry, + vma->vm_flags & VM_WRITE); + } + +#ifdef CONFIG_MMU_NOTIFIER + if (mmu_notifier_clear_young(mm, addr, + addr + huge_page_size(hstate_vma(vma)))) + referenced = true; +#endif /* CONFIG_MMU_NOTIFIER */ + + if (referenced) + set_page_young(page); + + set_page_idle(page); + put_page(page); +} + +static int damon_mkold_hugetlb_entry(pte_t *pte, unsigned long hmask, + unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct hstate *h = hstate_vma(walk->vma); + spinlock_t *ptl; + pte_t entry; + + ptl = huge_pte_lock(h, walk->mm, pte); + entry = huge_ptep_get(pte); + if (!pte_present(entry)) + goto out; + + damon_hugetlb_mkold(pte, walk->mm, walk->vma, addr); + +out: + spin_unlock(ptl); + return 0; +} +#else +#define damon_mkold_hugetlb_entry NULL +#endif /* CONFIG_HUGETLB_PAGE */ + +static const struct mm_walk_ops damon_mkold_ops = { + .pmd_entry = damon_mkold_pmd_entry, + .hugetlb_entry = damon_mkold_hugetlb_entry, +}; + +static void damon_va_mkold(struct mm_struct *mm, unsigned long addr) +{ + mmap_read_lock(mm); + walk_page_range(mm, addr, addr + 1, &damon_mkold_ops, NULL); + mmap_read_unlock(mm); +} + +/* + * Functions for the access checking of the regions + */ + +static void __damon_va_prepare_access_check(struct damon_ctx *ctx, + struct mm_struct *mm, struct damon_region *r) +{ + r->sampling_addr = damon_rand(r->ar.start, r->ar.end); + + damon_va_mkold(mm, r->sampling_addr); +} + +static void damon_va_prepare_access_checks(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct mm_struct *mm; + struct damon_region *r; + + damon_for_each_target(t, ctx) { + mm = damon_get_mm(t); + if (!mm) + continue; + damon_for_each_region(r, t) + __damon_va_prepare_access_check(ctx, mm, r); + mmput(mm); + } +} + +struct damon_young_walk_private { + unsigned long *page_sz; + bool young; +}; + +static int damon_young_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pte_t *pte; + spinlock_t *ptl; + struct page *page; + struct damon_young_walk_private *priv = walk->private; + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_huge(*pmd)) { + ptl = pmd_lock(walk->mm, pmd); + if (!pmd_huge(*pmd)) { + spin_unlock(ptl); + goto regular_page; + } + page = damon_get_page(pmd_pfn(*pmd)); + if (!page) + goto huge_out; + if (pmd_young(*pmd) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, + addr)) { + *priv->page_sz = ((1UL) << HPAGE_PMD_SHIFT); + priv->young = true; + } + put_page(page); +huge_out: + spin_unlock(ptl); + return 0; + } + +regular_page: +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + return -EINVAL; + pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + if (!pte_present(*pte)) + goto out; + page = damon_get_page(pte_pfn(*pte)); + if (!page) + goto out; + if (pte_young(*pte) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, addr)) { + *priv->page_sz = PAGE_SIZE; + priv->young = true; + } + put_page(page); +out: + pte_unmap_unlock(pte, ptl); + return 0; +} + +#ifdef CONFIG_HUGETLB_PAGE +static int damon_young_hugetlb_entry(pte_t *pte, unsigned long hmask, + unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct damon_young_walk_private *priv = walk->private; + struct hstate *h = hstate_vma(walk->vma); + struct page *page; + spinlock_t *ptl; + pte_t entry; + + ptl = huge_pte_lock(h, walk->mm, pte); + entry = huge_ptep_get(pte); + if (!pte_present(entry)) + goto out; + + page = pte_page(entry); + if (!page) + goto out; + + get_page(page); + + if (pte_young(entry) || !page_is_idle(page) || + mmu_notifier_test_young(walk->mm, addr)) { + *priv->page_sz = huge_page_size(h); + priv->young = true; + } + + put_page(page); + +out: + spin_unlock(ptl); + return 0; +} +#else +#define damon_young_hugetlb_entry NULL +#endif /* CONFIG_HUGETLB_PAGE */ + +static const struct mm_walk_ops damon_young_ops = { + .pmd_entry = damon_young_pmd_entry, + .hugetlb_entry = damon_young_hugetlb_entry, +}; + +static bool damon_va_young(struct mm_struct *mm, unsigned long addr, + unsigned long *page_sz) +{ + struct damon_young_walk_private arg = { + .page_sz = page_sz, + .young = false, + }; + + mmap_read_lock(mm); + walk_page_range(mm, addr, addr + 1, &damon_young_ops, &arg); + mmap_read_unlock(mm); + return arg.young; +} + +/* + * Check whether the region was accessed after the last preparation + * + * mm 'mm_struct' for the given virtual address space + * r the region to be checked + */ +static void __damon_va_check_access(struct damon_ctx *ctx, + struct mm_struct *mm, struct damon_region *r) +{ + static struct mm_struct *last_mm; + static unsigned long last_addr; + static unsigned long last_page_sz = PAGE_SIZE; + static bool last_accessed; + + /* If the region is in the last checked page, reuse the result */ + if (mm == last_mm && (ALIGN_DOWN(last_addr, last_page_sz) == + ALIGN_DOWN(r->sampling_addr, last_page_sz))) { + if (last_accessed) + r->nr_accesses++; + return; + } + + last_accessed = damon_va_young(mm, r->sampling_addr, &last_page_sz); + if (last_accessed) + r->nr_accesses++; + + last_mm = mm; + last_addr = r->sampling_addr; +} + +static unsigned int damon_va_check_accesses(struct damon_ctx *ctx) +{ + struct damon_target *t; + struct mm_struct *mm; + struct damon_region *r; + unsigned int max_nr_accesses = 0; + + damon_for_each_target(t, ctx) { + mm = damon_get_mm(t); + if (!mm) + continue; + damon_for_each_region(r, t) { + __damon_va_check_access(ctx, mm, r); + max_nr_accesses = max(r->nr_accesses, max_nr_accesses); + } + mmput(mm); + } + + return max_nr_accesses; +} + +/* + * Functions for the target validity check and cleanup + */ + +bool damon_va_target_valid(void *target) +{ + struct damon_target *t = target; + struct task_struct *task; + + task = damon_get_task_struct(t); + if (task) { + put_task_struct(task); + return true; + } + + return false; +} + +#ifndef CONFIG_ADVISE_SYSCALLS +static unsigned long damos_madvise(struct damon_target *target, + struct damon_region *r, int behavior) +{ + return 0; +} +#else +static unsigned long damos_madvise(struct damon_target *target, + struct damon_region *r, int behavior) +{ + struct mm_struct *mm; + unsigned long start = PAGE_ALIGN(r->ar.start); + unsigned long len = PAGE_ALIGN(r->ar.end - r->ar.start); + unsigned long applied; + + mm = damon_get_mm(target); + if (!mm) + return 0; + + applied = do_madvise(mm, start, len, behavior) ? 0 : len; + mmput(mm); + + return applied; +} +#endif /* CONFIG_ADVISE_SYSCALLS */ + +static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + int madv_action; + + switch (scheme->action) { + case DAMOS_WILLNEED: + madv_action = MADV_WILLNEED; + break; + case DAMOS_COLD: + madv_action = MADV_COLD; + break; + case DAMOS_PAGEOUT: + madv_action = MADV_PAGEOUT; + break; + case DAMOS_HUGEPAGE: + madv_action = MADV_HUGEPAGE; + break; + case DAMOS_NOHUGEPAGE: + madv_action = MADV_NOHUGEPAGE; + break; + case DAMOS_STAT: + return 0; + default: + return 0; + } + + return damos_madvise(t, r, madv_action); +} + +static int damon_va_scheme_score(struct damon_ctx *context, + struct damon_target *t, struct damon_region *r, + struct damos *scheme) +{ + + switch (scheme->action) { + case DAMOS_PAGEOUT: + return damon_pageout_score(context, r, scheme); + default: + break; + } + + return DAMOS_MAX_SCORE; +} + +void damon_va_set_primitives(struct damon_ctx *ctx) +{ + ctx->primitive.init = damon_va_init; + ctx->primitive.update = damon_va_update; + ctx->primitive.prepare_access_checks = damon_va_prepare_access_checks; + ctx->primitive.check_accesses = damon_va_check_accesses; + ctx->primitive.reset_aggregated = NULL; + ctx->primitive.target_valid = damon_va_target_valid; + ctx->primitive.cleanup = NULL; + ctx->primitive.apply_scheme = damon_va_apply_scheme; + ctx->primitive.get_scheme_score = damon_va_scheme_score; +} + +#include "vaddr-test.h" diff --git a/mm/debug.c b/mm/debug.c index aa44dea5276f54fec9e7204b6c169468624b5971..061e2eb08981e47fcfc96ca884e253f10453ef41 100644 --- a/mm/debug.c +++ b/mm/debug.c @@ -192,7 +192,6 @@ void dump_page(struct page *page, const char *reason) { __dump_page(page, reason); dump_page_owner(page); - dump_page_pinner(page); } EXPORT_SYMBOL(dump_page); diff --git a/mm/gup.c b/mm/gup.c index 54b0a694712e26d442935695ed910163616a711f..b831cdecdc94760c0c42232c6bf0ae801113b4d9 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -25,6 +25,9 @@ #include "internal.h" +#undef CREATE_TRACE_POINTS +#include + struct follow_page_context { struct dev_pagemap *pgmap; unsigned int page_mask; @@ -116,11 +119,14 @@ static __maybe_unused struct page *try_grab_compound_head(struct page *page, int refs, unsigned int flags) { + bool vendor_ret = false; + + trace_android_vh_try_grab_compound_head(page, refs, flags, &vendor_ret); + if (vendor_ret) + return NULL; + if (flags & FOLL_GET) { - struct page *head = try_get_compound_head(page, refs); - if (head) - set_page_pinner(head, compound_order(head)); - return head; + return try_get_compound_head(page, refs); } else if (flags & FOLL_PIN) { int orig_refs = refs; @@ -175,8 +181,6 @@ static void put_compound_head(struct page *page, int refs, unsigned int flags) refs *= GUP_PIN_COUNTING_BIAS; } - if (flags & FOLL_GET) - reset_page_pinner(page, compound_order(page)); put_page_refs(page, refs); } @@ -206,13 +210,7 @@ bool __must_check try_grab_page(struct page *page, unsigned int flags) WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN)); if (flags & FOLL_GET) { - bool ret = try_get_page(page); - - if (ret) { - page = compound_head(page); - set_page_pinner(page, compound_order(page)); - } - return ret; + return try_get_page(page); } else if (flags & FOLL_PIN) { int refs = 1; @@ -255,24 +253,6 @@ void unpin_user_page(struct page *page) } EXPORT_SYMBOL(unpin_user_page); -/* - * put_user_page() - release a page obtained using get_user_pages() or - * follow_page(FOLL_GET) - * @page: pointer to page to be released - * - * Pages that were obtained via get_user_pages()/follow_page(FOLL_GET) must be - * released via put_user_page. - * note: If it's not a page from GUP or follow_page(FOLL_GET), it's harmless. - */ -void put_user_page(struct page *page) -{ - struct page *head = compound_head(page); - - reset_page_pinner(head, compound_order(head)); - put_page(page); -} -EXPORT_SYMBOL(put_user_page); - /** * unpin_user_pages_dirty_lock() - release and optionally dirty gup-pinned pages * @pages: array of pages to be maybe marked dirty, and definitely released. @@ -1760,6 +1740,10 @@ static long __get_user_pages_remote(struct mm_struct *mm, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas, int *locked) { + unsigned int orig_gup_flags = gup_flags; + + trace_android_vh___get_user_pages_remote(locked, &gup_flags, pages); + /* * Parts of FOLL_LONGTERM behavior are incompatible with * FAULT_FLAG_ALLOW_RETRY because of the FS DAX check requirement on @@ -1767,16 +1751,24 @@ static long __get_user_pages_remote(struct mm_struct *mm, * callers that do request FOLL_LONGTERM, but do not set locked. So, * allow what we can. */ +retry: if (gup_flags & FOLL_LONGTERM) { + long ret; + if (WARN_ON_ONCE(locked)) return -EINVAL; /* * This will check the vmas (even if our vmas arg is NULL) * and return -ENOTSUPP if DAX isn't allowed in this case: */ - return __gup_longterm_locked(mm, start, nr_pages, pages, + ret = __gup_longterm_locked(mm, start, nr_pages, pages, vmas, gup_flags | FOLL_TOUCH | FOLL_REMOTE); + if (ret < 0 && orig_gup_flags != gup_flags) { + gup_flags = orig_gup_flags; + goto retry; + } else + return ret; } return __get_user_pages_locked(mm, start, nr_pages, pages, vmas, @@ -1895,11 +1887,23 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas) { + long ret; + unsigned int orig_gup_flags; + if (!is_valid_gup_flags(gup_flags)) return -EINVAL; - return __gup_longterm_locked(current->mm, start, nr_pages, + orig_gup_flags = gup_flags; + trace_android_vh_get_user_pages(&gup_flags, pages); +retry: + ret = __gup_longterm_locked(current->mm, start, nr_pages, pages, vmas, gup_flags | FOLL_TOUCH); + if (ret < 0 && orig_gup_flags != gup_flags) { + gup_flags = orig_gup_flags; + goto retry; + } + + return ret; } EXPORT_SYMBOL(get_user_pages); @@ -2707,6 +2711,7 @@ static int internal_get_user_pages_fast(unsigned long start, /* Slow path: try to get the remaining pages with get_user_pages */ start += nr_pinned << PAGE_SHIFT; pages += nr_pinned; + trace_android_vh_internal_get_user_pages_fast(&gup_flags, pages); ret = __gup_longterm_unlocked(start, nr_pages - nr_pinned, gup_flags, pages); if (ret < 0) { @@ -2932,6 +2937,7 @@ long pin_user_pages(unsigned long start, unsigned long nr_pages, return -EINVAL; gup_flags |= FOLL_PIN; + trace_android_vh_pin_user_pages(&gup_flags, pages); return __gup_longterm_locked(current->mm, start, nr_pages, pages, vmas, gup_flags); } diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1eea5787fd63940cbac9fe9f67d636c366e6bba2..123f3e03287124be46c3a3d6cfc088e3f026d61b 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2402,7 +2402,8 @@ static void __split_huge_page_tail(struct page *head, int tail, #ifdef CONFIG_64BIT (1L << PG_arch_2) | #endif - (1L << PG_dirty))); + (1L << PG_dirty) | + LRU_GEN_MASK | LRU_REFS_MASK)); /* ->mapping in first tail page is compound_mapcount */ VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c index fad1887e54c05ae3902b8ae54a8aae40c9b49233..9e1b6544bfa8e6263fc6a9db58d68b345692e591 100644 --- a/mm/kasan/hw_tags.c +++ b/mm/kasan/hw_tags.c @@ -172,12 +172,7 @@ void kasan_init_hw_tags_cpu(void) * Enable async or asymm modes only when explicitly requested * through the command line. */ - if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC) - hw_enable_tagging_async(); - else if (kasan_arg_mode == KASAN_ARG_MODE_ASYMM) - hw_enable_tagging_asymm(); - else - hw_enable_tagging_sync(); + kasan_enable_tagging(); } /* kasan_init_hw_tags() is called once on boot CPU. */ @@ -341,13 +336,19 @@ void __kasan_poison_vmalloc(const void *start, unsigned long size) #endif -#if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) - -void kasan_enable_tagging_sync(void) +void kasan_enable_tagging(void) { - hw_enable_tagging_sync(); + if (kasan_arg_mode == KASAN_ARG_MODE_ASYNC) + hw_enable_tagging_async(); + else if (kasan_arg_mode == KASAN_ARG_MODE_ASYMM) + hw_enable_tagging_asymm(); + else + hw_enable_tagging_sync(); } -EXPORT_SYMBOL_GPL(kasan_enable_tagging_sync); + +#if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) + +EXPORT_SYMBOL_GPL(kasan_enable_tagging); void kasan_force_async_fault(void) { diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 3fb9a1e847194dd9e169c6609bb65da17891eafe..e6417aca1ebf05cb98ff9da9a5576f360318d446 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -7,6 +7,16 @@ #include #include +#if IS_ENABLED(CONFIG_KUNIT) + +/* Used in KUnit-compatible KASAN tests. */ +struct kunit_kasan_status { + bool report_found; + bool sync_fault; +}; + +#endif + #ifdef CONFIG_KASAN_HW_TAGS #include @@ -339,25 +349,27 @@ static inline const void *arch_kasan_set_tag(const void *addr, u8 tag) #define hw_set_mem_tag_range(addr, size, tag, init) \ arch_set_mem_tag_range((addr), (size), (tag), (init)) +void kasan_enable_tagging(void); + #else /* CONFIG_KASAN_HW_TAGS */ #define hw_enable_tagging_sync() #define hw_enable_tagging_async() #define hw_enable_tagging_asymm() +static inline void kasan_enable_tagging(void) { } + #endif /* CONFIG_KASAN_HW_TAGS */ #if defined(CONFIG_KASAN_HW_TAGS) && IS_ENABLED(CONFIG_KASAN_KUNIT_TEST) -void kasan_enable_tagging_sync(void); void kasan_force_async_fault(void); -#else /* CONFIG_KASAN_HW_TAGS || CONFIG_KASAN_KUNIT_TEST */ +#else /* CONFIG_KASAN_HW_TAGS && CONFIG_KASAN_KUNIT_TEST */ -static inline void kasan_enable_tagging_sync(void) { } static inline void kasan_force_async_fault(void) { } -#endif /* CONFIG_KASAN_HW_TAGS || CONFIG_KASAN_KUNIT_TEST */ +#endif /* CONFIG_KASAN_HW_TAGS && CONFIG_KASAN_KUNIT_TEST */ #ifdef CONFIG_KASAN_SW_TAGS u8 kasan_random_tag(void); diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 5f22ddfa2d7a1ab5c949e3b8f1be62769e19918b..98c186f9d950348a8fbf1c5d19a5eea09a2d9497 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -344,20 +344,21 @@ static bool report_enabled(void) } #if IS_ENABLED(CONFIG_KUNIT) -static void kasan_update_kunit_status(struct kunit *cur_test) +static void kasan_update_kunit_status(struct kunit *cur_test, bool sync) { struct kunit_resource *resource; - struct kunit_kasan_expectation *kasan_data; + struct kunit_kasan_status *status; - resource = kunit_find_named_resource(cur_test, "kasan_data"); + resource = kunit_find_named_resource(cur_test, "kasan_status"); if (!resource) { kunit_set_failure(cur_test); return; } - kasan_data = (struct kunit_kasan_expectation *)resource->data; - WRITE_ONCE(kasan_data->report_found, true); + status = (struct kunit_kasan_status *)resource->data; + WRITE_ONCE(status->report_found, true); + WRITE_ONCE(status->sync_fault, sync); kunit_put_resource(resource); } #endif /* IS_ENABLED(CONFIG_KUNIT) */ @@ -371,7 +372,7 @@ void kasan_report_invalid_free(void *object, unsigned long ip) #if IS_ENABLED(CONFIG_KUNIT) if (current->kunit_test) - kasan_update_kunit_status(current->kunit_test); + kasan_update_kunit_status(current->kunit_test, true); #endif /* IS_ENABLED(CONFIG_KUNIT) */ start_report(&flags); @@ -391,7 +392,7 @@ void kasan_report_async(void) #if IS_ENABLED(CONFIG_KUNIT) if (current->kunit_test) - kasan_update_kunit_status(current->kunit_test); + kasan_update_kunit_status(current->kunit_test, false); #endif /* IS_ENABLED(CONFIG_KUNIT) */ start_report(&flags); @@ -413,7 +414,7 @@ static void __kasan_report(unsigned long addr, size_t size, bool is_write, #if IS_ENABLED(CONFIG_KUNIT) if (current->kunit_test) - kasan_update_kunit_status(current->kunit_test); + kasan_update_kunit_status(current->kunit_test, true); #endif /* IS_ENABLED(CONFIG_KUNIT) */ disable_trace_on_warning(); diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 47fee6d7d0a57bdf21e12e9aced5c9f3efc943d7..a3438661c777b85f786cd40aa3f6d7fd53f3f1b6 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -484,10 +484,11 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, return (void *)start; /* - * Don't tag executable memory. + * Don't tag executable memory with the tag-based mode. * The kernel doesn't tolerate having the PC register tagged. */ - if (!(flags & KASAN_VMALLOC_PROT_NORMAL)) + if (IS_ENABLED(CONFIG_KASAN_SW_TAGS) && + !(flags & KASAN_VMALLOC_PROT_NORMAL)) return (void *)start; start = set_tag(start, kasan_random_tag()); diff --git a/mm/kmemleak.c b/mm/kmemleak.c index b4867ab7b35aa1a8f2f75ce7172fb64c2fe91917..c8dc0470efa6ded2b55929b3cdedc9b526a420c6 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -795,8 +795,6 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) unsigned long flags; struct kmemleak_object *object; struct kmemleak_scan_area *area = NULL; - unsigned long untagged_ptr; - unsigned long untagged_objp; object = find_and_get_object(ptr, 1); if (!object) { @@ -805,9 +803,6 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) return; } - untagged_ptr = (unsigned long)kasan_reset_tag((void *)ptr); - untagged_objp = (unsigned long)kasan_reset_tag((void *)object->pointer); - if (scan_area_cache) area = kmem_cache_alloc(scan_area_cache, gfp_kmemleak_mask(gfp)); @@ -819,8 +814,8 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) goto out_unlock; } if (size == SIZE_MAX) { - size = untagged_objp + object->size - untagged_ptr; - } else if (untagged_ptr + size > untagged_objp + object->size) { + size = object->pointer + object->size - ptr; + } else if (ptr + size > object->pointer + object->size) { kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); dump_object_info(object); kmem_cache_free(scan_area_cache, area); diff --git a/mm/ksm.c b/mm/ksm.c index e2464c04ede28e487d4c4a61605eb65f4646ed9c..25b8362a4f89537abe7c03156d7407d9a18383c1 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -484,7 +484,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr) NULL); else ret = VM_FAULT_WRITE; - put_user_page(page); + put_page(page); } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM))); /* * We must loop because handle_mm_fault() may back out if there's @@ -569,7 +569,7 @@ static struct page *get_mergeable_page(struct rmap_item *rmap_item) flush_anon_page(vma, page, addr); flush_dcache_page(page); } else { - put_user_page(page); + put_page(page); out: page = NULL; } @@ -1950,7 +1950,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, * Don't substitute a ksm page for a forked page. */ if (page == tree_page) { - put_user_page(tree_page); + put_page(tree_page); return NULL; } @@ -1958,10 +1958,10 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, parent = *new; if (ret < 0) { - put_user_page(tree_page); + put_page(tree_page); new = &parent->rb_left; } else if (ret > 0) { - put_user_page(tree_page); + put_page(tree_page); new = &parent->rb_right; } else if (!ksm_merge_across_nodes && page_to_nid(tree_page) != nid) { @@ -1970,7 +1970,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, * it will be flushed out and put in the right unstable * tree next time: only merge with it when across_nodes. */ - put_user_page(tree_page); + put_page(tree_page); return NULL; } else { *tree_pagep = tree_page; @@ -2151,7 +2151,7 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) */ split = PageTransCompound(page) && compound_head(page) == compound_head(tree_page); - put_user_page(tree_page); + put_page(tree_page); if (kpage) { /* * The pages were successfully merged: insert new @@ -2320,11 +2320,11 @@ next_mm: &rmap_item->rmap_list; ksm_scan.address += PAGE_SIZE; } else - put_user_page(*page); + put_page(*page); mmap_read_unlock(mm); return rmap_item; } - put_user_page(*page); + put_page(*page); ksm_scan.address += PAGE_SIZE; cond_resched(); } diff --git a/mm/madvise.c b/mm/madvise.c index 2b5b2b3f6cbefba4f0af6fbdd43878b3af83aa14..8920a7125389fa41cf1c76c7d5faa1937273e703 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -63,7 +63,7 @@ static int madvise_need_mmap_write(int behavior) } #ifdef CONFIG_ANON_VMA_NAME -static struct anon_vma_name *anon_vma_name_alloc(const char *name) +struct anon_vma_name *anon_vma_name_alloc(const char *name) { struct anon_vma_name *anon_name; size_t count; @@ -79,78 +79,48 @@ static struct anon_vma_name *anon_vma_name_alloc(const char *name) return anon_name; } -static void vma_anon_name_free(struct kref *kref) +void anon_vma_name_free(struct kref *kref) { struct anon_vma_name *anon_name = container_of(kref, struct anon_vma_name, kref); kfree(anon_name); } -static inline bool has_vma_anon_name(struct vm_area_struct *vma) +struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma) { - return !vma->vm_file && vma->anon_name; -} - -const char *vma_anon_name(struct vm_area_struct *vma) -{ - if (!has_vma_anon_name(vma)) - return NULL; - mmap_assert_locked(vma->vm_mm); - return vma->anon_name->name; -} - -void dup_vma_anon_name(struct vm_area_struct *orig_vma, - struct vm_area_struct *new_vma) -{ - if (!has_vma_anon_name(orig_vma)) - return; - - kref_get(&orig_vma->anon_name->kref); - new_vma->anon_name = orig_vma->anon_name; -} - -void free_vma_anon_name(struct vm_area_struct *vma) -{ - struct anon_vma_name *anon_name; - - if (!has_vma_anon_name(vma)) - return; + if (vma->vm_file) + return NULL; - anon_name = vma->anon_name; - vma->anon_name = NULL; - kref_put(&anon_name->kref, vma_anon_name_free); + return vma->anon_name; } /* mmap_lock should be write-locked */ -static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name) +static int replace_anon_vma_name(struct vm_area_struct *vma, + struct anon_vma_name *anon_name) { - const char *anon_name; + struct anon_vma_name *orig_name = anon_vma_name(vma); - if (!name) { - free_vma_anon_name(vma); + if (!anon_name) { + vma->anon_name = NULL; + anon_vma_name_put(orig_name); return 0; } - anon_name = vma_anon_name(vma); - if (anon_name) { - /* Same name, nothing to do here */ - if (!strcmp(name, anon_name)) - return 0; + if (anon_vma_name_eq(orig_name, anon_name)) + return 0; - free_vma_anon_name(vma); - } - vma->anon_name = anon_vma_name_alloc(name); - if (!vma->anon_name) - return -ENOMEM; + vma->anon_name = anon_vma_name_reuse(anon_name); + anon_vma_name_put(orig_name); return 0; } #else /* CONFIG_ANON_VMA_NAME */ -static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name) +static int replace_anon_vma_name(struct vm_area_struct *vma, + struct anon_vma_name *anon_name) { - if (name) + if (anon_name) return -EINVAL; return 0; @@ -159,17 +129,19 @@ static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name) /* * Update the vm_flags on region of a vma, splitting it or merging it as * necessary. Must be called with mmap_sem held for writing; + * Caller should ensure anon_name stability by raising its refcount even when + * anon_name belongs to a valid vma because this function might free that vma. */ static int madvise_update_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end, unsigned long new_flags, - const char *name) + struct anon_vma_name *anon_name) { struct mm_struct *mm = vma->vm_mm; int error; pgoff_t pgoff; - if (new_flags == vma->vm_flags && is_same_vma_anon_name(vma, name)) { + if (new_flags == vma->vm_flags && anon_vma_name_eq(anon_vma_name(vma), anon_name)) { *prev = vma; return 0; } @@ -177,7 +149,7 @@ static int madvise_update_vma(struct vm_area_struct *vma, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - vma->vm_userfaultfd_ctx, name); + vma->vm_userfaultfd_ctx, anon_name); if (*prev) { vma = *prev; goto success; @@ -209,7 +181,7 @@ success: WRITE_ONCE(vma->vm_flags, new_flags); vm_write_end(vma); if (!vma->vm_file) { - error = replace_vma_anon_name(vma, name); + error = replace_anon_vma_name(vma, anon_name); if (error) return error; } @@ -923,6 +895,7 @@ static int madvise_vma_behavior(struct vm_area_struct *vma, unsigned long behavior) { int error; + struct anon_vma_name *anon_name; unsigned long new_flags = vma->vm_flags; switch (behavior) { @@ -985,8 +958,11 @@ static int madvise_vma_behavior(struct vm_area_struct *vma, break; } + anon_name = anon_vma_name(vma); + anon_vma_name_get(anon_name); error = madvise_update_vma(vma, prev, start, end, new_flags, - vma_anon_name(vma)); + anon_name); + anon_vma_name_put(anon_name); out: /* @@ -1172,7 +1148,7 @@ int madvise_walk_vmas(struct mm_struct *mm, unsigned long start, static int madvise_vma_anon_name(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end, - unsigned long name) + unsigned long anon_name) { int error; @@ -1181,7 +1157,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma, return -EBADF; error = madvise_update_vma(vma, prev, start, end, vma->vm_flags, - (const char *)name); + (struct anon_vma_name *)anon_name); /* * madvise() returns EAGAIN if kernel resources, such as @@ -1193,7 +1169,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma, } int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, - unsigned long len_in, const char *name) + unsigned long len_in, struct anon_vma_name *anon_name) { unsigned long end; unsigned long len; @@ -1213,7 +1189,7 @@ int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, if (end == start) return 0; - return madvise_walk_vmas(mm, start, end, (unsigned long)name, + return madvise_walk_vmas(mm, start, end, (unsigned long)anon_name, madvise_vma_anon_name); } #endif /* CONFIG_ANON_VMA_NAME */ diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 008e72c2b9805476094cbe78f9a09732c1516ad0..eed533d29bd77d28032fc611f7910a5e2fe6c752 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2883,6 +2883,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg) * - LRU isolation * - lock_page_memcg() * - exclusive reference + * - mem_cgroup_trylock_pages() */ page->mem_cgroup = memcg; } @@ -5254,6 +5255,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) static void mem_cgroup_free(struct mem_cgroup *memcg) { + lru_gen_exit_memcg(memcg); memcg_wb_domain_exit(memcg); /* * Flush percpu vmstats and vmevents to guarantee the value correctness @@ -5329,6 +5331,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) #endif idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); trace_android_vh_mem_cgroup_alloc(memcg); + lru_gen_init_memcg(memcg); return memcg; fail: mem_cgroup_id_remove(memcg); @@ -6223,6 +6226,29 @@ static void mem_cgroup_move_task(void) } #endif +#ifdef CONFIG_LRU_GEN +static void mem_cgroup_attach(struct cgroup_taskset *tset) +{ + struct cgroup_subsys_state *css; + struct task_struct *task = NULL; + + cgroup_taskset_for_each_leader(task, css, tset) + break; + + if (!task) + return; + + task_lock(task); + if (task->mm && task->mm->owner == task) + lru_gen_migrate_mm(task->mm); + task_unlock(task); +} +#else +static void mem_cgroup_attach(struct cgroup_taskset *tset) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * Cgroup retains root cgroups across [un]mount cycles making it necessary * to verify whether we're attached to the default hierarchy on each mount @@ -6575,6 +6601,7 @@ struct cgroup_subsys memory_cgrp_subsys = { .css_free = mem_cgroup_css_free, .css_reset = mem_cgroup_css_reset, .can_attach = mem_cgroup_can_attach, + .attach = mem_cgroup_attach, .cancel_attach = mem_cgroup_cancel_attach, .post_attach = mem_cgroup_move_task, .bind = mem_cgroup_bind, @@ -7123,7 +7150,7 @@ static int __init cgroup_memory(char *s) if (!strcmp(token, "nokmem")) cgroup_memory_nokmem = true; } - return 1; + return 0; } __setup("cgroup.memory=", cgroup_memory); diff --git a/mm/memory.c b/mm/memory.c index 7261bfd5c5375750099e460491493d1b16fe1a7a..a038d72a8110600b59722f62cbb4d85d49dad7cf 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -126,18 +126,6 @@ int randomize_va_space __read_mostly = 2; #endif -#ifndef arch_faults_on_old_pte -static inline bool arch_faults_on_old_pte(void) -{ - /* - * Those arches which don't have hw access flag feature need to - * implement their own helper. By default, "true" means pagefault - * will be hit on old pte. - */ - return true; -} -#endif - #ifndef arch_wants_old_prefaulted_pte static inline bool arch_wants_old_prefaulted_pte(void) { @@ -2880,7 +2868,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src, * On architectures with software "accessed" bits, we would * take a double page fault, so mark it accessed here. */ - if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) { + if (!arch_has_hw_pte_young() && !pte_young(vmf->orig_pte)) { pte_t entry; vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); @@ -3612,7 +3600,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) if (data_race(si->flags & SWP_SYNCHRONOUS_IO) && __swap_count(entry) == 1) { /* skip swapcache */ - gfp_t flags = GFP_HIGHUSER_MOVABLE; + gfp_t flags = GFP_HIGHUSER_MOVABLE | __GFP_CMA; trace_android_rvh_set_skip_swapcache_flags(&flags); page = alloc_page_vma(flags, vma, vmf->address); @@ -3652,7 +3640,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) ret = VM_FAULT_RETRY; goto out; } else { - page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, + page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE | __GFP_CMA, vmf); swapcache = page; } @@ -3982,20 +3970,11 @@ static vm_fault_t __do_fault(struct vm_fault *vmf) return ret; if (unlikely(PageHWPoison(vmf->page))) { - struct page *page = vmf->page; - vm_fault_t poisonret = VM_FAULT_HWPOISON; - if (ret & VM_FAULT_LOCKED) { - if (page_mapped(page)) - unmap_mapping_pages(page_mapping(page), - page->index, 1, false); - /* Retry if a clean page was removed from the cache. */ - if (invalidate_inode_page(page)) - poisonret = VM_FAULT_NOPAGE; - unlock_page(page); - } - put_page(page); + if (ret & VM_FAULT_LOCKED) + unlock_page(vmf->page); + put_page(vmf->page); vmf->page = NULL; - return poisonret; + return VM_FAULT_HWPOISON; } if (unlikely(!(ret & VM_FAULT_LOCKED))) @@ -4913,6 +4892,10 @@ static inline void mm_account_fault(struct pt_regs *regs, else perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); } + +static void lru_gen_enter_fault(struct vm_area_struct *vma); +static void lru_gen_exit_fault(void); + #ifdef CONFIG_SPECULATIVE_PAGE_FAULT #ifndef CONFIG_ARCH_HAS_PTE_SPECIAL @@ -5104,7 +5087,9 @@ static vm_fault_t ___handle_speculative_fault(struct mm_struct *mm, } mem_cgroup_enter_user_fault(); + lru_gen_enter_fault(vmf.vma); ret = handle_pte_fault(&vmf); + lru_gen_exit_fault(); mem_cgroup_exit_user_fault(); if (ret != VM_FAULT_RETRY) { @@ -5180,6 +5165,27 @@ bool can_reuse_spf_vma(struct vm_area_struct *vma, unsigned long address) } #endif /* CONFIG_SPECULATIVE_PAGE_FAULT */ +#ifdef CONFIG_LRU_GEN +static void lru_gen_enter_fault(struct vm_area_struct *vma) +{ + /* the LRU algorithm doesn't apply to sequential or random reads */ + current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); +} + +static void lru_gen_exit_fault(void) +{ + current->in_lru_fault = false; +} +#else +static void lru_gen_enter_fault(struct vm_area_struct *vma) +{ +} + +static void lru_gen_exit_fault(void) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * By the time we get here, we already hold the mm semaphore * @@ -5211,11 +5217,15 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, if (flags & FAULT_FLAG_USER) mem_cgroup_enter_user_fault(); + lru_gen_enter_fault(vma); + if (unlikely(is_vm_hugetlb_page(vma))) ret = hugetlb_fault(vma->vm_mm, vma, address, flags); else ret = __handle_mm_fault(vma, address, flags); + lru_gen_exit_fault(); + if (flags & FAULT_FLAG_USER) { mem_cgroup_exit_user_fault(); /* @@ -5544,7 +5554,7 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, buf, maddr + offset, bytes); } kunmap(page); - put_user_page(page); + put_page(page); } len -= bytes; buf += bytes; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 1ae78937af424116f40f3bbb82ed3072b63eff29..3b2584088d2813a6da00857a9867b070b2b2b5b7 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -814,6 +814,7 @@ static int vma_replace_policy(struct vm_area_struct *vma, static int mbind_range(struct mm_struct *mm, unsigned long start, unsigned long end, struct mempolicy *new_pol) { + struct vm_area_struct *next; struct vm_area_struct *prev; struct vm_area_struct *vma; int err = 0; @@ -828,7 +829,8 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (start > vma->vm_start) prev = vma; - for (; vma && vma->vm_start < end; prev = vma, vma = vma->vm_next) { + for (; vma && vma->vm_start < end; prev = vma, vma = next) { + next = vma->vm_next; vmstart = max(start, vma->vm_start); vmend = min(end, vma->vm_end); @@ -840,9 +842,13 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, vma->anon_vma, vma->vm_file, pgoff, new_pol, vma->vm_userfaultfd_ctx, - vma_anon_name(vma)); + anon_vma_name(vma)); if (prev) { vma = prev; + next = vma->vm_next; + if (mpol_equal(vma_policy(vma), new_pol)) + continue; + /* vma_merge() joined vma && vma->next, case 8 */ goto replace; } if (vma->vm_start != vmstart) { diff --git a/mm/migrate.c b/mm/migrate.c index 26f8595de076c941d8cecdd49878e946b0afb030..4d25efd7fca47dec6bf1633141ba3d9e3b71d5b2 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1655,7 +1655,7 @@ out_putpage: * isolate_lru_page() or drop the page ref if it was * not isolated. */ - put_user_page(page); + put_page(page); out: mmap_read_unlock(mm); return err; diff --git a/mm/mlock.c b/mm/mlock.c index a90b46d863346e634fcfe7d38fe461f6fc829a6a..49fe3d9ca2846e6178540057a9c4e0b17ff4ecfa 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -119,7 +119,7 @@ static bool __munlock_isolate_lru_page(struct page *page, bool getpage) if (getpage) get_page(page); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); return true; } @@ -472,14 +472,6 @@ void munlock_vma_pages_range(struct vm_area_struct *vma, */ page = follow_page(vma, start, FOLL_GET | FOLL_DUMP); if (page && !IS_ERR(page)) { - /* - * munlock_vma_pages_range uses follow_page(FOLL_GET) - * so it need to use put_user_page but the munlock - * path is quite complicated to deal with each put - * sites correctly so just unattribute them to avoid - * false positive at this moment. - */ - reset_page_pinner(page, compound_order(page)); if (PageTransTail(page)) { VM_BUG_ON_PAGE(PageMlocked(page), page); put_page(page); /* follow_page_mask() */ @@ -550,7 +542,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - vma->vm_userfaultfd_ctx, vma_anon_name(vma)); + vma->vm_userfaultfd_ctx, anon_vma_name(vma)); if (*prev) { vma = *prev; goto success; diff --git a/mm/mm_init.c b/mm/mm_init.c index b06a30fbedff7f3432ffe4ef82f23ed213d54d14..9351e8a25a80ddf9477e216947b7414a08973c93 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -19,10 +19,6 @@ #ifdef CONFIG_DEBUG_MEMORY_INIT int __meminitdata mminit_loglevel; -#ifndef SECTIONS_SHIFT -#define SECTIONS_SHIFT 0 -#endif - /* The zonelists are simply reported, validation is manual. */ void __init mminit_verify_zonelist(void) { @@ -69,14 +65,16 @@ void __init mminit_verify_pageflags_layout(void) shift = 8 * sizeof(unsigned long); width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH - - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH; + - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", - "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Flags %d\n", + "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", SECTIONS_WIDTH, NODES_WIDTH, ZONES_WIDTH, LAST_CPUPID_WIDTH, KASAN_TAG_WIDTH, + LRU_GEN_WIDTH, + LRU_REFS_WIDTH, NR_PAGEFLAGS); mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", diff --git a/mm/mmap.c b/mm/mmap.c index bfdecbb21bb2e92ba3d61b8a6bb980250798cb85..cb5fded3aa0b41b9f19f107399f794d233bf7277 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1084,7 +1084,7 @@ again: static inline int is_mergeable_vma(struct vm_area_struct *vma, struct file *file, unsigned long vm_flags, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name) + struct anon_vma_name *anon_name) { /* * VM_SOFTDIRTY should not prevent from VMA merging, if we @@ -1102,7 +1102,7 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma, return 0; if (!is_mergeable_vm_userfaultfd_ctx(vma, vm_userfaultfd_ctx)) return 0; - if (!is_same_vma_anon_name(vma, anon_name)) + if (!anon_vma_name_eq(anon_vma_name(vma), anon_name)) return 0; return 1; } @@ -1137,7 +1137,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name) + struct anon_vma_name *anon_name) { if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { @@ -1159,7 +1159,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name) + struct anon_vma_name *anon_name) { if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { @@ -1220,7 +1220,7 @@ struct vm_area_struct *__vma_merge(struct mm_struct *mm, struct anon_vma *anon_vma, struct file *file, pgoff_t pgoff, struct mempolicy *policy, struct vm_userfaultfd_ctx vm_userfaultfd_ctx, - const char *anon_name, bool keep_locked) + struct anon_vma_name *anon_name, bool keep_locked) { pgoff_t pglen = (end - addr) >> PAGE_SHIFT; struct vm_area_struct *area, *next; @@ -2676,7 +2676,7 @@ static int __init cmdline_parse_stack_guard_gap(char *p) if (!*endptr) stack_guard_gap = val << PAGE_SHIFT; - return 1; + return 0; } __setup("stack_guard_gap=", cmdline_parse_stack_guard_gap); @@ -3410,7 +3410,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, new_vma = __vma_merge(mm, prev, addr, addr + len, vma->vm_flags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), vma->vm_userfaultfd_ctx, - vma_anon_name(vma), true); + anon_vma_name(vma), true); if (new_vma) { /* * Source vma may have been merged into new_vma diff --git a/mm/mmzone.c b/mm/mmzone.c index 2241281ffe1677289a553eec5cbc7c21f769fdc9..1470eea5454aee86616a0788bccc740a39501fe8 100644 --- a/mm/mmzone.c +++ b/mm/mmzone.c @@ -96,6 +96,8 @@ void lruvec_init(struct lruvec *lruvec) for_each_lru(lru) INIT_LIST_HEAD(&lruvec->lists[lru]); + + lru_gen_init_lruvec(lruvec); } #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) diff --git a/mm/mprotect.c b/mm/mprotect.c index 02886b66171987ba3d0c47a86e00677ab7553346..b7f744ce029537ff84577bb6146a1c5469e6fefa 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -454,7 +454,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *pprev = vma_merge(mm, *pprev, start, end, newflags, vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), - vma->vm_userfaultfd_ctx, vma_anon_name(vma)); + vma->vm_userfaultfd_ctx, anon_vma_name(vma)); if (*pprev) { vma = *pprev; VM_WARN_ON((vma->vm_flags ^ newflags) & ~VM_SOFTDIRTY); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a3a877d804040eec93bf4a54cb33c735a3dccb19..757cb85124b038a1078e1504bf657d4b77cde291 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -83,6 +83,18 @@ /* Free Page Internal flags: for internal, non-pcp variants of free_pages(). */ typedef int __bitwise fpi_t; +static inline struct per_cpu_pageset_ext *pcp_to_pageset_ext(struct per_cpu_pages *pcp) +{ + struct per_cpu_pageset *ps = container_of(pcp, struct per_cpu_pageset, pcp); + + return container_of(ps, struct per_cpu_pageset_ext, pageset); +} + +static inline struct per_cpu_pageset_ext *pageset_to_pageset_ext(struct per_cpu_pageset *ps) +{ + return container_of(ps, struct per_cpu_pageset_ext, pageset); +} + /* No special request */ #define FPI_NONE ((__force fpi_t)0) @@ -123,6 +135,20 @@ typedef int __bitwise fpi_t; static DEFINE_MUTEX(pcp_batch_high_lock); #define MIN_PERCPU_PAGELIST_FRACTION (8) +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) +/* + * On SMP, spin_trylock is sufficient protection. + * On PREEMPT_RT, spin_trylock is equivalent on both SMP and UP. + */ +#define pcp_trylock_prepare(flags) do { } while (0) +#define pcp_trylock_finish(flag) do { } while (0) +#else + +/* UP spin_trylock always succeeds so disable IRQs to prevent re-entrancy. */ +#define pcp_trylock_prepare(flags) local_irq_save(flags) +#define pcp_trylock_finish(flags) local_irq_restore(flags) +#endif + #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID DEFINE_PER_CPU(int, numa_node); EXPORT_PER_CPU_SYMBOL(numa_node); @@ -141,13 +167,7 @@ DEFINE_PER_CPU(int, _numa_mem_); /* Kernel "local memory" node */ EXPORT_PER_CPU_SYMBOL(_numa_mem_); #endif -/* work_structs for global per-cpu drains */ -struct pcpu_drain { - struct zone *zone; - struct work_struct work; -}; static DEFINE_MUTEX(pcpu_drain_mutex); -static DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain); #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY volatile unsigned long latent_entropy __latent_entropy; @@ -1509,13 +1529,15 @@ static void free_one_page(struct zone *zone, unsigned int order, int migratetype, fpi_t fpi_flags) { - spin_lock(&zone->lock); + unsigned long flags; + + spin_lock_irqsave(&zone->lock, flags); if (unlikely(has_isolate_pageblock(zone) || is_migrate_isolate(migratetype))) { migratetype = get_pfnblock_migratetype(page, pfn); } __free_one_page(page, pfn, zone, order, migratetype, fpi_flags); - spin_unlock(&zone->lock); + spin_unlock_irqrestore(&zone->lock, flags); } static void __meminit __init_single_page(struct page *page, unsigned long pfn, @@ -3104,52 +3126,54 @@ static struct list_head *get_populated_pcp_list(struct zone *zone, * Called from the vmstat counter updater to drain pagesets of this * currently executing processor on remote nodes after they have * expired. - * - * Note that this function must be called with the thread pinned to - * a single processor. */ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) { - unsigned long flags; int to_drain, batch; - local_irq_save(flags); batch = READ_ONCE(pcp->batch); to_drain = min(pcp->count, batch); - if (to_drain > 0) + if (to_drain > 0) { + unsigned long flags; + struct per_cpu_pageset_ext *ps_ext = pcp_to_pageset_ext(pcp); + + /* + * free_pcppages_bulk expects IRQs disabled for zone->lock + * so even though pcp->lock is not intended to be IRQ-safe, + * it's needed in this context. + */ + spin_lock_irqsave(&ps_ext->lock, flags); free_pcppages_bulk(zone, to_drain, pcp); - local_irq_restore(flags); + spin_unlock_irqrestore(&ps_ext->lock, flags); + } } #endif /* * Drain pcplists of the indicated processor and zone. - * - * The processor must either be the current processor and the - * thread pinned to the current processor or a processor that - * is not online. */ static void drain_pages_zone(unsigned int cpu, struct zone *zone) { - unsigned long flags; struct per_cpu_pageset *pset; + struct per_cpu_pageset_ext *ps_ext; struct per_cpu_pages *pcp; - local_irq_save(flags); pset = per_cpu_ptr(zone->pageset, cpu); + ps_ext = pageset_to_pageset_ext(pset); pcp = &pset->pcp; - if (pcp->count) + if (pcp->count) { + unsigned long flags; + + /* See drain_zone_pages on why this is disabling IRQs */ + spin_lock_irqsave(&ps_ext->lock, flags); free_pcppages_bulk(zone, pcp->count, pcp); - local_irq_restore(flags); + spin_unlock_irqrestore(&ps_ext->lock, flags); + } } /* * Drain pcplists of all zones on the indicated processor. - * - * The processor must either be the current processor and the - * thread pinned to the current processor or a processor that - * is not online. */ static void drain_pages(unsigned int cpu) { @@ -3162,9 +3186,6 @@ static void drain_pages(unsigned int cpu) /* * Spill all of this CPU's per-cpu pages back into the buddy allocator. - * - * The CPU has to be pinned. When zone parameter is non-NULL, spill just - * the single zone's pages. */ void drain_local_pages(struct zone *zone) { @@ -3176,30 +3197,10 @@ void drain_local_pages(struct zone *zone) drain_pages(cpu); } -static void drain_local_pages_wq(struct work_struct *work) -{ - struct pcpu_drain *drain; - - drain = container_of(work, struct pcpu_drain, work); - - /* - * drain_all_pages doesn't use proper cpu hotplug protection so - * we can race with cpu offline when the WQ can move this from - * a cpu pinned worker to an unbound one. We can operate on a different - * cpu which is allright but we also have to make sure to not move to - * a different one. - */ - preempt_disable(); - drain_local_pages(drain->zone); - preempt_enable(); -} - /* * Spill all the per-cpu pages from all CPUs back into the buddy allocator. * * When zone parameter is non-NULL, spill just the single zone's pages. - * - * Note that this can be extremely slow as the draining happens in a workqueue. */ void drain_all_pages(struct zone *zone) { @@ -3211,13 +3212,6 @@ void drain_all_pages(struct zone *zone) */ static cpumask_t cpus_with_pcps; - /* - * Make sure nobody triggers this path before mm_percpu_wq is fully - * initialized. - */ - if (WARN_ON_ONCE(!mm_percpu_wq)) - return; - /* * Do not drain if one is already in progress unless it's specific to * a zone. Such callers are primarily CMA and memory hotplug and need @@ -3261,14 +3255,12 @@ void drain_all_pages(struct zone *zone) } for_each_cpu(cpu, &cpus_with_pcps) { - struct pcpu_drain *drain = per_cpu_ptr(&pcpu_drain, cpu); - - drain->zone = zone; - INIT_WORK(&drain->work, drain_local_pages_wq); - queue_work_on(cpu, mm_percpu_wq, &drain->work); + if (zone) { + drain_pages_zone(cpu, zone); + } else { + drain_pages(cpu); + } } - for_each_cpu(cpu, &cpus_with_pcps) - flush_work(&per_cpu_ptr(&pcpu_drain, cpu)->work); mutex_unlock(&pcpu_drain_mutex); } @@ -3340,38 +3332,41 @@ static bool free_unref_page_prepare(struct page *page, unsigned long pfn) return true; } -static void free_unref_page_commit(struct page *page, unsigned long pfn) +/* Returns true if the page was committed to the per-cpu list. */ +static bool free_unref_page_commit(struct page *page, int migratetype, + bool locked) { struct zone *zone = page_zone(page); struct per_cpu_pages *pcp; - int migratetype; + struct per_cpu_pageset_ext *ps_ext; + unsigned long __maybe_unused UP_flags; - migratetype = get_pcppage_migratetype(page); __count_vm_event(PGFREE); + pcp = &this_cpu_ptr(zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); - /* - * We only track unmovable, reclaimable and movable on pcp lists. - * Free ISOLATE pages back to the allocator because they are being - * offlined but treat HIGHATOMIC as movable pages so we can get those - * areas back if necessary. Otherwise, we may have to free - * excessively into the page allocator - */ - if (migratetype >= MIGRATE_PCPTYPES) { - if (unlikely(is_migrate_isolate(migratetype))) { - free_one_page(zone, page, pfn, 0, migratetype, - FPI_NONE); - return; + if (!locked) { + /* Protect against a parallel drain. */ + pcp_trylock_prepare(UP_flags); + if (!spin_trylock(&ps_ext->lock)) { + pcp_trylock_finish(UP_flags); + return false; } - migratetype = MIGRATE_MOVABLE; } - pcp = &this_cpu_ptr(zone->pageset)->pcp; list_add(&page->lru, &pcp->lists[migratetype]); pcp->count++; if (pcp->count >= pcp->high) { unsigned long batch = READ_ONCE(pcp->batch); free_pcppages_bulk(zone, batch, pcp); } + + if (!locked) { + spin_unlock(&ps_ext->lock); + pcp_trylock_finish(UP_flags); + } + + return true; } /* @@ -3381,13 +3376,36 @@ void free_unref_page(struct page *page) { unsigned long flags; unsigned long pfn = page_to_pfn(page); + int migratetype; + bool freed_pcp = false; if (!free_unref_page_prepare(page, pfn)) return; + /* + * We only track unmovable, reclaimable, movable and cma on pcp lists. + * Place ISOLATE pages on the isolated list because they are being + * offlined but treat HIGHATOMIC as movable pages so we can get those + * areas back if necessary. Otherwise, we may have to free + * excessively into the page allocator + */ + migratetype = get_pcppage_migratetype(page); + if (unlikely(migratetype > MIGRATE_RECLAIMABLE)) { + if (unlikely(is_migrate_isolate(migratetype))) { + free_one_page(page_zone(page), page, pfn, 0, migratetype, FPI_NONE); + return; + } + if (migratetype == MIGRATE_HIGHATOMIC) + migratetype = MIGRATE_MOVABLE; + } + local_irq_save(flags); - free_unref_page_commit(page, pfn); + freed_pcp = free_unref_page_commit(page, migratetype, false); local_irq_restore(flags); + + if (unlikely(!freed_pcp)) + free_one_page(page_zone(page), page, pfn, 0, migratetype, + FPI_NONE); } /* @@ -3396,35 +3414,107 @@ void free_unref_page(struct page *page) void free_unref_page_list(struct list_head *list) { struct page *page, *next; - unsigned long flags, pfn; + struct per_cpu_pageset_ext *ps_ext; + struct per_cpu_pages *pcp; + struct zone *locked_zone; + unsigned long flags; int batch_count = 0; + int migratetype; + + /* + * An empty list is possible. Check early so that the later + * lru_to_page() does not potentially read garbage. + */ + if (list_empty(list)) + return; /* Prepare pages for freeing */ list_for_each_entry_safe(page, next, list, lru) { - pfn = page_to_pfn(page); - if (!free_unref_page_prepare(page, pfn)) + unsigned long pfn = page_to_pfn(page); + if (!free_unref_page_prepare(page, pfn)) { list_del(&page->lru); - set_page_private(page, pfn); + continue; + } + + /* + * Free isolated pages directly to the allocator, see + * comment in free_unref_page. + */ + migratetype = get_pcppage_migratetype(page); + if (unlikely(migratetype > MIGRATE_RECLAIMABLE)) { + if (unlikely(is_migrate_isolate(migratetype))) { + list_del(&page->lru); + free_one_page(page_zone(page), page, pfn, 0, + migratetype, FPI_NONE); + continue; + } + + /* + * Non-isolated types over MIGRATE_RECLAIMABLE get added + * to the MIGRATE_MOVABLE pcp list. + */ + if (migratetype == MIGRATE_HIGHATOMIC) + set_pcppage_migratetype(page, MIGRATE_MOVABLE); + } } + /* + * Preparation could have drained the list due to failing to prepare + * or all pages are being isolated. + */ + if (list_empty(list)) + return; + + VM_BUG_ON(in_irq()); + local_irq_save(flags); + + page = lru_to_page(list); + locked_zone = page_zone(page); + pcp = &this_cpu_ptr(locked_zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); + spin_lock(&ps_ext->lock); + list_for_each_entry_safe(page, next, list, lru) { - unsigned long pfn = page_private(page); + struct zone *zone = page_zone(page); - set_page_private(page, 0); + /* Different zone, different pcp lock. */ + if (zone != locked_zone) { + spin_unlock(&ps_ext->lock); + locked_zone = zone; + pcp = &this_cpu_ptr(zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); + spin_lock(&ps_ext->lock); + } + + migratetype = get_pcppage_migratetype(page); trace_mm_page_free_batched(page); - free_unref_page_commit(page, pfn); + + /* + * If there is a parallel drain in progress, free to the buddy + * allocator directly. This is expensive as the zone lock will + * be acquired multiple times but if a drain is in progress + * then an expensive operation is already taking place. + */ + if (!free_unref_page_commit(page, migratetype, true)) + free_one_page(page_zone(page), page, page_to_pfn(page), + 0, migratetype, FPI_NONE); /* * Guard against excessive IRQ disabled times when we get * a large list of pages to free. */ if (++batch_count == SWAP_CLUSTER_MAX) { + spin_unlock(&ps_ext->lock); local_irq_restore(flags); batch_count = 0; local_irq_save(flags); + pcp = &this_cpu_ptr(locked_zone->pageset)->pcp; + ps_ext = pcp_to_pageset_ext(pcp); + spin_lock(&ps_ext->lock); } } + spin_unlock(&ps_ext->lock); local_irq_restore(flags); } @@ -3546,14 +3636,79 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z) #endif } +static __always_inline +struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone, + unsigned int order, unsigned int alloc_flags, + int migratetype) +{ + struct page *page; + unsigned long flags; + + do { + page = NULL; + spin_lock_irqsave(&zone->lock, flags); + /* + * order-0 request can reach here when the pcplist is skipped + * due to non-CMA allocation context. HIGHATOMIC area is + * reserved for high-order atomic allocation, so order-0 + * request should skip it. + */ + if (order > 0 && alloc_flags & ALLOC_HARDER) { + page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); + if (page) + trace_mm_page_alloc_zone_locked(page, order, migratetype); + } + if (!page) { + if (migratetype == MIGRATE_MOVABLE && + alloc_flags & ALLOC_CMA) + page = __rmqueue_cma(zone, order, migratetype, + alloc_flags); + if (!page) + page = __rmqueue(zone, order, migratetype, + alloc_flags); + } + if (!page) { + spin_unlock_irqrestore(&zone->lock, flags); + return NULL; + } + + __mod_zone_freepage_state(zone, -(1 << order), + get_pcppage_migratetype(page)); + spin_unlock_irqrestore(&zone->lock, flags); + } while (check_new_pages(page, order)); + + __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); + zone_statistics(preferred_zone, zone); + + return page; +} + /* Remove page from the per-cpu list, caller must protect the list */ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, unsigned int alloc_flags, struct per_cpu_pages *pcp, - gfp_t gfp_flags) + gfp_t gfp_flags, bool locked) { struct page *page = NULL; + unsigned long __maybe_unused UP_flags; struct list_head *list = NULL; + struct per_cpu_pageset_ext *ps_ext = pcp_to_pageset_ext(pcp); + + /* + * spin_trylock is not necessary right now due to due to + * local_lock_irqsave and is a preparation step for + * a conversion to local_lock using the trylock to prevent + * IRQ re-entrancy. If pcp->lock cannot be acquired, the caller + * uses rmqueue_buddy. + * TODO: Convert local_lock_irqsave to local_lock. + */ + if (unlikely(!locked)) { + pcp_trylock_prepare(UP_flags); + if (!spin_trylock(&ps_ext->lock)) { + pcp_trylock_finish(UP_flags); + return NULL; + } + } do { /* First try to get CMA pages */ @@ -3571,8 +3726,10 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, list = get_populated_pcp_list(zone, 0, pcp, migratetype, alloc_flags); if (unlikely(list == NULL) || - unlikely(list_empty(list))) - return NULL; + unlikely(list_empty(list))) { + page = NULL; + goto out; + } } page = list_first_entry(list, struct page, lru); @@ -3580,6 +3737,12 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype, pcp->count--; } while (check_new_pcp(page)); +out: + if (!locked) { + spin_unlock(&ps_ext->lock); + pcp_trylock_finish(UP_flags); + } + return page; } @@ -3595,7 +3758,7 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone, local_irq_save(flags); pcp = &this_cpu_ptr(zone->pageset)->pcp; page = __rmqueue_pcplist(zone, migratetype, alloc_flags, pcp, - gfp_flags); + gfp_flags, false); if (page) { __count_zid_vm_events(PGALLOC, page_zonenum(page), 1); zone_statistics(preferred_zone, zone); @@ -3613,13 +3776,13 @@ struct page *rmqueue(struct zone *preferred_zone, gfp_t gfp_flags, unsigned int alloc_flags, int migratetype) { - unsigned long flags; struct page *page; if (likely(order == 0)) { page = rmqueue_pcplist(preferred_zone, zone, gfp_flags, migratetype, alloc_flags); - goto out; + if (page) + goto out; } /* @@ -3627,42 +3790,14 @@ struct page *rmqueue(struct zone *preferred_zone, * allocate greater than order-1 page units with __GFP_NOFAIL. */ WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1)); - spin_lock_irqsave(&zone->lock, flags); - do { - page = NULL; - /* - * order-0 request can reach here when the pcplist is skipped - * due to non-CMA allocation context. HIGHATOMIC area is - * reserved for high-order atomic allocation, so order-0 - * request should skip it. - */ - if (order > 0 && alloc_flags & ALLOC_HARDER) { - page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); - if (page) - trace_mm_page_alloc_zone_locked(page, order, migratetype); - } - if (!page) { - if (migratetype == MIGRATE_MOVABLE && - alloc_flags & ALLOC_CMA) - page = __rmqueue_cma(zone, order, migratetype, - alloc_flags); - if (!page) - page = __rmqueue(zone, order, migratetype, - alloc_flags); - } - } while (page && check_new_pages(page, order)); - spin_unlock(&zone->lock); - if (!page) - goto failed; - __mod_zone_freepage_state(zone, -(1 << order), - get_pcppage_migratetype(page)); + page = rmqueue_buddy(preferred_zone, zone, order, alloc_flags, + migratetype); + if (unlikely(!page)) + return NULL; - __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); - zone_statistics(preferred_zone, zone); trace_android_vh_rmqueue(preferred_zone, zone, order, gfp_flags, alloc_flags, migratetype); - local_irq_restore(flags); out: /* Separate test+clear to avoid unnecessary atomics */ @@ -3673,10 +3808,6 @@ out: VM_BUG_ON_PAGE(page && bad_range(zone, page), page); return page; - -failed: - local_irq_restore(flags); - return NULL; } #ifdef CONFIG_FAIL_PAGE_ALLOC @@ -6113,7 +6244,7 @@ static void build_zonelists(pg_data_t *pgdat) * Other parts of the kernel may not check if the zone is available. */ static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch); -static DEFINE_PER_CPU(struct per_cpu_pageset, boot_pageset); +static DEFINE_PER_CPU(struct per_cpu_pageset_ext, boot_pageset); static DEFINE_PER_CPU(struct per_cpu_nodestat, boot_nodestats); static void __build_all_zonelists(void *data) @@ -6180,7 +6311,7 @@ build_all_zonelists_init(void) * (a chicken-egg dilemma). */ for_each_possible_cpu(cpu) - setup_pageset(&per_cpu(boot_pageset, cpu), 0); + setup_pageset(&per_cpu(boot_pageset, cpu).pageset, 0); mminit_verify_zonelist(); cpuset_init_current_mems_allowed(); @@ -6599,11 +6730,14 @@ static void pageset_set_batch(struct per_cpu_pageset *p, unsigned long batch) static void pageset_init(struct per_cpu_pageset *p) { struct per_cpu_pages *pcp; + struct per_cpu_pageset_ext *ps_ext; int migratetype; memset(p, 0, sizeof(*p)); + ps_ext = pageset_to_pageset_ext(p); pcp = &p->pcp; + spin_lock_init(&ps_ext->lock); for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++) INIT_LIST_HEAD(&pcp->lists[migratetype]); } @@ -6650,7 +6784,10 @@ static void __meminit zone_pageset_init(struct zone *zone, int cpu) void __meminit setup_zone_pageset(struct zone *zone) { int cpu; - zone->pageset = alloc_percpu(struct per_cpu_pageset); + struct per_cpu_pageset_ext *ps_ext; + + ps_ext = alloc_percpu(struct per_cpu_pageset_ext); + zone->pageset = &ps_ext->pageset; for_each_possible_cpu(cpu) zone_pageset_init(zone, cpu); } @@ -6676,7 +6813,7 @@ void __init setup_per_cpu_pageset(void) * the nodes these zones are associated with. */ for_each_possible_cpu(cpu) { - struct per_cpu_pageset *pcp = &per_cpu(boot_pageset, cpu); + struct per_cpu_pageset *pcp = &per_cpu(boot_pageset, cpu).pageset; memset(pcp->vm_numa_stat_diff, 0, sizeof(pcp->vm_numa_stat_diff)); } @@ -6694,7 +6831,7 @@ static __meminit void zone_pcp_init(struct zone *zone) * relies on the ability of the linker to provide the * offset of a (static) per cpu variable into the per cpu area. */ - zone->pageset = &boot_pageset; + zone->pageset = &boot_pageset.pageset; if (populated_zone(zone)) printk(KERN_DEBUG " %s zone: %lu pages, LIFO batch:%u\n", @@ -7603,17 +7740,10 @@ restart: out2: /* Align start of ZONE_MOVABLE on all nids to MAX_ORDER_NR_PAGES */ - for (nid = 0; nid < MAX_NUMNODES; nid++) { - unsigned long start_pfn, end_pfn; - + for (nid = 0; nid < MAX_NUMNODES; nid++) zone_movable_pfn[nid] = roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES); - get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); - if (zone_movable_pfn[nid] >= end_pfn) - zone_movable_pfn[nid] = 0; - } - out: /* restore the node_state */ node_states[N_MEMORY] = saved_node_state; @@ -8722,7 +8852,12 @@ static int __alloc_contig_migrate_range(struct compact_control *cc, if (ret < 0) { if (ret == -EBUSY) { alloc_contig_dump_pages(&cc->migratepages); - page_pinner_mark_migration_failed_pages(&cc->migratepages); + list_for_each_entry(page, &cc->migratepages, lru) { + /* The page will be freed by putback_movable_pages soon */ + if (page_count(page) == 1) + continue; + page_pinner_failure_detect(page); + } } if (!list_empty(&cc->migratepages)) { @@ -9032,13 +9167,13 @@ void zone_pcp_reset(struct zone *zone) /* avoid races with drain_pages() */ local_irq_save(flags); - if (zone->pageset != &boot_pageset) { + if (zone->pageset != &boot_pageset.pageset) { for_each_online_cpu(cpu) { pset = per_cpu_ptr(zone->pageset, cpu); drain_zonestat(zone, pset); } free_percpu(zone->pageset); - zone->pageset = &boot_pageset; + zone->pageset = &boot_pageset.pageset; } local_irq_restore(flags); } diff --git a/mm/page_ext.c b/mm/page_ext.c index 7e44726b3549511bda09ef2d66cb35efd3c0208a..e5e31ff1adba5cf1751b420e4ab634c50fa22b1d 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -58,11 +58,21 @@ * can utilize this callback to initialize the state of it correctly. */ +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) +static bool need_page_idle(void) +{ + return true; +} +struct page_ext_operations page_idle_ops = { + .need = need_page_idle, +}; +#endif + static struct page_ext_operations *page_ext_ops[] = { #ifdef CONFIG_PAGE_OWNER &page_owner_ops, #endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) +#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) &page_idle_ops, #endif #ifdef CONFIG_PAGE_PINNER diff --git a/mm/page_idle.c b/mm/page_idle.c index 057c61df12dba277af673ee2c5e68ab6232fa9a6..144fb4ed961d79f3a6377d37ebabab69e1cf2398 100644 --- a/mm/page_idle.c +++ b/mm/page_idle.c @@ -211,16 +211,6 @@ static const struct attribute_group page_idle_attr_group = { .name = "page_idle", }; -#ifndef CONFIG_64BIT -static bool need_page_idle(void) -{ - return true; -} -struct page_ext_operations page_idle_ops = { - .need = need_page_idle, -}; -#endif - static int __init page_idle_init(void) { int err; diff --git a/mm/page_io.c b/mm/page_io.c index f2900cf6c5b4f27698986e466b142957ae4836a2..d5efe9558b8a073047098861e14759fdd4349188 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -69,54 +69,6 @@ void end_swap_bio_write(struct bio *bio) bio_put(bio); } -static void swap_slot_free_notify(struct page *page) -{ - struct swap_info_struct *sis; - struct gendisk *disk; - swp_entry_t entry; - - /* - * There is no guarantee that the page is in swap cache - the software - * suspend code (at least) uses end_swap_bio_read() against a non- - * swapcache page. So we must check PG_swapcache before proceeding with - * this optimization. - */ - if (unlikely(!PageSwapCache(page))) - return; - - sis = page_swap_info(page); - if (data_race(!(sis->flags & SWP_BLKDEV))) - return; - - /* - * The swap subsystem performs lazy swap slot freeing, - * expecting that the page will be swapped out again. - * So we can avoid an unnecessary write if the page - * isn't redirtied. - * This is good for real swap storage because we can - * reduce unnecessary I/O and enhance wear-leveling - * if an SSD is used as the as swap device. - * But if in-memory swap device (eg zram) is used, - * this causes a duplicated copy between uncompressed - * data in VM-owned memory and compressed data in - * zram-owned memory. So let's free zram-owned memory - * and make the VM-owned decompressed page *dirty*, - * so the page should be swapped out somewhere again if - * we again wish to reclaim it. - */ - disk = sis->bdev->bd_disk; - entry.val = page_private(page); - if (disk->fops->swap_slot_free_notify && __swap_count(entry) == 1) { - unsigned long offset; - - offset = swp_offset(entry); - - SetPageDirty(page); - disk->fops->swap_slot_free_notify(sis->bdev, - offset); - } -} - static void end_swap_bio_read(struct bio *bio) { struct page *page = bio_first_page_all(bio); @@ -132,7 +84,6 @@ static void end_swap_bio_read(struct bio *bio) } SetPageUptodate(page); - swap_slot_free_notify(page); out: unlock_page(page); WRITE_ONCE(bio->bi_private, NULL); @@ -409,11 +360,6 @@ int swap_readpage(struct page *page, bool synchronous) if (sis->flags & SWP_SYNCHRONOUS_IO) { ret = bdev_read_page(sis->bdev, swap_page_sector(page), page); if (!ret) { - if (trylock_page(page)) { - swap_slot_free_notify(page); - unlock_page(page); - } - count_vm_event(PSWPIN); goto out; } diff --git a/mm/page_pinner.c b/mm/page_pinner.c index 12d545c44a666c291c2c2e7b992e3b27ebbfef21..b81d48fa65fdb9dc6ce414931b353737029e74bd 100644 --- a/mm/page_pinner.c +++ b/mm/page_pinner.c @@ -15,19 +15,25 @@ #include "internal.h" #define PAGE_PINNER_STACK_DEPTH 16 -#define LONGTERM_PIN_BUCKETS 4096 +static unsigned long pp_buf_size = 4096; struct page_pinner { depot_stack_handle_t handle; - s64 ts_usec; + u64 ts_usec; atomic_t count; }; +enum pp_state { + PP_PUT, + PP_FREE, + PP_FAIL_DETECTED, +}; + struct captured_pinner { depot_stack_handle_t handle; union { - s64 ts_usec; - s64 elapsed; + u64 ts_usec; + u64 elapsed; }; /* struct page fields */ @@ -36,24 +42,17 @@ struct captured_pinner { int mapcount; struct address_space *mapping; unsigned long flags; + enum pp_state state; }; -struct longterm_pinner { +struct page_pinner_buffer { spinlock_t lock; - unsigned int index; - struct captured_pinner pinner[LONGTERM_PIN_BUCKETS]; + unsigned long index; + struct captured_pinner *buffer; }; -static struct longterm_pinner lt_pinner = { - .lock = __SPIN_LOCK_UNLOCKED(lt_pinner.lock), -}; - -static s64 threshold_usec = 300000; - /* alloc_contig failed pinner */ -static struct longterm_pinner acf_pinner = { - .lock = __SPIN_LOCK_UNLOCKED(acf_pinner.lock), -}; +static struct page_pinner_buffer pp_buffer; static bool page_pinner_enabled; DEFINE_STATIC_KEY_FALSE(page_pinner_inited); @@ -128,96 +127,61 @@ static void capture_page_state(struct page *page, record->mapcount = page_mapcount(page); } -static void check_longterm_pin(struct page_pinner *page_pinner, - struct page *page) +static void add_record(struct page_pinner_buffer *pp_buf, + struct captured_pinner *record) { - s64 now, delta = 0; unsigned long flags; unsigned int idx; - struct captured_pinner record; - - now = ktime_to_us(ktime_get_boottime()); - - /* get/put_page can be raced. Ignore that case */ - if (page_pinner->ts_usec < now) - delta = now - page_pinner->ts_usec; - if (delta <= threshold_usec) - return; - - record.handle = page_pinner->handle; - record.elapsed = delta; - capture_page_state(page, &record); - - spin_lock_irqsave(<_pinner.lock, flags); - idx = lt_pinner.index++; - lt_pinner.index %= LONGTERM_PIN_BUCKETS; - lt_pinner.pinner[idx] = record; - spin_unlock_irqrestore(<_pinner.lock, flags); + spin_lock_irqsave(&pp_buf->lock, flags); + idx = pp_buf->index++; + pp_buf->index %= pp_buf_size; + pp_buf->buffer[idx] = *record; + spin_unlock_irqrestore(&pp_buf->lock, flags); } -void __reset_page_pinner(struct page *page, unsigned int order, bool free) +void __free_page_pinner(struct page *page, unsigned int order) { struct page_pinner *page_pinner; struct page_ext *page_ext; int i; + /* free_page could be called before buffer is initialized */ + if (!pp_buffer.buffer) + return; + page_ext = lookup_page_ext(page); if (unlikely(!page_ext)) return; for (i = 0; i < (1 << order); i++) { - if (!test_bit(PAGE_EXT_GET, &page_ext->flags) && - !test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, - &page_ext->flags)) + struct captured_pinner record; + + if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) continue; page_pinner = get_page_pinner(page_ext); - if (free) { - /* record page free call path */ - __page_pinner_migration_failed(page); - atomic_set(&page_pinner->count, 0); - __clear_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); - } else { - check_longterm_pin(page_pinner, page); - } - clear_bit(PAGE_EXT_GET, &page_ext->flags); - page_ext = page_ext_next(page_ext); - } -} + /* record page free call path */ + page_ext = lookup_page_ext(page); + if (unlikely(!page_ext)) + continue; -static inline void __set_page_pinner_handle(struct page *page, - struct page_ext *page_ext, depot_stack_handle_t handle, - unsigned int order) -{ - struct page_pinner *page_pinner; - int i; - s64 usec = ktime_to_us(ktime_get_boottime()); + record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); + record.ts_usec = (u64)ktime_to_us(ktime_get_boottime()); + record.state = PP_FREE; + capture_page_state(page, &record); - for (i = 0; i < (1 << order); i++) { - page_pinner = get_page_pinner(page_ext); - page_pinner->handle = handle; - page_pinner->ts_usec = usec; - set_bit(PAGE_EXT_GET, &page_ext->flags); - atomic_inc(&page_pinner->count); + add_record(&pp_buffer, &record); + + atomic_set(&page_pinner->count, 0); + page_pinner->ts_usec = 0; + clear_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); page_ext = page_ext_next(page_ext); } } -noinline void __set_page_pinner(struct page *page, unsigned int order) -{ - struct page_ext *page_ext = lookup_page_ext(page); - depot_stack_handle_t handle; - - if (unlikely(!page_ext)) - return; - - handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); - __set_page_pinner_handle(page, page_ext, handle, order); -} - static ssize_t -print_page_pinner(bool longterm, char __user *buf, size_t count, struct captured_pinner *record) +print_page_pinner(char __user *buf, size_t count, struct captured_pinner *record) { int ret; unsigned long *entries; @@ -229,15 +193,17 @@ print_page_pinner(bool longterm, char __user *buf, size_t count, struct captured if (!kbuf) return -ENOMEM; - if (longterm) { - ret = snprintf(kbuf, count, "Page pinned for %lld us\n", + if (record->state == PP_PUT) { + ret = snprintf(kbuf, count, "At least, pinned for %llu us\n", record->elapsed); } else { - s64 ts_usec = record->ts_usec; + u64 ts_usec = record->ts_usec; unsigned long rem_usec = do_div(ts_usec, 1000000); ret = snprintf(kbuf, count, - "Page pinned ts [%5lu.%06lu]\n", + "%s [%5lu.%06lu]\n", + record->state == PP_FREE ? "Freed at" : + "Failure detected at", (unsigned long)ts_usec, rem_usec); } @@ -277,60 +243,39 @@ err: return -ENOMEM; } -void __dump_page_pinner(struct page *page) +void __page_pinner_failure_detect(struct page *page) { struct page_ext *page_ext = lookup_page_ext(page); struct page_pinner *page_pinner; - depot_stack_handle_t handle; - unsigned long *entries; - unsigned int nr_entries; - int pageblock_mt; - unsigned long pfn; - int count; - unsigned long rem_usec; - s64 ts_usec; + struct captured_pinner record; + u64 now; - if (unlikely(!page_ext)) { - pr_alert("There is not page extension available.\n"); + if (unlikely(!page_ext)) return; - } - page_pinner = get_page_pinner(page_ext); - - count = atomic_read(&page_pinner->count); - if (!count) { - pr_alert("page_pinner info is not present (never set?)\n"); + if (test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) return; - } - pfn = page_to_pfn(page); - ts_usec = page_pinner->ts_usec; - rem_usec = do_div(ts_usec, 1000000); - pr_alert("page last pinned %5lu.%06lu] count %d\n", - (unsigned long)ts_usec, rem_usec, count); - - pageblock_mt = get_pageblock_migratetype(page); - pr_alert("PFN %lu Block %lu type %s Flags %#lx(%pGp)\n", - pfn, - pfn >> pageblock_order, - migratetype_names[pageblock_mt], - page->flags, &page->flags); - - handle = READ_ONCE(page_pinner->handle); - if (!handle) { - pr_alert("page_pinner allocation stack trace missing\n"); - } else { - nr_entries = stack_depot_fetch(handle, &entries); - stack_trace_print(entries, nr_entries, 0); - } + now = (u64)ktime_to_us(ktime_get_boottime()); + page_pinner = get_page_pinner(page_ext); + if (!page_pinner->ts_usec) + page_pinner->ts_usec = now; + set_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); + record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); + record.ts_usec = now; + record.state = PP_FAIL_DETECTED; + capture_page_state(page, &record); + + add_record(&pp_buffer, &record); } +EXPORT_SYMBOL_GPL(__page_pinner_failure_detect); -void __page_pinner_migration_failed(struct page *page) +void __page_pinner_put_page(struct page *page) { struct page_ext *page_ext = lookup_page_ext(page); + struct page_pinner *page_pinner; struct captured_pinner record; - unsigned long flags; - unsigned int idx; + u64 now, ts_usec; if (unlikely(!page_ext)) return; @@ -338,74 +283,26 @@ void __page_pinner_migration_failed(struct page *page) if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) return; + page_pinner = get_page_pinner(page_ext); record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN); - record.ts_usec = ktime_to_us(ktime_get_boottime()); - capture_page_state(page, &record); - - spin_lock_irqsave(&acf_pinner.lock, flags); - idx = acf_pinner.index++; - acf_pinner.index %= LONGTERM_PIN_BUCKETS; - acf_pinner.pinner[idx] = record; - spin_unlock_irqrestore(&acf_pinner.lock, flags); -} -EXPORT_SYMBOL_GPL(__page_pinner_migration_failed); - -void __page_pinner_mark_migration_failed_pages(struct list_head *page_list) -{ - struct page *page; - struct page_ext *page_ext; - - list_for_each_entry(page, page_list, lru) { - /* The page will be freed by putback_movable_pages soon */ - if (page_count(page) == 1) - continue; - page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - continue; - __set_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags); - __page_pinner_migration_failed(page); - } -} - -static ssize_t -read_longterm_page_pinner(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - loff_t i, idx; - struct captured_pinner record; - unsigned long flags; - - if (!static_branch_unlikely(&page_pinner_inited)) - return -EINVAL; - - if (*ppos >= LONGTERM_PIN_BUCKETS) - return 0; - - i = *ppos; - *ppos = i + 1; + now = (u64)ktime_to_us(ktime_get_boottime()); + ts_usec = page_pinner->ts_usec; - /* - * reading the records in the reverse order with newest one - * being read first followed by older ones - */ - idx = (lt_pinner.index - 1 - i + LONGTERM_PIN_BUCKETS) % - LONGTERM_PIN_BUCKETS; - spin_lock_irqsave(<_pinner.lock, flags); - record = lt_pinner.pinner[idx]; - spin_unlock_irqrestore(<_pinner.lock, flags); - if (!record.handle) - return 0; + if (now > ts_usec) + record.elapsed = now - ts_usec; + else + record.elapsed = 0; + record.state = PP_PUT; + capture_page_state(page, &record); - return print_page_pinner(true, buf, count, &record); + add_record(&pp_buffer, &record); } +EXPORT_SYMBOL_GPL(__page_pinner_put_page); -static const struct file_operations proc_longterm_pinner_operations = { - .read = read_longterm_page_pinner, -}; - -static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf, +static ssize_t read_buffer(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + u64 tmp; loff_t i, idx; struct captured_pinner record; unsigned long flags; @@ -413,7 +310,7 @@ static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf, if (!static_branch_unlikely(&failure_tracking)) return -EINVAL; - if (*ppos >= LONGTERM_PIN_BUCKETS) + if (*ppos >= pp_buf_size) return 0; i = *ppos; @@ -423,45 +320,22 @@ static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf, * reading the records in the reverse order with newest one * being read first followed by older ones */ - idx = (acf_pinner.index - 1 - i + LONGTERM_PIN_BUCKETS) % - LONGTERM_PIN_BUCKETS; + tmp = pp_buffer.index - 1 - i + pp_buf_size; + idx = do_div(tmp, pp_buf_size); - spin_lock_irqsave(&acf_pinner.lock, flags); - record = acf_pinner.pinner[idx]; - spin_unlock_irqrestore(&acf_pinner.lock, flags); + spin_lock_irqsave(&pp_buffer.lock, flags); + record = pp_buffer.buffer[idx]; + spin_unlock_irqrestore(&pp_buffer.lock, flags); if (!record.handle) return 0; - return print_page_pinner(false, buf, count, &record); + return print_page_pinner(buf, count, &record); } -static const struct file_operations proc_alloc_contig_failed_operations = { - .read = read_alloc_contig_failed, +static const struct file_operations proc_buffer_operations = { + .read = read_buffer, }; -static int pp_threshold_set(void *data, unsigned long long val) -{ - unsigned long flags; - - threshold_usec = (s64)val; - - spin_lock_irqsave(<_pinner.lock, flags); - memset(lt_pinner.pinner, 0, - sizeof(struct captured_pinner) * LONGTERM_PIN_BUCKETS); - lt_pinner.index = 0; - spin_unlock_irqrestore(<_pinner.lock, flags); - return 0; -} - -static int pp_threshold_get(void *data, unsigned long long *val) -{ - *val = (unsigned long long)threshold_usec; - - return 0; -} -DEFINE_DEBUGFS_ATTRIBUTE(pp_threshold_fops, pp_threshold_get, - pp_threshold_set, "%lld\n"); - static int failure_tracking_set(void *data, u64 val) { bool on; @@ -483,6 +357,35 @@ DEFINE_DEBUGFS_ATTRIBUTE(failure_tracking_fops, failure_tracking_get, failure_tracking_set, "%llu\n"); +static int buffer_size_set(void *data, u64 val) +{ + unsigned long flags; + struct captured_pinner *new, *old; + + new = kvmalloc_array(val, sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + spin_lock_irqsave(&pp_buffer.lock, flags); + old = pp_buffer.buffer; + pp_buffer.buffer = new; + pp_buffer.index = 0; + pp_buf_size = val; + spin_unlock_irqrestore(&pp_buffer.lock, flags); + kvfree(old); + + return 0; +} + +static int buffer_size_get(void *data, u64 *val) +{ + *val = pp_buf_size; + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(buffer_size_fops, + buffer_size_get, + buffer_size_set, "%llu\n"); + static int __init page_pinner_init(void) { struct dentry *pp_debugfs_root; @@ -490,23 +393,31 @@ static int __init page_pinner_init(void) if (!static_branch_unlikely(&page_pinner_inited)) return 0; - pr_info("page_pinner enabled\n"); + pp_buffer.buffer = kvmalloc_array(pp_buf_size, sizeof(*pp_buffer.buffer), + GFP_KERNEL); + if (!pp_buffer.buffer) { + pr_info("page_pinner disabled due to \n"); + return 1; + } - pp_debugfs_root = debugfs_create_dir("page_pinner", NULL); + spin_lock_init(&pp_buffer.lock); + pp_buffer.index = 0; - debugfs_create_file("longterm_pinner", 0444, pp_debugfs_root, NULL, - &proc_longterm_pinner_operations); + pr_info("page_pinner enabled\n"); - debugfs_create_file("threshold", 0644, pp_debugfs_root, NULL, - &pp_threshold_fops); + pp_debugfs_root = debugfs_create_dir("page_pinner", NULL); - debugfs_create_file("alloc_contig_failed", 0444, + debugfs_create_file("buffer", 0444, pp_debugfs_root, NULL, - &proc_alloc_contig_failed_operations); + &proc_buffer_operations); debugfs_create_file("failure_tracking", 0644, pp_debugfs_root, NULL, &failure_tracking_fops); + + debugfs_create_file("buffer_size", 0644, + pp_debugfs_root, NULL, + &buffer_size_fops); return 0; } late_initcall(page_pinner_init) diff --git a/mm/rmap.c b/mm/rmap.c index 4fdbda090c2c2948260ca3e9cf79d149efbb79fa..52291f59b0b45ee5ab3908a157ebbb80d336cf8a 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -72,6 +72,7 @@ #include #include #include +#include #include @@ -782,6 +783,12 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, } if (pvmw.pte) { + if (lru_gen_enabled() && pte_young(*pvmw.pte) && + !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { + lru_gen_look_around(&pvmw); + referenced++; + } + if (ptep_clear_flush_young_notify(vma, address, pvmw.pte)) { /* diff --git a/mm/swap.c b/mm/swap.c index 8d5c61de5a6ebe8c15707d4df576934ded33a1a0..2f69e44ca7374bed550d888a601b98d557047d70 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -87,9 +87,8 @@ static void __page_cache_release(struct page *page) spin_lock_irqsave(&pgdat->lru_lock, flags); lruvec = mem_cgroup_page_lruvec(page, pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); spin_unlock_irqrestore(&pgdat->lru_lock, flags); } __ClearPageWaiters(page); @@ -240,9 +239,9 @@ static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec, int *pgmoved = arg; if (PageLRU(page) && !PageUnevictable(page)) { - del_page_from_lru_list(page, lruvec, page_lru(page)); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); - add_page_to_lru_list_tail(page, lruvec, page_lru(page)); + add_page_to_lru_list_tail(page, lruvec); (*pgmoved) += thp_nr_pages(page); } } @@ -333,13 +332,11 @@ static void __activate_page(struct page *page, struct lruvec *lruvec, void *arg) { if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - int lru = page_lru_base_type(page); int nr_pages = thp_nr_pages(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); SetPageActive(page); - lru += LRU_ACTIVE; - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); trace_mm_lru_activate(page); __count_vm_events(PGACTIVATE, nr_pages); @@ -362,7 +359,7 @@ static bool need_activate_page_drain(int cpu) return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0; } -static void activate_page(struct page *page) +void activate_page(struct page *page) { page = compound_head(page); if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { @@ -382,7 +379,7 @@ static inline void activate_page_drain(int cpu) { } -static void activate_page(struct page *page) +void activate_page(struct page *page) { pg_data_t *pgdat = page_pgdat(page); @@ -423,6 +420,43 @@ static void __lru_cache_activate_page(struct page *page) local_unlock(&lru_pvecs.lock); } +#ifdef CONFIG_LRU_GEN +static void page_inc_refs(struct page *page) +{ + unsigned long refs; + unsigned long old_flags, new_flags; + + if (PageUnevictable(page)) + return; + + /* see the comment on MAX_NR_TIERS */ + do { + new_flags = old_flags = READ_ONCE(page->flags); + + if (!(new_flags & BIT(PG_referenced))) { + new_flags |= BIT(PG_referenced); + continue; + } + + if (!(new_flags & BIT(PG_workingset))) { + new_flags |= BIT(PG_workingset); + continue; + } + + refs = new_flags & LRU_REFS_MASK; + refs = min(refs + BIT(LRU_REFS_PGOFF), LRU_REFS_MASK); + + new_flags &= ~LRU_REFS_MASK; + new_flags |= refs; + } while (new_flags != old_flags && + cmpxchg(&page->flags, old_flags, new_flags) != old_flags); +} +#else +static void page_inc_refs(struct page *page) +{ +} +#endif /* CONFIG_LRU_GEN */ + /* * Mark a page as having seen activity. * @@ -437,6 +471,11 @@ void mark_page_accessed(struct page *page) { page = compound_head(page); + if (lru_gen_enabled()) { + page_inc_refs(page); + return; + } + if (!PageReferenced(page)) { SetPageReferenced(page); } else if (PageUnevictable(page)) { @@ -480,6 +519,11 @@ void lru_cache_add(struct page *page) VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); VM_BUG_ON_PAGE(PageLRU(page), page); + /* see the comment in lru_gen_add_page() */ + if (lru_gen_enabled() && !PageUnevictable(page) && + lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) + SetPageActive(page); + get_page(page); local_lock(&lru_pvecs.lock); pvec = this_cpu_ptr(&lru_pvecs.lru_add); @@ -542,8 +586,7 @@ void __lru_cache_add_inactive_or_unevictable(struct page *page, static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, void *arg) { - int lru; - bool active; + bool active = PageActive(page); int nr_pages = thp_nr_pages(page); if (!PageLRU(page)) @@ -556,10 +599,7 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, if (page_mapped(page)) return; - active = PageActive(page); - lru = page_lru_base_type(page); - - del_page_from_lru_list(page, lruvec, lru + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); @@ -569,14 +609,14 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, * It can make readahead confusing. But race window * is _really_ small and it's non-critical problem. */ - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); SetPageReclaim(page); } else { /* * The page's writeback ends up during pagevec * We moves tha page into tail of inactive. */ - add_page_to_lru_list_tail(page, lruvec, lru); + add_page_to_lru_list_tail(page, lruvec); __count_vm_events(PGROTATED, nr_pages); } @@ -590,14 +630,13 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec, void *arg) { - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { - int lru = page_lru_base_type(page); + if (PageLRU(page) && !PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { int nr_pages = thp_nr_pages(page); - del_page_from_lru_list(page, lruvec, lru + LRU_ACTIVE); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); __count_vm_events(PGDEACTIVATE, nr_pages); __count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE, @@ -610,11 +649,9 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec, { if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page) && !PageUnevictable(page)) { - bool active = PageActive(page); int nr_pages = thp_nr_pages(page); - del_page_from_lru_list(page, lruvec, - LRU_INACTIVE_ANON + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); /* @@ -623,7 +660,7 @@ static void lru_lazyfree_fn(struct page *page, struct lruvec *lruvec, * anonymous pages */ ClearPageSwapBacked(page); - add_page_to_lru_list(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list(page, lruvec); __count_vm_events(PGLAZYFREE, nr_pages); __count_memcg_events(lruvec_memcg(lruvec), PGLAZYFREE, @@ -638,16 +675,13 @@ static void lru_lazyfree_movetail_fn(struct page *page, struct lruvec *lruvec, if (PageLRU(page) && !PageUnevictable(page) && PageSwapBacked(page) && !PageSwapCache(page)) { - bool active = PageActive(page); - - del_page_from_lru_list(page, lruvec, - LRU_INACTIVE_ANON + active); + del_page_from_lru_list(page, lruvec); ClearPageActive(page); ClearPageReferenced(page); if (add_to_tail && *add_to_tail) - add_page_to_lru_list_tail(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list_tail(page, lruvec); else - add_page_to_lru_list(page, lruvec, LRU_INACTIVE_FILE); + add_page_to_lru_list(page, lruvec); } } @@ -733,7 +767,7 @@ void deactivate_file_page(struct page *page) */ void deactivate_page(struct page *page) { - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { + if (PageLRU(page) && !PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { struct pagevec *pvec; local_lock(&lru_pvecs.lock); @@ -1052,9 +1086,8 @@ void release_pages(struct page **pages, int nr) } lruvec = mem_cgroup_page_lruvec(page, locked_pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); } __ClearPageWaiters(page); @@ -1117,8 +1150,7 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, * Put page_tail on the list at the correct position * so they all end up in order. */ - add_page_to_lru_list_tail(page_tail, lruvec, - page_lru(page_tail)); + add_page_to_lru_list_tail(page_tail, lruvec); } } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ @@ -1126,7 +1158,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, void *arg) { - enum lru_list lru; int was_unevictable = TestClearPageUnevictable(page); int nr_pages = thp_nr_pages(page); @@ -1162,19 +1193,17 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, smp_mb__after_atomic(); if (page_evictable(page)) { - lru = page_lru(page); if (was_unevictable) __count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages); } else { - lru = LRU_UNEVICTABLE; ClearPageActive(page); SetPageUnevictable(page); if (!was_unevictable) __count_vm_events(UNEVICTABLE_PGCULLED, nr_pages); } - add_page_to_lru_list(page, lruvec, lru); - trace_mm_lru_insertion(page, lru); + add_page_to_lru_list(page, lruvec); + trace_mm_lru_insertion(page); } /* diff --git a/mm/swap_state.c b/mm/swap_state.c index a8a98bf7c894edd48e485b8c7411ed2d8cdf4138..d13d58fe48c1fc6851bbf59001d16abfc0e90f8f 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -513,7 +513,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * __read_swap_cache_async(), which has set SWAP_HAS_CACHE * in swap_map, but not yet added its page to swap cache. */ - schedule_timeout_uninterruptible(1); + cond_resched(); } /* @@ -538,7 +538,6 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, workingset_refault(page, shadow); /* Caller will initiate read into locked page */ - SetPageWorkingset(page); lru_cache_add(page); *new_page_allocated = true; return page; diff --git a/mm/usercopy.c b/mm/usercopy.c index 540968b481e7eb54f4a83ec38aaacde87b89f50c..b3de3c4eefba750836d2368a89ef42ed47995884 100644 --- a/mm/usercopy.c +++ b/mm/usercopy.c @@ -294,10 +294,7 @@ static bool enable_checks __initdata = true; static int __init parse_hardened_usercopy(char *str) { - if (strtobool(str, &enable_checks)) - pr_warn("Invalid option string for hardened_usercopy: '%s'\n", - str); - return 1; + return strtobool(str, &enable_checks); } __setup("hardened_usercopy=", parse_hardened_usercopy); diff --git a/mm/vmscan.c b/mm/vmscan.c index d49cd9cb79e0eca6a611abedf549a50da8f73340..cb1a9b5b0729af5121fba5dcae272438d8a12c75 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -51,6 +51,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -129,6 +133,13 @@ struct scan_control { /* The file pages on the current node are dangerously low */ unsigned int file_is_tiny:1; +#ifdef CONFIG_LRU_GEN + /* help make better choices when multiple memcgs are available */ + unsigned int memcgs_need_aging:1; + unsigned int memcgs_need_swapping:1; + unsigned int memcgs_avoid_swapping:1; +#endif + /* Allocation order */ s8 order; @@ -931,9 +942,11 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, if (PageSwapCache(page)) { swp_entry_t swap = { .val = page_private(page) }; - mem_cgroup_swapout(page, swap); + + /* get a shadow entry before mem_cgroup_swapout() clears page_memcg() */ if (reclaimed && !mapping_exiting(mapping)) shadow = workingset_eviction(page, target_memcg); + mem_cgroup_swapout(page, swap); __delete_from_swap_cache(page, swap, shadow); xa_unlock_irqrestore(&mapping->i_pages, flags); put_swap_page(page, swap); @@ -1144,6 +1157,11 @@ static unsigned int shrink_page_list(struct list_head *page_list, if (!sc->may_unmap && page_mapped(page)) goto keep_locked; + /* page_update_gen() tried to promote this page? */ + if (lru_gen_enabled() && !ignore_references && + page_mapped(page) && PageReferenced(page)) + goto keep_locked; + may_enter_fs = (sc->gfp_mask & __GFP_FS) || (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); @@ -1837,10 +1855,9 @@ int isolate_lru_page(struct page *page) spin_lock_irq(&pgdat->lru_lock); lruvec = mem_cgroup_page_lruvec(page, pgdat); if (PageLRU(page)) { - int lru = page_lru(page); get_page(page); ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); ret = 0; } spin_unlock_irq(&pgdat->lru_lock); @@ -1912,13 +1929,12 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, int nr_pages, nr_moved = 0; LIST_HEAD(pages_to_free); struct page *page; - enum lru_list lru; while (!list_empty(list)) { page = lru_to_page(list); VM_BUG_ON_PAGE(PageLRU(page), page); + list_del(&page->lru); if (unlikely(!page_evictable(page))) { - list_del(&page->lru); spin_unlock_irq(&pgdat->lru_lock); putback_lru_page(page); spin_lock_irq(&pgdat->lru_lock); @@ -1927,16 +1943,11 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, lruvec = mem_cgroup_page_lruvec(page, pgdat); SetPageLRU(page); - lru = page_lru(page); - - nr_pages = thp_nr_pages(page); - update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); - list_move(&page->lru, &lruvec->lists[lru]); + add_page_to_lru_list(page, lruvec); if (put_page_testzero(page)) { - __ClearPageLRU(page); - __ClearPageActive(page); - del_page_from_lru_list(page, lruvec, lru); + del_page_from_lru_list(page, lruvec); + __clear_page_lru_flags(page); if (unlikely(PageCompound(page))) { spin_unlock_irq(&pgdat->lru_lock); @@ -1945,6 +1956,7 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, } else list_add(&page->lru, &pages_to_free); } else { + nr_pages = thp_nr_pages(page); nr_moved += nr_pages; if (PageActive(page)) workingset_age_nonresident(lruvec, nr_pages); @@ -2288,6 +2300,106 @@ enum scan_balance { SCAN_FILE, }; +static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) +{ + unsigned long file; + struct lruvec *target_lruvec; + + if (lru_gen_enabled()) + return; + + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + /* + * Determine the scan balance between anon and file LRUs. + */ + spin_lock_irq(&pgdat->lru_lock); + sc->anon_cost = target_lruvec->anon_cost; + sc->file_cost = target_lruvec->file_cost; + spin_unlock_irq(&pgdat->lru_lock); + + /* + * Target desirable inactive:active list ratios for the anon + * and file LRU lists. + */ + if (!sc->force_deactivate) { + unsigned long refaults; + + refaults = lruvec_page_state(target_lruvec, + WORKINGSET_ACTIVATE_ANON); + if (refaults != target_lruvec->refaults[0] || + inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) + sc->may_deactivate |= DEACTIVATE_ANON; + else + sc->may_deactivate &= ~DEACTIVATE_ANON; + + /* + * When refaults are being observed, it means a new + * workingset is being established. Deactivate to get + * rid of any stale active pages quickly. + */ + refaults = lruvec_page_state(target_lruvec, + WORKINGSET_ACTIVATE_FILE); + if (refaults != target_lruvec->refaults[1] || + inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) + sc->may_deactivate |= DEACTIVATE_FILE; + else + sc->may_deactivate &= ~DEACTIVATE_FILE; + } else + sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; + + /* + * If we have plenty of inactive file pages that aren't + * thrashing, try to reclaim those first before touching + * anonymous pages. + */ + file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); + if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) + sc->cache_trim_mode = 1; + else + sc->cache_trim_mode = 0; + + /* + * Prevent the reclaimer from falling into the cache trap: as + * cache pages start out inactive, every cache fault will tip + * the scan balance towards the file LRU. And as the file LRU + * shrinks, so does the window for rotation from references. + * This means we have a runaway feedback loop where a tiny + * thrashing file LRU becomes infinitely more attractive than + * anon pages. Try to detect this based on file LRU size. + */ + if (!cgroup_reclaim(sc)) { + unsigned long total_high_wmark = 0; + unsigned long free, anon; + int z; + + free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); + file = node_page_state(pgdat, NR_ACTIVE_FILE) + + node_page_state(pgdat, NR_INACTIVE_FILE); + + for (z = 0; z < MAX_NR_ZONES; z++) { + struct zone *zone = &pgdat->node_zones[z]; + + if (!managed_zone(zone)) + continue; + + total_high_wmark += high_wmark_pages(zone); + } + + /* + * Consider anon: if that's low too, this isn't a + * runaway file reclaim problem, but rather just + * extreme pressure. Reclaim as per usual then. + */ + anon = node_page_state(pgdat, NR_INACTIVE_ANON); + + sc->file_is_tiny = + file + free <= total_high_wmark && + !(sc->may_deactivate & DEACTIVATE_ANON) && + anon >> sc->priority; + } +} + /* * Determine how aggressively the anon and file LRU lists should be * scanned. The relative value of each set of LRU lists is determined @@ -2500,158 +2612,2793 @@ out: } } -static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -{ - unsigned long nr[NR_LRU_LISTS]; - unsigned long targets[NR_LRU_LISTS]; - unsigned long nr_to_scan; - enum lru_list lru; - unsigned long nr_reclaimed = 0; - unsigned long nr_to_reclaim = sc->nr_to_reclaim; - struct blk_plug plug; - bool scan_adjusted; +#ifdef CONFIG_LRU_GEN - get_scan_count(lruvec, sc, nr); +#ifdef CONFIG_LRU_GEN_ENABLED +DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS); +#else +DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); +#endif - /* Record the original scan target for proportional adjustments later */ - memcpy(targets, nr, sizeof(nr)); +/****************************************************************************** + * shorthand helpers + ******************************************************************************/ - /* - * Global reclaiming within direct reclaim at DEF_PRIORITY is a normal - * event that can occur when there is little memory pressure e.g. - * multiple streaming readers/writers. Hence, we do not abort scanning - * when the requested number of pages are reclaimed when scanning at - * DEF_PRIORITY on the assumption that the fact we are direct - * reclaiming implies that kswapd is not keeping up and it is best to - * do a batch of work at once. For memcg reclaim one check is made to - * abort proportional reclaim if either the file or anon lru has already - * dropped to zero at the first pass. - */ - scan_adjusted = (!cgroup_reclaim(sc) && !current_is_kswapd() && - sc->priority == DEF_PRIORITY); +#define DEFINE_MAX_SEQ(lruvec) \ + unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq) - blk_start_plug(&plug); - while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || - nr[LRU_INACTIVE_FILE]) { - unsigned long nr_anon, nr_file, percentage; - unsigned long nr_scanned; +#define DEFINE_MIN_SEQ(lruvec) \ + unsigned long min_seq[ANON_AND_FILE] = { \ + READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_ANON]), \ + READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_FILE]), \ + } - for_each_evictable_lru(lru) { - if (nr[lru]) { - nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX); - nr[lru] -= nr_to_scan; +#define for_each_gen_type_zone(gen, type, zone) \ + for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) - nr_reclaimed += shrink_list(lru, nr_to_scan, - lruvec, sc); - } - } +static int page_lru_gen(struct page *page) +{ + unsigned long flags = READ_ONCE(page->flags); - cond_resched(); + return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; +} - if (nr_reclaimed < nr_to_reclaim || scan_adjusted) - continue; +static int page_lru_tier(struct page *page) +{ + int refs; + unsigned long flags = READ_ONCE(page->flags); - /* - * For kswapd and memcg, reclaim at least the number of pages - * requested. Ensure that the anon and file LRUs are scanned - * proportionally what was requested by get_scan_count(). We - * stop reclaiming one LRU and reduce the amount scanning - * proportional to the original scan target. - */ - nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE]; - nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON]; + refs = (flags & LRU_REFS_FLAGS) == LRU_REFS_FLAGS ? + ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + 1 : 0; - /* - * It's just vindictive to attack the larger once the smaller - * has gone to zero. And given the way we stop scanning the - * smaller below, this makes sure that we only make one nudge - * towards proportionality once we've got nr_to_reclaim. - */ - if (!nr_file || !nr_anon) - break; + return lru_tier_from_refs(refs); +} - if (nr_file > nr_anon) { - unsigned long scan_target = targets[LRU_INACTIVE_ANON] + - targets[LRU_ACTIVE_ANON] + 1; - lru = LRU_BASE; - percentage = nr_anon * 100 / scan_target; - } else { - unsigned long scan_target = targets[LRU_INACTIVE_FILE] + - targets[LRU_ACTIVE_FILE] + 1; - lru = LRU_FILE; - percentage = nr_file * 100 / scan_target; - } +static bool get_cap(int cap) +{ +#ifdef CONFIG_LRU_GEN_ENABLED + return static_branch_likely(&lru_gen_caps[cap]); +#else + return static_branch_unlikely(&lru_gen_caps[cap]); +#endif +} - /* Stop scanning the smaller of the LRU */ - nr[lru] = 0; - nr[lru + LRU_ACTIVE] = 0; +static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) +{ + struct pglist_data *pgdat = NODE_DATA(nid); - /* - * Recalculate the other LRU scan count based on its original - * scan target and the percentage scanning already complete - */ - lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE; - nr_scanned = targets[lru] - nr[lru]; - nr[lru] = targets[lru] * (100 - percentage) / 100; - nr[lru] -= min(nr[lru], nr_scanned); +#ifdef CONFIG_MEMCG + if (memcg) { + struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; - lru += LRU_ACTIVE; - nr_scanned = targets[lru] - nr[lru]; - nr[lru] = targets[lru] * (100 - percentage) / 100; - nr[lru] -= min(nr[lru], nr_scanned); + /* for hotadd_new_pgdat() */ + if (!lruvec->pgdat) + lruvec->pgdat = pgdat; - scan_adjusted = true; + return lruvec; } - blk_finish_plug(&plug); - sc->nr_reclaimed += nr_reclaimed; +#endif + VM_BUG_ON(!mem_cgroup_disabled()); - /* - * Even if we did not try to evict anon pages at all, we want to - * rebalance the anon lru active/inactive ratio. - */ - if (total_swap_pages && inactive_is_low(lruvec, LRU_INACTIVE_ANON)) - shrink_active_list(SWAP_CLUSTER_MAX, lruvec, - sc, LRU_ACTIVE_ANON); + return pgdat ? &pgdat->__lruvec : NULL; } -/* Use reclaim/compaction for costly allocs or under memory pressure */ -static bool in_reclaim_compaction(struct scan_control *sc) +static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) { - if (IS_ENABLED(CONFIG_COMPACTION) && sc->order && - (sc->order > PAGE_ALLOC_COSTLY_ORDER || - sc->priority < DEF_PRIORITY - 2)) - return true; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); - return false; + if (mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) + return 0; + + return mem_cgroup_swappiness(memcg); } -/* - * Reclaim/compaction is used for high-order allocation requests. It reclaims - * order-0 pages before compacting the zone. should_continue_reclaim() returns - * true if more pages should be reclaimed such that when the page allocator - * calls try_to_compact_pages() that it will have enough free pages to succeed. - * It will give up earlier than that if there is difficulty reclaiming pages. - */ -static inline bool should_continue_reclaim(struct pglist_data *pgdat, - unsigned long nr_reclaimed, - struct scan_control *sc) +static int get_nr_gens(struct lruvec *lruvec, int type) { - unsigned long pages_for_compaction; - unsigned long inactive_lru_pages; - int z; + return lruvec->lrugen.max_seq - lruvec->lrugen.min_seq[type] + 1; +} - /* If not in reclaim/compaction mode, stop */ - if (!in_reclaim_compaction(sc)) - return false; +static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) +{ + /* see the comment on lru_gen_struct */ + return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && + get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; +} - /* - * Stop if we failed to reclaim any pages from the last SWAP_CLUSTER_MAX - * number of pages that were scanned. This will return to the caller - * with the risk reclaim/compaction and the resulting allocation attempt - * fails. In the past we have tried harder for __GFP_RETRY_MAYFAIL - * allocations through requiring that the full LRU list has been scanned - * first, by assuming that zero delta of sc->nr_scanned means full LRU - * scan, but that approximation was wrong, and there were corner cases +/****************************************************************************** + * mm_struct list + ******************************************************************************/ + +static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) +{ + static struct lru_gen_mm_list mm_list = { + .fifo = LIST_HEAD_INIT(mm_list.fifo), + .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), + }; + +#ifdef CONFIG_MEMCG + if (memcg) + return &memcg->mm_list; +#endif + VM_BUG_ON(!mem_cgroup_disabled()); + + return &mm_list; +} + +void lru_gen_add_mm(struct mm_struct *mm) +{ + int nid; + struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + + VM_BUG_ON_MM(!list_empty(&mm->lru_gen.list), mm); +#ifdef CONFIG_MEMCG + VM_BUG_ON_MM(mm->lru_gen.memcg, mm); + mm->lru_gen.memcg = memcg; +#endif + spin_lock(&mm_list->lock); + + for_each_node_state(nid, N_MEMORY) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (lruvec->mm_state.tail == &mm_list->fifo) + lruvec->mm_state.tail = &mm->lru_gen.list; + } + + list_add_tail(&mm->lru_gen.list, &mm_list->fifo); + + spin_unlock(&mm_list->lock); +} + +void lru_gen_del_mm(struct mm_struct *mm) +{ + int nid; + struct lru_gen_mm_list *mm_list; + struct mem_cgroup *memcg = NULL; + + if (list_empty(&mm->lru_gen.list)) + return; + +#ifdef CONFIG_MEMCG + memcg = mm->lru_gen.memcg; +#endif + mm_list = get_mm_list(memcg); + + spin_lock(&mm_list->lock); + + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (lruvec->mm_state.tail == &mm->lru_gen.list) + lruvec->mm_state.tail = lruvec->mm_state.tail->next; + + if (lruvec->mm_state.head != &mm->lru_gen.list) + continue; + + lruvec->mm_state.head = lruvec->mm_state.head->next; + if (lruvec->mm_state.head == &mm_list->fifo) + WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); + } + + list_del_init(&mm->lru_gen.list); + + spin_unlock(&mm_list->lock); + +#ifdef CONFIG_MEMCG + mem_cgroup_put(mm->lru_gen.memcg); + mm->lru_gen.memcg = NULL; +#endif +} + +#ifdef CONFIG_MEMCG +void lru_gen_migrate_mm(struct mm_struct *mm) +{ + struct mem_cgroup *memcg; + + lockdep_assert_held(&mm->owner->alloc_lock); + + /* for mm_update_next_owner() */ + if (mem_cgroup_disabled()) + return; + + rcu_read_lock(); + memcg = mem_cgroup_from_task(mm->owner); + rcu_read_unlock(); + if (memcg == mm->lru_gen.memcg) + return; + + VM_BUG_ON_MM(!mm->lru_gen.memcg, mm); + VM_BUG_ON_MM(list_empty(&mm->lru_gen.list), mm); + + lru_gen_del_mm(mm); + lru_gen_add_mm(mm); +} +#endif + +/* + * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when + * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of + * bits in a bitmap, k is the number of hash functions and n is the number of + * inserted items. + * + * Page table walkers use one of the two filters to reduce their search space. + * To get rid of non-leaf entries that no longer have enough leaf entries, the + * aging uses the double-buffering technique to flip to the other filter each + * time it produces a new generation. For non-leaf entries that have enough + * leaf entries, the aging carries them over to the next generation in + * walk_pmd_range(); the eviction also report them when walking the rmap + * in lru_gen_look_around(). + * + * For future optimizations: + * 1. It's not necessary to keep both filters all the time. The spare one can be + * freed after the RCU grace period and reallocated if needed again. + * 2. And when reallocating, it's worth scaling its size according to the number + * of inserted entries in the other filter, to reduce the memory overhead on + * small systems and false positives on large systems. + * 3. Jenkins' hash function is an alternative to Knuth's. + */ +#define BLOOM_FILTER_SHIFT 15 + +static inline int filter_gen_from_seq(unsigned long seq) +{ + return seq % NR_BLOOM_FILTERS; +} + +static void get_item_key(void *item, int *key) +{ + u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); + + BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); + + key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); + key[1] = hash >> BLOOM_FILTER_SHIFT; +} + +static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) +{ + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); + + filter = lruvec->mm_state.filters[gen]; + if (filter) { + bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); + return; + } + + filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), GFP_ATOMIC); + WRITE_ONCE(lruvec->mm_state.filters[gen], filter); +} + +static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +{ + int key[2]; + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + filter = READ_ONCE(lruvec->mm_state.filters[gen]); + if (!filter) + return; + + get_item_key(item, key); + + if (!test_bit(key[0], filter)) + set_bit(key[0], filter); + if (!test_bit(key[1], filter)) + set_bit(key[1], filter); +} + +static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +{ + int key[2]; + unsigned long *filter; + int gen = filter_gen_from_seq(seq); + + filter = READ_ONCE(lruvec->mm_state.filters[gen]); + if (!filter) + return true; + + get_item_key(item, key); + + return test_bit(key[0], filter) && test_bit(key[1], filter); +} + +static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) +{ + int i; + int hist; + + lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); + + if (walk) { + hist = lru_hist_from_seq(walk->max_seq); + + for (i = 0; i < NR_MM_STATS; i++) { + WRITE_ONCE(lruvec->mm_state.stats[hist][i], + lruvec->mm_state.stats[hist][i] + walk->mm_stats[i]); + walk->mm_stats[i] = 0; + } + } + + if (NR_HIST_GENS > 1 && last) { + hist = lru_hist_from_seq(lruvec->mm_state.seq + 1); + + for (i = 0; i < NR_MM_STATS; i++) + WRITE_ONCE(lruvec->mm_state.stats[hist][i], 0); + } +} + +static bool should_skip_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk) +{ + int type; + unsigned long size = 0; + struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); + + if (!walk->full_scan && cpumask_empty(mm_cpumask(mm)) && + !node_isset(pgdat->node_id, mm->lru_gen.nodes)) + return true; + + node_clear(pgdat->node_id, mm->lru_gen.nodes); + + for (type = !walk->can_swap; type < ANON_AND_FILE; type++) { + size += type ? get_mm_counter(mm, MM_FILEPAGES) : + get_mm_counter(mm, MM_ANONPAGES) + + get_mm_counter(mm, MM_SHMEMPAGES); + } + + if (size < MIN_LRU_BATCH) + return true; + + if (mm_is_oom_victim(mm)) + return true; + + return !mmget_not_zero(mm); +} + +static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, + struct mm_struct **iter) +{ + bool first = false; + bool last = true; + struct mm_struct *mm = NULL; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + /* + * There are four interesting cases for this page table walker: + * 1. It tries to start a new iteration of mm_list with a stale max_seq; + * there is nothing to be done. + * 2. It's the first of the current generation, and it needs to reset + * the Bloom filter for the next generation. + * 3. It reaches the end of mm_list, and it needs to increment + * mm_state->seq; the iteration is done. + * 4. It's the last of the current generation, and it needs to reset the + * mm stats counters for the next generation. + */ + if (*iter) + mmput_async(*iter); + else if (walk->max_seq <= READ_ONCE(mm_state->seq)) + return false; + + spin_lock(&mm_list->lock); + + VM_BUG_ON(mm_state->seq + 1 < walk->max_seq); + VM_BUG_ON(*iter && mm_state->seq > walk->max_seq); + VM_BUG_ON(*iter && !mm_state->nr_walkers); + + if (walk->max_seq <= mm_state->seq) { + if (!*iter) + last = false; + goto done; + } + + if (!mm_state->nr_walkers) { + VM_BUG_ON(mm_state->head && mm_state->head != &mm_list->fifo); + + mm_state->head = mm_list->fifo.next; + first = true; + } + + while (!mm && mm_state->head != &mm_list->fifo) { + mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + + mm_state->head = mm_state->head->next; + + /* full scan for those added after the last iteration */ + if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { + mm_state->tail = mm_state->head; + walk->full_scan = true; + } + + if (should_skip_mm(mm, walk)) + mm = NULL; + } + + if (mm_state->head == &mm_list->fifo) + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); +done: + if (*iter && !mm) + mm_state->nr_walkers--; + if (!*iter && mm) + mm_state->nr_walkers++; + + if (mm_state->nr_walkers) + last = false; + + if (mm && first) + reset_bloom_filter(lruvec, walk->max_seq + 1); + + if (*iter || last) + reset_mm_stats(lruvec, walk, last); + + spin_unlock(&mm_list->lock); + + *iter = mm; + + return last; +} + +static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) +{ + bool success = false; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + if (max_seq <= READ_ONCE(mm_state->seq)) + return false; + + spin_lock(&mm_list->lock); + + VM_BUG_ON(mm_state->seq + 1 < max_seq); + + if (max_seq > mm_state->seq && !mm_state->nr_walkers) { + VM_BUG_ON(mm_state->head && mm_state->head != &mm_list->fifo); + + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); + reset_mm_stats(lruvec, NULL, true); + success = true; + } + + spin_unlock(&mm_list->lock); + + return success; +} + +/****************************************************************************** + * refault feedback loop + ******************************************************************************/ + +/* + * A feedback loop based on Proportional-Integral-Derivative (PID) controller. + * + * The P term is refaulted/(evicted+protected) from a tier in the generation + * currently being evicted; the I term is the exponential moving average of the + * P term over the generations previously evicted, using the smoothing factor + * 1/2; the D term isn't supported. + * + * The setpoint (SP) is always the first tier of one type; the process variable + * (PV) is either any tier of the other type or any other tier of the same + * type. + * + * The error is the difference between the SP and the PV; the correction is + * turn off protection when SP>PV or turn on protection when SPlrugen; + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + pos->refaulted = lrugen->avg_refaulted[type][tier] + + atomic_long_read(&lrugen->refaulted[hist][type][tier]); + pos->total = lrugen->avg_total[type][tier] + + atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + pos->total += lrugen->protected[hist][type][tier - 1]; + pos->gain = gain; +} + +static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) +{ + int hist, tier; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; + unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; + + lockdep_assert_held(&lruvec_pgdat(lruvec)->lru_lock); + + if (!carryover && !clear) + return; + + hist = lru_hist_from_seq(seq); + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + if (carryover) { + unsigned long sum; + + sum = lrugen->avg_refaulted[type][tier] + + atomic_long_read(&lrugen->refaulted[hist][type][tier]); + WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); + + sum = lrugen->avg_total[type][tier] + + atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + sum += lrugen->protected[hist][type][tier - 1]; + WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); + } + + if (clear) { + atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); + atomic_long_set(&lrugen->evicted[hist][type][tier], 0); + if (tier) + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); + } + } +} + +static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) +{ + /* + * Return true if the PV has a limited number of refaults or a lower + * refaulted/total than the SP. + */ + return pv->refaulted < MIN_LRU_BATCH || + pv->refaulted * (sp->total + MIN_LRU_BATCH) * sp->gain <= + (sp->refaulted + 1) * pv->total * pv->gain; +} + +/****************************************************************************** + * the aging + ******************************************************************************/ + +static int page_update_gen(struct page *page, int gen) +{ + unsigned long old_flags, new_flags; + + VM_BUG_ON(gen >= MAX_NR_GENS); + VM_BUG_ON(!rcu_read_lock_held()); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + + /* for shrink_page_list() */ + if (!(new_flags & LRU_GEN_MASK)) { + new_flags |= BIT(PG_referenced); + continue; + } + + new_flags &= ~LRU_GEN_MASK; + new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + } while (new_flags != old_flags && + cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; +} + +static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) +{ + unsigned long old_flags, new_flags; + int type = page_is_file_lru(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + + do { + new_flags = old_flags = READ_ONCE(page->flags); + VM_BUG_ON_PAGE(!(new_flags & LRU_GEN_MASK), page); + + new_gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; + /* page_update_gen() has promoted this page? */ + if (new_gen >= 0 && new_gen != old_gen) + return new_gen; + + new_gen = (old_gen + 1) % MAX_NR_GENS; + + new_flags &= ~LRU_GEN_MASK; + new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; + new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); + /* for end_page_writeback() */ + if (reclaiming) + new_flags |= BIT(PG_reclaim); + } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); + + lru_gen_update_size(lruvec, page, old_gen, new_gen); + + return new_gen; +} + +static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, + int old_gen, int new_gen) +{ + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + int delta = thp_nr_pages(page); + + VM_BUG_ON(old_gen >= MAX_NR_GENS); + VM_BUG_ON(new_gen >= MAX_NR_GENS); + + walk->batched++; + + walk->nr_pages[old_gen][type][zone] -= delta; + walk->nr_pages[new_gen][type][zone] += delta; +} + +static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) +{ + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + walk->batched = 0; + + for_each_gen_type_zone(gen, type, zone) { + enum lru_list lru = type * LRU_INACTIVE_FILE; + int delta = walk->nr_pages[gen][type][zone]; + + if (!delta) + continue; + + walk->nr_pages[gen][type][zone] = 0; + WRITE_ONCE(lrugen->nr_pages[gen][type][zone], + lrugen->nr_pages[gen][type][zone] + delta); + + if (lru_gen_is_active(lruvec, gen)) + lru += LRU_ACTIVE; + __update_lru_size(lruvec, lru, zone, delta); + } +} + +static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *walk) +{ + struct address_space *mapping; + struct vm_area_struct *vma = walk->vma; + struct lru_gen_mm_walk *priv = walk->private; + + if (!vma_is_accessible(vma) || is_vm_hugetlb_page(vma) || + (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) || + vma == get_gate_vma(vma->vm_mm)) + return true; + + if (vma_is_anonymous(vma)) + return !priv->can_swap; + + if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) + return true; + + mapping = vma->vm_file->f_mapping; + if (mapping_unevictable(mapping)) + return true; + + /* check readpage to exclude special mappings like dax, etc. */ + return shmem_mapping(mapping) ? !priv->can_swap : !mapping->a_ops->readpage; +} + +/* + * Some userspace memory allocators map many single-page VMAs. Instead of + * returning back to the PGD table for each of such VMAs, finish an entire PMD + * table to reduce zigzags and improve cache performance. + */ +static bool get_next_vma(struct mm_walk *walk, unsigned long mask, unsigned long size, + unsigned long *start, unsigned long *end) +{ + unsigned long next = round_up(*end, size); + + VM_BUG_ON(mask & size); + VM_BUG_ON(*start >= *end); + VM_BUG_ON((next & mask) != (*start & mask)); + + while (walk->vma) { + if (next >= walk->vma->vm_end) { + walk->vma = walk->vma->vm_next; + continue; + } + + if ((next & mask) != (walk->vma->vm_start & mask)) + return false; + + if (should_skip_vma(walk->vma->vm_start, walk->vma->vm_end, walk)) { + walk->vma = walk->vma->vm_next; + continue; + } + + *start = max(next, walk->vma->vm_start); + next = (next | ~mask) + 1; + /* rounded-up boundaries can wrap to 0 */ + *end = next && next < walk->vma->vm_end ? next : walk->vma->vm_end; + + return true; + } + + return false; +} + +static bool suitable_to_scan(int total, int young) +{ + int n = clamp_t(int, cache_line_size() / sizeof(pte_t), 2, 8); + + /* suitable if the average number of young PTEs per cacheline is >=1 */ + return young * n >= total; +} + +static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pte_t *pte; + spinlock_t *ptl; + unsigned long addr; + int total = 0; + int young = 0; + struct lru_gen_mm_walk *priv = walk->private; + struct mem_cgroup *memcg = lruvec_memcg(priv->lruvec); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + int old_gen, new_gen = lru_gen_from_seq(priv->max_seq); + + VM_BUG_ON(pmd_leaf(*pmd)); + + ptl = pte_lockptr(walk->mm, pmd); + if (!spin_trylock(ptl)) + return false; + + arch_enter_lazy_mmu_mode(); + + pte = pte_offset_map(pmd, start & PMD_MASK); +restart: + for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) { + struct page *page; + unsigned long pfn = pte_pfn(pte[i]); + + VM_BUG_ON(addr < walk->vma->vm_start || addr >= walk->vma->vm_end); + + total++; + priv->mm_stats[MM_PTE_TOTAL]++; + + if (!pte_present(pte[i]) || is_zero_pfn(pfn)) + continue; + + if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) + continue; + + if (!pte_young(pte[i])) { + priv->mm_stats[MM_PTE_OLD]++; + continue; + } + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + page = compound_head(pfn_to_page(pfn)); + if (page_to_nid(page) != pgdat->node_id) + continue; + + if (page_memcg_rcu(page) != memcg) + continue; + + if (!ptep_test_and_clear_young(walk->vma, addr, pte + i)) + continue; + + young++; + priv->mm_stats[MM_PTE_YOUNG]++; + + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_update_gen(page, new_gen); + if (old_gen >= 0 && old_gen != new_gen) + update_batch_size(priv, page, old_gen, new_gen); + } + + if (i < PTRS_PER_PTE && get_next_vma(walk, PMD_MASK, PAGE_SIZE, &start, &end)) + goto restart; + + pte_unmap(pte); + + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); + + return suitable_to_scan(total, young); +} + +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) +static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, + struct mm_walk *walk, unsigned long *start) +{ + int i; + pmd_t *pmd; + spinlock_t *ptl; + struct lru_gen_mm_walk *priv = walk->private; + struct mem_cgroup *memcg = lruvec_memcg(priv->lruvec); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + int old_gen, new_gen = lru_gen_from_seq(priv->max_seq); + + VM_BUG_ON(pud_leaf(*pud)); + + /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ + if (*start == -1) { + *start = next; + return; + } + + i = next == -1 ? 0 : pmd_index(next) - pmd_index(*start); + if (i && i <= MIN_LRU_BATCH) { + __set_bit(i - 1, priv->bitmap); + return; + } + + pmd = pmd_offset(pud, *start); + + ptl = pmd_lockptr(walk->mm, pmd); + if (!spin_trylock(ptl)) + goto done; + + arch_enter_lazy_mmu_mode(); + + do { + struct page *page; + unsigned long pfn = pmd_pfn(pmd[i]); + unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; + + VM_BUG_ON(addr < vma->vm_start || addr >= vma->vm_end); + + if (!pmd_present(pmd[i]) || is_huge_zero_pmd(pmd[i])) + goto next; + + if (WARN_ON_ONCE(pmd_devmap(pmd[i]))) + goto next; + + if (!pmd_trans_huge(pmd[i])) { + if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && + get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; + } + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + goto next; + + page = pfn_to_page(pfn); + VM_BUG_ON_PAGE(PageTail(page), page); + if (page_to_nid(page) != pgdat->node_id) + goto next; + + if (page_memcg_rcu(page) != memcg) + goto next; + + if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) + goto next; + + priv->mm_stats[MM_PTE_YOUNG]++; + + if (pmd_dirty(pmd[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_update_gen(page, new_gen); + if (old_gen >= 0 && old_gen != new_gen) + update_batch_size(priv, page, old_gen, new_gen); +next: + i = i > MIN_LRU_BATCH ? 0 : + find_next_bit(priv->bitmap, MIN_LRU_BATCH, i) + 1; + } while (i <= MIN_LRU_BATCH); + + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); +done: + *start = -1; + bitmap_zero(priv->bitmap, MIN_LRU_BATCH); +} +#else +static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, + struct mm_walk *walk, unsigned long *start) +{ +} +#endif + +static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pmd_t *pmd; + unsigned long next; + unsigned long addr; + struct vm_area_struct *vma; + unsigned long pos = -1; + struct lru_gen_mm_walk *priv = walk->private; + + VM_BUG_ON(pud_leaf(*pud)); + + /* + * Finish an entire PMD in two passes: the first only reaches to PTE + * tables to avoid taking the PMD lock; the second, if necessary, takes + * the PMD lock to clear the accessed bit in PMD entries. + */ + pmd = pmd_offset(pud, start & PUD_MASK); +restart: + /* walk_pte_range() may call get_next_vma() */ + vma = walk->vma; + for (i = pmd_index(start), addr = start; addr != end; i++, addr = next) { + pmd_t val = pmd_read_atomic(pmd + i); + + /* for pmd_read_atomic() */ + barrier(); + + next = pmd_addr_end(addr, end); + + if (!pmd_present(val)) { + priv->mm_stats[MM_PTE_TOTAL]++; + continue; + } + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_trans_huge(val)) { + unsigned long pfn = pmd_pfn(val); + struct pglist_data *pgdat = lruvec_pgdat(priv->lruvec); + + priv->mm_stats[MM_PTE_TOTAL]++; + + if (is_huge_zero_pmd(val)) + continue; + + if (!pmd_young(val)) { + priv->mm_stats[MM_PTE_OLD]++; + continue; + } + + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + walk_pmd_range_locked(pud, addr, vma, walk, &pos); + continue; + } +#endif + priv->mm_stats[MM_PMD_TOTAL]++; + +#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG + if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { + if (!pmd_young(val)) + continue; + + walk_pmd_range_locked(pud, addr, vma, walk, &pos); + } +#endif + if (!priv->full_scan && !test_bloom_filter(priv->lruvec, priv->max_seq, pmd + i)) + continue; + + priv->mm_stats[MM_PMD_FOUND]++; + + if (!walk_pte_range(&val, addr, next, walk)) + continue; + + priv->mm_stats[MM_PMD_ADDED]++; + + /* carry over to the next generation */ + update_bloom_filter(priv->lruvec, priv->max_seq + 1, pmd + i); + } + + walk_pmd_range_locked(pud, -1, vma, walk, &pos); + + if (i < PTRS_PER_PMD && get_next_vma(walk, PUD_MASK, PMD_SIZE, &start, &end)) + goto restart; +} + +static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, + struct mm_walk *walk) +{ + int i; + pud_t *pud; + unsigned long addr; + unsigned long next; + struct lru_gen_mm_walk *priv = walk->private; + + VM_BUG_ON(p4d_leaf(*p4d)); + + pud = pud_offset(p4d, start & P4D_MASK); +restart: + for (i = pud_index(start), addr = start; addr != end; i++, addr = next) { + pud_t val = READ_ONCE(pud[i]); + + next = pud_addr_end(addr, end); + + if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) + continue; + + walk_pmd_range(&val, addr, next, walk); + + if (priv->batched >= MAX_LRU_BATCH) { + end = (addr | ~PUD_MASK) + 1; + goto done; + } + } + + if (i < PTRS_PER_PUD && get_next_vma(walk, P4D_MASK, PUD_SIZE, &start, &end)) + goto restart; + + end = round_up(end, P4D_SIZE); +done: + /* rounded-up boundaries can wrap to 0 */ + priv->next_addr = end && walk->vma ? max(end, walk->vma->vm_start) : 0; + + return -EAGAIN; +} + +static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_mm_walk *walk) +{ + static const struct mm_walk_ops mm_walk_ops = { + .test_walk = should_skip_vma, + .p4d_entry = walk_pud_range, + }; + + int err; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + walk->next_addr = FIRST_USER_ADDRESS; + + do { + err = -EBUSY; + + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + break; + + /* the caller might be holding the lock for write */ + if (mmap_read_trylock(mm)) { + unsigned long start = walk->next_addr; + unsigned long end = mm->highest_vm_end; + + err = walk_page_range(mm, start, end, &mm_walk_ops, walk); + + mmap_read_unlock(mm); + + if (walk->batched) { + spin_lock_irq(&pgdat->lru_lock); + reset_batch_size(lruvec, walk); + spin_unlock_irq(&pgdat->lru_lock); + } + } + + mem_cgroup_unlock_pages(); + + cond_resched(); + } while (err == -EAGAIN && walk->next_addr && !mm_is_oom_victim(mm)); +} + +static struct lru_gen_mm_walk *alloc_mm_walk(void) +{ + if (current->reclaim_state && current->reclaim_state->mm_walk) + return current->reclaim_state->mm_walk; + + return kzalloc(sizeof(struct lru_gen_mm_walk), + __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); +} + +static void free_mm_walk(struct lru_gen_mm_walk *walk) +{ + if (!current->reclaim_state || !current->reclaim_state->mm_walk) + kfree(walk); +} + +static void inc_min_seq(struct lruvec *lruvec) +{ + int type; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(!seq_is_valid(lruvec)); + + for (type = 0; type < ANON_AND_FILE; type++) { + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; + + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); + } +} + +static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +{ + int gen, type, zone; + bool success = false; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + DEFINE_MIN_SEQ(lruvec); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + while (min_seq[type] + MIN_NR_GENS <= lrugen->max_seq) { + gen = lru_gen_from_seq(min_seq[type]); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) { + if (!list_empty(&lrugen->lists[gen][type][zone])) + goto next; + } + + min_seq[type]++; + } +next: + ; + } + + /* see the comment on lru_gen_struct */ + if (can_swap) { + min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); + min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); + } + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + if (min_seq[type] == lrugen->min_seq[type]) + continue; + + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); + success = true; + } + + return success; +} + +static void inc_max_seq(struct lruvec *lruvec) +{ + int prev, next; + int type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock_irq(&pgdat->lru_lock); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + inc_min_seq(lruvec); + + /* + * Update the active/inactive LRU sizes for compatibility. Both sides of + * the current max_seq need to be covered, since max_seq+1 can overlap + * with min_seq[LRU_GEN_ANON] if swapping is constrained. And if they do + * overlap, cold/hot inversion happens. This can be solved by moving + * pages from min_seq to min_seq+1 but is omitted for simplicity. + */ + prev = lru_gen_from_seq(lrugen->max_seq - 1); + next = lru_gen_from_seq(lrugen->max_seq + 1); + + for (type = 0; type < ANON_AND_FILE; type++) { + for (zone = 0; zone < MAX_NR_ZONES; zone++) { + enum lru_list lru = type * LRU_INACTIVE_FILE; + long delta = lrugen->nr_pages[prev][type][zone] - + lrugen->nr_pages[next][type][zone]; + + if (!delta) + continue; + + WARN_ON_ONCE(delta != (int)delta); + + __update_lru_size(lruvec, lru, zone, delta); + __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); + } + } + + for (type = 0; type < ANON_AND_FILE; type++) + reset_ctrl_pos(lruvec, type, false); + + WRITE_ONCE(lrugen->timestamps[next], jiffies); + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); + + spin_unlock_irq(&pgdat->lru_lock); +} + +static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + struct scan_control *sc, bool can_swap, bool full_scan) +{ + bool success; + struct lru_gen_mm_walk *walk; + struct mm_struct *mm = NULL; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON(max_seq > READ_ONCE(lrugen->max_seq)); + + /* + * If the hardware doesn't automatically set the accessed bit, fallback + * to lru_gen_look_around(), which only clears the accessed bit in a + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ + if (!full_scan && (!arch_has_hw_pte_young() || !get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } + + walk = alloc_mm_walk(); + if (!walk) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } + + walk->lruvec = lruvec; + walk->max_seq = max_seq; + walk->can_swap = can_swap; + walk->full_scan = full_scan; + + do { + success = iterate_mm_list(lruvec, walk, &mm); + if (mm) + walk_mm(lruvec, mm, walk); + + cond_resched(); + } while (mm); + + free_mm_walk(walk); +done: + if (!success) { + if (!current_is_kswapd() && !sc->priority) + wait_event_killable(lruvec->mm_state.wait, + max_seq < READ_ONCE(lrugen->max_seq)); + + return max_seq < READ_ONCE(lrugen->max_seq); + } + + VM_BUG_ON(max_seq != READ_ONCE(lrugen->max_seq)); + + inc_max_seq(lruvec); + /* either this sees any waiters or they will see updated max_seq */ + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); + + wakeup_flusher_threads(WB_REASON_VMSCAN); + + return true; +} + +static long get_nr_evictable(struct lruvec *lruvec, unsigned long max_seq, + unsigned long *min_seq, bool can_swap, bool *need_aging) +{ + int gen, type, zone; + long old = 0; + long young = 0; + long total = 0; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + unsigned long seq; + + for (seq = min_seq[type]; seq <= max_seq; seq++) { + long size = 0; + + gen = lru_gen_from_seq(seq); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) + size += READ_ONCE(lrugen->nr_pages[gen][type][zone]); + + total += size; + if (seq == max_seq) + young += size; + if (seq + MIN_NR_GENS == max_seq) + old += size; + } + } + + /* + * The aging and the eviction is a typical producer-consumer model. The + * aging tries to be lazy to reduce the unnecessary overhead. On the + * other hand, the eviction stalls when the number of generations + * reaches MIN_NR_GENS. So ideally, there should be MIN_NR_GENS+1 + * generations, hence the first two if's. + * + * In addition, it's ideal to spread pages out evenly, meaning + * 1/(MIN_NR_GENS+1) of the total number of pages for each generation. A + * reasonable range for this average portion would [1/MIN_NR_GENS, + * 1/(MIN_NR_GENS+2)]. From the consumer's POV, the eviction only cares + * about the lower bound of cold pages, i.e., 1/(MIN_NR_GENS+2), whereas + * from the producer's POV, the aging only cares about the upper bound + * of hot pages, i.e., 1/MIN_NR_GENS. + */ + if (min_seq[LRU_GEN_FILE] + MIN_NR_GENS > max_seq) + *need_aging = true; + else if (min_seq[LRU_GEN_FILE] + MIN_NR_GENS < max_seq) + *need_aging = false; + else if (young * MIN_NR_GENS > total) + *need_aging = true; + else if (old * (MIN_NR_GENS + 2) < total) + *need_aging = true; + else + *need_aging = false; + + return total > 0 ? total : 0; +} + +static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, + unsigned long min_ttl) +{ + bool need_aging; + long nr_to_scan; + int swappiness = get_swappiness(lruvec, sc); + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (min_ttl) { + int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); + unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + + if (time_is_after_jiffies(birth + min_ttl)) + return false; + } + + mem_cgroup_calculate_protection(NULL, memcg); + + if (mem_cgroup_below_min(memcg)) + return false; + + nr_to_scan = get_nr_evictable(lruvec, max_seq, min_seq, swappiness, &need_aging); + if (!nr_to_scan) + return false; + + nr_to_scan >>= sc->priority; + + if (!mem_cgroup_online(memcg)) + nr_to_scan++; + + if (nr_to_scan && need_aging && (!mem_cgroup_below_low(memcg) || sc->memcg_low_reclaim)) + try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); + + return true; +} + +/* to protect the working set of the last N jiffies */ +static unsigned long lru_gen_min_ttl __read_mostly; + +static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +{ + struct mem_cgroup *memcg; + bool success = false; + unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_BUG_ON(!current_is_kswapd()); + + /* + * To reduce the chance of going into the aging path or swapping, which + * can be costly, optimistically skip them unless their corresponding + * flags were cleared in the eviction path. This improves the overall + * performance when multiple memcgs are available. + */ + if (!sc->memcgs_need_aging) { + sc->memcgs_need_aging = true; + sc->memcgs_avoid_swapping = !sc->memcgs_need_swapping; + sc->memcgs_need_swapping = true; + return; + } + + sc->memcgs_need_swapping = true; + sc->memcgs_avoid_swapping = true; + + current->reclaim_state->mm_walk = &pgdat->mm_walk; + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + + if (age_lruvec(lruvec, sc, min_ttl)) + success = true; + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + current->reclaim_state->mm_walk = NULL; + + /* + * The main goal is to OOM kill if every generation from all memcgs is + * younger than min_ttl. However, another theoretical possibility is all + * memcgs are either below min or empty. + */ + if (!success && mutex_trylock(&oom_lock)) { + struct oom_control oc = { + .gfp_mask = sc->gfp_mask, + .order = sc->order, + }; + + out_of_memory(&oc); + + mutex_unlock(&oom_lock); + } +} + +/* + * This function exploits spatial locality when shrink_page_list() walks the + * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. + * If the scan was done cacheline efficiently, it adds the PMD entry pointing + * to the PTE table to the Bloom filter. This process is a feedback loop from + * the eviction to the aging. + */ +void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +{ + int i; + pte_t *pte; + unsigned long start; + unsigned long end; + unsigned long addr; + struct page *page; + struct lru_gen_mm_walk *walk; + int young = 0; + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; + struct mem_cgroup *memcg = page_memcg(pvmw->page); + struct pglist_data *pgdat = page_pgdat(pvmw->page); + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + DEFINE_MAX_SEQ(lruvec); + int old_gen, new_gen = lru_gen_from_seq(max_seq); + + lockdep_assert_held(pvmw->ptl); + VM_BUG_ON_PAGE(PageLRU(pvmw->page), pvmw->page); + + if (spin_is_contended(pvmw->ptl)) + return; + + start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); + end = pmd_addr_end(pvmw->address, pvmw->vma->vm_end); + + if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { + if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) + end = start + MIN_LRU_BATCH * PAGE_SIZE; + else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) + start = end - MIN_LRU_BATCH * PAGE_SIZE; + else { + start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; + end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; + } + } + + pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; + + rcu_read_lock(); + arch_enter_lazy_mmu_mode(); + + for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { + unsigned long pfn = pte_pfn(pte[i]); + + VM_BUG_ON(addr < pvmw->vma->vm_start || addr >= pvmw->vma->vm_end); + + if (!pte_present(pte[i]) || is_zero_pfn(pfn)) + continue; + + if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) + continue; + + if (!pte_young(pte[i])) + continue; + + VM_BUG_ON(!pfn_valid(pfn)); + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + + page = compound_head(pfn_to_page(pfn)); + if (page_to_nid(page) != pgdat->node_id) + continue; + + if (page_memcg_rcu(page) != memcg) + continue; + + if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) + continue; + + young++; + + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) + set_page_dirty(page); + + old_gen = page_lru_gen(page); + if (old_gen < 0) + SetPageReferenced(page); + else if (old_gen != new_gen) + __set_bit(i, bitmap); + } + + arch_leave_lazy_mmu_mode(); + rcu_read_unlock(); + + /* feedback from rmap walkers to page table walkers */ + if (suitable_to_scan(i, young)) + update_bloom_filter(lruvec, max_seq, pvmw->pmd); + + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + + if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) + activate_page(pte_page(pte[i])); + return; + } + + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + return; + + if (!walk) { + spin_lock_irq(&pgdat->lru_lock); + new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); + } + + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = compound_head(pte_page(pte[i])); + if (page_memcg_rcu(page) != memcg) + continue; + + old_gen = page_update_gen(page, new_gen); + if (old_gen < 0 || old_gen == new_gen) + continue; + + if (walk) + update_batch_size(walk, page, old_gen, new_gen); + else + lru_gen_update_size(lruvec, page, old_gen, new_gen); + } + + if (!walk) + spin_unlock_irq(&pgdat->lru_lock); + + mem_cgroup_unlock_pages(); +} + +/****************************************************************************** + * the eviction + ******************************************************************************/ + +static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +{ + bool success; + int gen = page_lru_gen(page); + int type = page_is_file_lru(page); + int zone = page_zonenum(page); + int tier = page_lru_tier(page); + int delta = thp_nr_pages(page); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + VM_BUG_ON_PAGE(gen >= MAX_NR_GENS, page); + + if (!page_evictable(page)) { + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + SetPageUnevictable(page); + add_page_to_lru_list(page, lruvec); + __count_vm_events(UNEVICTABLE_PGCULLED, delta); + return true; + } + + if (type == LRU_GEN_FILE && PageAnon(page) && PageDirty(page)) { + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + SetPageSwapBacked(page); + add_page_to_lru_list_tail(page, lruvec); + return true; + } + + if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { + list_move(&page->lru, &lrugen->lists[gen][type][zone]); + return true; + } + + if (tier > tier_idx) { + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + gen = page_inc_gen(lruvec, page, false); + list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); + + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], + lrugen->protected[hist][type][tier - 1] + delta); + __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta); + return true; + } + + if (PageLocked(page) || PageWriteback(page) || + (type == LRU_GEN_FILE && PageDirty(page))) { + gen = page_inc_gen(lruvec, page, true); + list_move(&page->lru, &lrugen->lists[gen][type][zone]); + return true; + } + + return false; +} + +static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_control *sc) +{ + bool success; + + if (!sc->may_unmap && page_mapped(page)) + return false; + + if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && + (PageDirty(page) || (PageAnon(page) && !PageSwapCache(page)))) + return false; + + if (!get_page_unless_zero(page)) + return false; + + ClearPageLRU(page); + + success = lru_gen_del_page(lruvec, page, true); + VM_BUG_ON_PAGE(!success, page); + + return true; +} + +static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, + int type, int tier, struct list_head *list) +{ + int gen, zone; + enum vm_event_item item; + int sorted = 0; + int scanned = 0; + int isolated = 0; + int remaining = MAX_LRU_BATCH; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + VM_BUG_ON(!list_empty(list)); + + if (get_nr_gens(lruvec, type) == MIN_NR_GENS) + return 0; + + gen = lru_gen_from_seq(lrugen->min_seq[type]); + + for (zone = sc->reclaim_idx; zone >= 0; zone--) { + LIST_HEAD(moved); + int skipped = 0; + struct list_head *head = &lrugen->lists[gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); + int delta = thp_nr_pages(page); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); + VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); + + prefetchw_prev_lru_page(page, head, flags); + + scanned += delta; + + if (sort_page(lruvec, page, tier)) + sorted += delta; + else if (isolate_page(lruvec, page, sc)) { + list_add(&page->lru, list); + isolated += delta; + } else { + list_move(&page->lru, &moved); + skipped += delta; + } + + if (!--remaining || max(isolated, skipped) >= MIN_LRU_BATCH) + break; + } + + if (skipped) { + list_splice(&moved, head); + __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); + } + + if (!remaining || isolated >= MIN_LRU_BATCH) + break; + } + + item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; + if (!cgroup_reclaim(sc)) { + __count_vm_events(item, isolated); + __count_vm_events(PGREFILL, sorted); + } + __count_memcg_events(memcg, item, isolated); + __count_memcg_events(memcg, PGREFILL, sorted); + __count_vm_events(PGSCAN_ANON + type, isolated); + + /* + * There might not be eligible pages due to reclaim_idx, may_unmap and + * may_writepage. Check the remaining to prevent livelock if there is no + * progress. + */ + return isolated || !remaining ? scanned : 0; +} + +static int get_tier_idx(struct lruvec *lruvec, int type) +{ + int tier; + struct ctrl_pos sp, pv; + + /* + * To leave a margin for fluctuations, use a larger gain factor (1:2). + * This value is chosen because any other tier would have at least twice + * as many refaults as the first tier. + */ + read_ctrl_pos(lruvec, type, 0, 1, &sp); + for (tier = 1; tier < MAX_NR_TIERS; tier++) { + read_ctrl_pos(lruvec, type, tier, 2, &pv); + if (!positive_ctrl_err(&sp, &pv)) + break; + } + + return tier - 1; +} + +static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) +{ + int type, tier; + struct ctrl_pos sp, pv; + int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; + + /* + * Compare the first tier of anon with that of file to determine which + * type to scan. Also need to compare other tiers of the selected type + * with the first tier of the other type to determine the last tier (of + * the selected type) to evict. + */ + read_ctrl_pos(lruvec, LRU_GEN_ANON, 0, gain[LRU_GEN_ANON], &sp); + read_ctrl_pos(lruvec, LRU_GEN_FILE, 0, gain[LRU_GEN_FILE], &pv); + type = positive_ctrl_err(&sp, &pv); + + read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); + for (tier = 1; tier < MAX_NR_TIERS; tier++) { + read_ctrl_pos(lruvec, type, tier, gain[type], &pv); + if (!positive_ctrl_err(&sp, &pv)) + break; + } + + *tier_idx = tier - 1; + + return type; +} + +static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, + int *type_scanned, struct list_head *list) +{ + int i; + int type; + int scanned; + int tier = -1; + DEFINE_MIN_SEQ(lruvec); + + VM_BUG_ON(!seq_is_valid(lruvec)); + + /* + * Try to make the obvious choice first. When anon and file are both + * available from the same generation, interpret swappiness 1 as file + * first and 200 as anon first. + */ + if (!swappiness) + type = LRU_GEN_FILE; + else if (min_seq[LRU_GEN_ANON] < min_seq[LRU_GEN_FILE]) + type = LRU_GEN_ANON; + else if (swappiness == 1) + type = LRU_GEN_FILE; + else if (swappiness == 200) + type = LRU_GEN_ANON; + else + type = get_type_to_scan(lruvec, swappiness, &tier); + + for (i = !swappiness; i < ANON_AND_FILE; i++) { + if (tier < 0) + tier = get_tier_idx(lruvec, type); + + scanned = scan_pages(lruvec, sc, type, tier, list); + if (scanned) + break; + + type = !type; + tier = -1; + } + + *type_scanned = type; + + return scanned; +} + +static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, + bool *swapped) +{ + int type; + int scanned; + int reclaimed; + LIST_HEAD(list); + struct page *page; + enum vm_event_item item; + struct reclaim_stat stat; + struct lru_gen_mm_walk *walk; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock_irq(&pgdat->lru_lock); + + scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); + + if (try_to_inc_min_seq(lruvec, swappiness)) + scanned++; + + if (get_nr_gens(lruvec, LRU_GEN_FILE) == MIN_NR_GENS) + scanned = 0; + + spin_unlock_irq(&pgdat->lru_lock); + + if (list_empty(&list)) + return scanned; + + reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); + + /* + * To avoid livelock, don't add rejected pages back to the same lists + * they were isolated from. See lru_gen_add_page(). + */ + list_for_each_entry(page, &list, lru) { + ClearPageReferenced(page); + ClearPageWorkingset(page); + + if (PageReclaim(page) && (PageDirty(page) || PageWriteback(page))) + ClearPageActive(page); + else + SetPageActive(page); + } + + spin_lock_irq(&pgdat->lru_lock); + + move_pages_to_lru(lruvec, &list); + + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + if (walk && walk->batched) + reset_batch_size(lruvec, walk); + + item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; + if (!cgroup_reclaim(sc)) + __count_vm_events(item, reclaimed); + __count_memcg_events(memcg, item, reclaimed); + __count_vm_events(PGSTEAL_ANON + type, reclaimed); + + spin_unlock_irq(&pgdat->lru_lock); + + mem_cgroup_uncharge_list(&list); + free_unref_page_list(&list); + + sc->nr_reclaimed += reclaimed; + + if (type == LRU_GEN_ANON && swapped) + *swapped = true; + + return scanned; +} + +static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool can_swap) +{ + bool need_aging; + long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (mem_cgroup_below_min(memcg) || + (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) + return 0; + + nr_to_scan = get_nr_evictable(lruvec, max_seq, min_seq, can_swap, &need_aging); + if (!nr_to_scan) + return 0; + + /* reset the priority if the target has been met */ + nr_to_scan >>= sc->nr_reclaimed < sc->nr_to_reclaim ? sc->priority : DEF_PRIORITY; + + if (!mem_cgroup_online(memcg)) + nr_to_scan++; + + if (!nr_to_scan) + return 0; + + if (!need_aging) { + sc->memcgs_need_aging = false; + return nr_to_scan; + } + + /* leave the work to lru_gen_age_node() */ + if (current_is_kswapd()) + return 0; + + /* try other memcgs before going to the aging path */ + if (!cgroup_reclaim(sc) && !sc->force_deactivate) { + sc->skipped_deactivate = true; + return 0; + } + + if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) + return nr_to_scan; + + return min_seq[LRU_GEN_FILE] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; +} + +static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ + struct blk_plug plug; + long scanned = 0; + bool swapped = false; + unsigned long reclaimed = sc->nr_reclaimed; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + lru_add_drain(); + + blk_start_plug(&plug); + + if (current_is_kswapd()) + current->reclaim_state->mm_walk = &pgdat->mm_walk; + + while (true) { + int delta; + int swappiness; + long nr_to_scan; + + if (sc->may_swap) + swappiness = get_swappiness(lruvec, sc); + else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) + swappiness = 1; + else + swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); + if (!nr_to_scan) + break; + + delta = evict_pages(lruvec, sc, swappiness, &swapped); + if (!delta) + break; + + if (sc->memcgs_avoid_swapping && swappiness < 200 && swapped) + break; + + scanned += delta; + if (scanned >= nr_to_scan) { + if (!swapped && sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH) + sc->memcgs_need_swapping = false; + break; + } + + cond_resched(); + } + + if (current_is_kswapd()) + current->reclaim_state->mm_walk = NULL; + + blk_finish_plug(&plug); +} + +/****************************************************************************** + * state change + ******************************************************************************/ + +static bool __maybe_unused state_is_valid(struct lruvec *lruvec) +{ + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + if (lrugen->enabled) { + enum lru_list lru; + + for_each_evictable_lru(lru) { + if (!list_empty(&lruvec->lists[lru])) + return false; + } + } else { + int gen, type, zone; + + for_each_gen_type_zone(gen, type, zone) { + if (!list_empty(&lrugen->lists[gen][type][zone])) + return false; + + /* unlikely but not a bug when reset_batch_size() is pending */ + VM_WARN_ON(lrugen->nr_pages[gen][type][zone]); + } + } + + return true; +} + +static bool fill_evictable(struct lruvec *lruvec) +{ + enum lru_list lru; + int remaining = MAX_LRU_BATCH; + + for_each_evictable_lru(lru) { + int type = is_file_lru(lru); + bool active = is_active_lru(lru); + struct list_head *head = &lruvec->lists[lru]; + + while (!list_empty(head)) { + bool success; + struct page *page = lru_to_page(head); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page) != active, page); + VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); + VM_BUG_ON_PAGE(page_lru_gen(page) < MAX_NR_GENS, page); + + prefetchw_prev_lru_page(page, head, flags); + + del_page_from_lru_list(page, lruvec); + success = lru_gen_add_page(lruvec, page, false); + VM_BUG_ON(!success); + + if (!--remaining) + return false; + } + } + + return true; +} + +static bool drain_evictable(struct lruvec *lruvec) +{ + int gen, type, zone; + int remaining = MAX_LRU_BATCH; + + for_each_gen_type_zone(gen, type, zone) { + struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; + + while (!list_empty(head)) { + bool success; + struct page *page = lru_to_page(head); + + VM_BUG_ON_PAGE(PageTail(page), page); + VM_BUG_ON_PAGE(PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageActive(page), page); + VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); + VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); + + prefetchw_prev_lru_page(page, head, flags); + + success = lru_gen_del_page(lruvec, page, false); + VM_BUG_ON(!success); + add_page_to_lru_list(page, lruvec); + + if (!--remaining) + return false; + } + } + + return true; +} + +static void lru_gen_change_state(bool enable) +{ + static DEFINE_MUTEX(state_mutex); + + struct mem_cgroup *memcg; + + cgroup_lock(); + cpus_read_lock(); + get_online_mems(); + mutex_lock(&state_mutex); + + if (enable == lru_gen_enabled()) + goto unlock; + + if (enable) + static_branch_enable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); + else + static_branch_disable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + int nid; + + for_each_node(nid) { + struct pglist_data *pgdat = NODE_DATA(nid); + struct lruvec *lruvec = get_lruvec(memcg, nid); + + if (!lruvec) + continue; + + if (!pgdat) { + lruvec->lrugen.enabled = enable; + continue; + } + + spin_lock_irq(&pgdat->lru_lock); + + VM_BUG_ON(!seq_is_valid(lruvec)); + VM_BUG_ON(!state_is_valid(lruvec)); + + lruvec->lrugen.enabled = enable; + + while (!(enable ? fill_evictable(lruvec) : drain_evictable(lruvec))) { + spin_unlock_irq(&pgdat->lru_lock); + cond_resched(); + spin_lock_irq(&pgdat->lru_lock); + } + + spin_unlock_irq(&pgdat->lru_lock); + } + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); +unlock: + mutex_unlock(&state_mutex); + put_online_mems(); + cpus_read_unlock(); + cgroup_unlock(); +} + +/****************************************************************************** + * sysfs interface + ******************************************************************************/ + +static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); +} + +static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t len) +{ + unsigned int msecs; + + if (kstrtouint(buf, 0, &msecs)) + return -EINVAL; + + WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); + + return len; +} + +static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( + min_ttl_ms, 0644, show_min_ttl, store_min_ttl +); + +static ssize_t show_enable(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + unsigned int caps = 0; + + if (get_cap(LRU_GEN_CORE)) + caps |= BIT(LRU_GEN_CORE); + + if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) + caps |= BIT(LRU_GEN_MM_WALK); + + if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) + caps |= BIT(LRU_GEN_NONLEAF_YOUNG); + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); +} + +static ssize_t store_enable(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t len) +{ + int i; + unsigned int caps; + + if (tolower(*buf) == 'n') + caps = 0; + else if (tolower(*buf) == 'y') + caps = -1; + else if (kstrtouint(buf, 0, &caps)) + return -EINVAL; + + for (i = 0; i < NR_LRU_GEN_CAPS; i++) { + bool enable = caps & BIT(i); + + if (i == LRU_GEN_CORE) + lru_gen_change_state(enable); + else if (enable) + static_branch_enable(&lru_gen_caps[i]); + else + static_branch_disable(&lru_gen_caps[i]); + } + + return len; +} + +static struct kobj_attribute lru_gen_enabled_attr = __ATTR( + enabled, 0644, show_enable, store_enable +); + +static struct attribute *lru_gen_attrs[] = { + &lru_gen_min_ttl_attr.attr, + &lru_gen_enabled_attr.attr, + NULL +}; + +static struct attribute_group lru_gen_attr_group = { + .name = "lru_gen", + .attrs = lru_gen_attrs, +}; + +/****************************************************************************** + * debugfs interface + ******************************************************************************/ + +static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) +{ + struct mem_cgroup *memcg; + loff_t nr_to_skip = *pos; + + m->private = kvmalloc(PATH_MAX, GFP_KERNEL); + if (!m->private) + return ERR_PTR(-ENOMEM); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + int nid; + + for_each_node_state(nid, N_MEMORY) { + if (!nr_to_skip--) + return get_lruvec(memcg, nid); + } + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + return NULL; +} + +static void lru_gen_seq_stop(struct seq_file *m, void *v) +{ + if (!IS_ERR_OR_NULL(v)) + mem_cgroup_iter_break(NULL, lruvec_memcg(v)); + + kvfree(m->private); + m->private = NULL; +} + +static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + int nid = lruvec_pgdat(v)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(v); + + ++*pos; + + nid = next_memory_node(nid); + if (nid == MAX_NUMNODES) { + memcg = mem_cgroup_iter(NULL, memcg, NULL); + if (!memcg) + return NULL; + + nid = first_memory_node; + } + + return get_lruvec(memcg, nid); +} + +static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, + unsigned long max_seq, unsigned long *min_seq, + unsigned long seq) +{ + int i; + int type, tier; + int hist = lru_hist_from_seq(seq); + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + seq_printf(m, " %10d", tier); + for (type = 0; type < ANON_AND_FILE; type++) { + unsigned long n[3] = {}; + + if (seq == max_seq) { + n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); + n[1] = READ_ONCE(lrugen->avg_total[type][tier]); + + seq_printf(m, " %10luR %10luT %10lu ", n[0], n[1], n[2]); + } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { + n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); + n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); + if (tier) + n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); + + seq_printf(m, " %10lur %10lue %10lup", n[0], n[1], n[2]); + } else + seq_puts(m, " 0 0 0 "); + } + seq_putc(m, '\n'); + } + + seq_puts(m, " "); + for (i = 0; i < NR_MM_STATS; i++) { + if (seq == max_seq && NR_HIST_GENS == 1) + seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_state.stats[hist][i]), + toupper(MM_STAT_CODES[i])); + else if (seq != max_seq && NR_HIST_GENS > 1) + seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_state.stats[hist][i]), + MM_STAT_CODES[i]); + else + seq_puts(m, " 0 "); + } + seq_putc(m, '\n'); +} + +static int lru_gen_seq_show(struct seq_file *m, void *v) +{ + unsigned long seq; + bool full = !debugfs_real_fops(m->file)->write; + struct lruvec *lruvec = v; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + int nid = lruvec_pgdat(lruvec)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + + if (nid == first_memory_node) { + const char *path = memcg ? m->private : ""; + +#ifdef CONFIG_MEMCG + if (memcg) + cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); +#endif + seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); + } + + seq_printf(m, " node %5d\n", nid); + + if (!full) + seq = min_seq[LRU_GEN_ANON]; + else if (max_seq >= MAX_NR_GENS) + seq = max_seq - MAX_NR_GENS + 1; + else + seq = 0; + + for (; seq <= max_seq; seq++) { + int type, zone; + int gen = lru_gen_from_seq(seq); + unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + + seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - birth)); + + for (type = 0; type < ANON_AND_FILE; type++) { + long size = 0; + char mark = full && seq < min_seq[type] ? 'x' : ' '; + + for (zone = 0; zone < MAX_NR_ZONES; zone++) + size += READ_ONCE(lrugen->nr_pages[gen][type][zone]); + + seq_printf(m, " %10lu%c", max(size, 0L), mark); + } + + seq_putc(m, '\n'); + + if (full) + lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); + } + + return 0; +} + +static const struct seq_operations lru_gen_seq_ops = { + .start = lru_gen_seq_start, + .stop = lru_gen_seq_stop, + .next = lru_gen_seq_next, + .show = lru_gen_seq_show, +}; + +static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, + bool can_swap, bool full_scan) +{ + DEFINE_MAX_SEQ(lruvec); + + if (seq == max_seq) + try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, full_scan); + + return seq > max_seq ? -EINVAL : 0; +} + +static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, + int swappiness, unsigned long nr_to_reclaim) +{ + struct blk_plug plug; + int err = -EINTR; + DEFINE_MAX_SEQ(lruvec); + + if (seq + MIN_NR_GENS > max_seq) + return -EINVAL; + + sc->nr_reclaimed = 0; + + blk_start_plug(&plug); + + while (!signal_pending(current)) { + DEFINE_MIN_SEQ(lruvec); + + if (seq < min_seq[!swappiness] || sc->nr_reclaimed >= nr_to_reclaim || + !evict_pages(lruvec, sc, swappiness, NULL)) { + err = 0; + break; + } + + cond_resched(); + } + + blk_finish_plug(&plug); + + return err; +} + +static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, + struct scan_control *sc, int swappiness, unsigned long opt) +{ + struct lruvec *lruvec; + int err = -EINVAL; + struct mem_cgroup *memcg = NULL; + + if (!mem_cgroup_disabled()) { + rcu_read_lock(); + memcg = mem_cgroup_from_id(memcg_id); +#ifdef CONFIG_MEMCG + if (memcg && !css_tryget(&memcg->css)) + memcg = NULL; +#endif + rcu_read_unlock(); + + if (!memcg) + goto done; + } + if (memcg_id != mem_cgroup_id(memcg)) + goto done; + + if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) + goto done; + + lruvec = get_lruvec(memcg, nid); + + if (swappiness < 0) + swappiness = get_swappiness(lruvec, sc); + else if (swappiness > 200) + goto done; + + switch (cmd) { + case '+': + err = run_aging(lruvec, seq, sc, swappiness, opt); + break; + case '-': + err = run_eviction(lruvec, seq, sc, swappiness, opt); + break; + } +done: + mem_cgroup_put(memcg); + + return err; +} + +static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, + size_t len, loff_t *pos) +{ + void *buf; + char *cur, *next; + unsigned int flags; + int err = 0; + struct scan_control sc = { + .may_writepage = true, + .may_unmap = true, + .may_swap = true, + .reclaim_idx = MAX_NR_ZONES - 1, + .gfp_mask = GFP_KERNEL, + }; + + buf = kvmalloc(len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, src, len)) { + kvfree(buf); + return -EFAULT; + } + + next = buf; + next[len] = '\0'; + + sc.reclaim_state.mm_walk = alloc_mm_walk(); + if (!sc.reclaim_state.mm_walk) { + kvfree(buf); + return -ENOMEM; + } + + set_task_reclaim_state(current, &sc.reclaim_state); + flags = memalloc_noreclaim_save(); + + while ((cur = strsep(&next, ",;\n"))) { + int n; + int end; + char cmd; + unsigned int memcg_id; + unsigned int nid; + unsigned long seq; + unsigned int swappiness = -1; + unsigned long opt = -1; + + cur = skip_spaces(cur); + if (!*cur) + continue; + + n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, + &seq, &end, &swappiness, &end, &opt, &end); + if (n < 4 || cur[end]) { + err = -EINVAL; + break; + } + + err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, opt); + if (err) + break; + } + + memalloc_noreclaim_restore(flags); + set_task_reclaim_state(current, NULL); + + free_mm_walk(sc.reclaim_state.mm_walk); + kvfree(buf); + + return err ? : len; +} + +static int lru_gen_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &lru_gen_seq_ops); +} + +static const struct file_operations lru_gen_rw_fops = { + .open = lru_gen_seq_open, + .read = seq_read, + .write = lru_gen_seq_write, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations lru_gen_ro_fops = { + .open = lru_gen_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/****************************************************************************** + * initialization + ******************************************************************************/ + +void lru_gen_init_lruvec(struct lruvec *lruvec) +{ + int i; + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); + + for (i = 0; i <= MIN_NR_GENS + 1; i++) + lrugen->timestamps[i] = jiffies; + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; + init_waitqueue_head(&lruvec->mm_state.wait); +} + +#ifdef CONFIG_MEMCG +void lru_gen_init_memcg(struct mem_cgroup *memcg) +{ + INIT_LIST_HEAD(&memcg->mm_list.fifo); + spin_lock_init(&memcg->mm_list.lock); +} + +void lru_gen_exit_memcg(struct mem_cgroup *memcg) +{ + int i; + int nid; + + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + + VM_BUG_ON(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); + + for (i = 0; i < NR_BLOOM_FILTERS; i++) { + bitmap_free(lruvec->mm_state.filters[i]); + lruvec->mm_state.filters[i] = NULL; + } + } +} +#endif + +static int __init init_lru_gen(void) +{ + BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); + BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); + BUILD_BUG_ON(sizeof(MM_STAT_CODES) != NR_MM_STATS + 1); + + if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) + pr_err("lru_gen: failed to create sysfs group\n"); + + debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); + debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); + + return 0; +}; +late_initcall(init_lru_gen); + +#else + +static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +{ +} + +static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ +} + +#endif /* CONFIG_LRU_GEN */ + +static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +{ + unsigned long nr[NR_LRU_LISTS]; + unsigned long targets[NR_LRU_LISTS]; + unsigned long nr_to_scan; + enum lru_list lru; + unsigned long nr_reclaimed = 0; + unsigned long nr_to_reclaim = sc->nr_to_reclaim; + struct blk_plug plug; + bool scan_adjusted; + + if (lru_gen_enabled()) { + lru_gen_shrink_lruvec(lruvec, sc); + return; + } + + get_scan_count(lruvec, sc, nr); + + /* Record the original scan target for proportional adjustments later */ + memcpy(targets, nr, sizeof(nr)); + + /* + * Global reclaiming within direct reclaim at DEF_PRIORITY is a normal + * event that can occur when there is little memory pressure e.g. + * multiple streaming readers/writers. Hence, we do not abort scanning + * when the requested number of pages are reclaimed when scanning at + * DEF_PRIORITY on the assumption that the fact we are direct + * reclaiming implies that kswapd is not keeping up and it is best to + * do a batch of work at once. For memcg reclaim one check is made to + * abort proportional reclaim if either the file or anon lru has already + * dropped to zero at the first pass. + */ + scan_adjusted = (!cgroup_reclaim(sc) && !current_is_kswapd() && + sc->priority == DEF_PRIORITY); + + blk_start_plug(&plug); + while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || + nr[LRU_INACTIVE_FILE]) { + unsigned long nr_anon, nr_file, percentage; + unsigned long nr_scanned; + + for_each_evictable_lru(lru) { + if (nr[lru]) { + nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX); + nr[lru] -= nr_to_scan; + + nr_reclaimed += shrink_list(lru, nr_to_scan, + lruvec, sc); + } + } + + cond_resched(); + + if (nr_reclaimed < nr_to_reclaim || scan_adjusted) + continue; + + /* + * For kswapd and memcg, reclaim at least the number of pages + * requested. Ensure that the anon and file LRUs are scanned + * proportionally what was requested by get_scan_count(). We + * stop reclaiming one LRU and reduce the amount scanning + * proportional to the original scan target. + */ + nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE]; + nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON]; + + /* + * It's just vindictive to attack the larger once the smaller + * has gone to zero. And given the way we stop scanning the + * smaller below, this makes sure that we only make one nudge + * towards proportionality once we've got nr_to_reclaim. + */ + if (!nr_file || !nr_anon) + break; + + if (nr_file > nr_anon) { + unsigned long scan_target = targets[LRU_INACTIVE_ANON] + + targets[LRU_ACTIVE_ANON] + 1; + lru = LRU_BASE; + percentage = nr_anon * 100 / scan_target; + } else { + unsigned long scan_target = targets[LRU_INACTIVE_FILE] + + targets[LRU_ACTIVE_FILE] + 1; + lru = LRU_FILE; + percentage = nr_file * 100 / scan_target; + } + + /* Stop scanning the smaller of the LRU */ + nr[lru] = 0; + nr[lru + LRU_ACTIVE] = 0; + + /* + * Recalculate the other LRU scan count based on its original + * scan target and the percentage scanning already complete + */ + lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE; + nr_scanned = targets[lru] - nr[lru]; + nr[lru] = targets[lru] * (100 - percentage) / 100; + nr[lru] -= min(nr[lru], nr_scanned); + + lru += LRU_ACTIVE; + nr_scanned = targets[lru] - nr[lru]; + nr[lru] = targets[lru] * (100 - percentage) / 100; + nr[lru] -= min(nr[lru], nr_scanned); + + scan_adjusted = true; + } + blk_finish_plug(&plug); + sc->nr_reclaimed += nr_reclaimed; + + /* + * Even if we did not try to evict anon pages at all, we want to + * rebalance the anon lru active/inactive ratio. + */ + if (total_swap_pages && inactive_is_low(lruvec, LRU_INACTIVE_ANON)) + shrink_active_list(SWAP_CLUSTER_MAX, lruvec, + sc, LRU_ACTIVE_ANON); +} + +/* Use reclaim/compaction for costly allocs or under memory pressure */ +static bool in_reclaim_compaction(struct scan_control *sc) +{ + if (IS_ENABLED(CONFIG_COMPACTION) && sc->order && + (sc->order > PAGE_ALLOC_COSTLY_ORDER || + sc->priority < DEF_PRIORITY - 2)) + return true; + + return false; +} + +/* + * Reclaim/compaction is used for high-order allocation requests. It reclaims + * order-0 pages before compacting the zone. should_continue_reclaim() returns + * true if more pages should be reclaimed such that when the page allocator + * calls try_to_compact_pages() that it will have enough free pages to succeed. + * It will give up earlier than that if there is difficulty reclaiming pages. + */ +static inline bool should_continue_reclaim(struct pglist_data *pgdat, + unsigned long nr_reclaimed, + struct scan_control *sc) +{ + unsigned long pages_for_compaction; + unsigned long inactive_lru_pages; + int z; + + /* If not in reclaim/compaction mode, stop */ + if (!in_reclaim_compaction(sc)) + return false; + + /* + * Stop if we failed to reclaim any pages from the last SWAP_CLUSTER_MAX + * number of pages that were scanned. This will return to the caller + * with the risk reclaim/compaction and the resulting allocation attempt + * fails. In the past we have tried harder for __GFP_RETRY_MAYFAIL + * allocations through requiring that the full LRU list has been scanned + * first, by assuming that zero delta of sc->nr_scanned means full LRU + * scan, but that approximation was wrong, and there were corner cases * where always a non-zero amount of pages were scanned. */ if (!nr_reclaimed) @@ -2748,7 +5495,6 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) unsigned long nr_reclaimed, nr_scanned; struct lruvec *target_lruvec; bool reclaimable = false; - unsigned long file; target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); @@ -2758,93 +5504,7 @@ again: nr_reclaimed = sc->nr_reclaimed; nr_scanned = sc->nr_scanned; - /* - * Determine the scan balance between anon and file LRUs. - */ - spin_lock_irq(&pgdat->lru_lock); - sc->anon_cost = target_lruvec->anon_cost; - sc->file_cost = target_lruvec->file_cost; - spin_unlock_irq(&pgdat->lru_lock); - - /* - * Target desirable inactive:active list ratios for the anon - * and file LRU lists. - */ - if (!sc->force_deactivate) { - unsigned long refaults; - - refaults = lruvec_page_state(target_lruvec, - WORKINGSET_ACTIVATE_ANON); - if (refaults != target_lruvec->refaults[0] || - inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) - sc->may_deactivate |= DEACTIVATE_ANON; - else - sc->may_deactivate &= ~DEACTIVATE_ANON; - - /* - * When refaults are being observed, it means a new - * workingset is being established. Deactivate to get - * rid of any stale active pages quickly. - */ - refaults = lruvec_page_state(target_lruvec, - WORKINGSET_ACTIVATE_FILE); - if (refaults != target_lruvec->refaults[1] || - inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) - sc->may_deactivate |= DEACTIVATE_FILE; - else - sc->may_deactivate &= ~DEACTIVATE_FILE; - } else - sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; - - /* - * If we have plenty of inactive file pages that aren't - * thrashing, try to reclaim those first before touching - * anonymous pages. - */ - file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); - if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) - sc->cache_trim_mode = 1; - else - sc->cache_trim_mode = 0; - - /* - * Prevent the reclaimer from falling into the cache trap: as - * cache pages start out inactive, every cache fault will tip - * the scan balance towards the file LRU. And as the file LRU - * shrinks, so does the window for rotation from references. - * This means we have a runaway feedback loop where a tiny - * thrashing file LRU becomes infinitely more attractive than - * anon pages. Try to detect this based on file LRU size. - */ - if (!cgroup_reclaim(sc)) { - unsigned long total_high_wmark = 0; - unsigned long free, anon; - int z; - - free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); - file = node_page_state(pgdat, NR_ACTIVE_FILE) + - node_page_state(pgdat, NR_INACTIVE_FILE); - - for (z = 0; z < MAX_NR_ZONES; z++) { - struct zone *zone = &pgdat->node_zones[z]; - if (!managed_zone(zone)) - continue; - - total_high_wmark += high_wmark_pages(zone); - } - - /* - * Consider anon: if that's low too, this isn't a - * runaway file reclaim problem, but rather just - * extreme pressure. Reclaim as per usual then. - */ - anon = node_page_state(pgdat, NR_INACTIVE_ANON); - - sc->file_is_tiny = - file + free <= total_high_wmark && - !(sc->may_deactivate & DEACTIVATE_ANON) && - anon >> sc->priority; - } + prepare_scan_count(pgdat, sc); shrink_node_memcgs(pgdat, sc); @@ -3064,6 +5724,9 @@ static void snapshot_refaults(struct mem_cgroup *target_memcg, pg_data_t *pgdat) struct lruvec *target_lruvec; unsigned long refaults; + if (lru_gen_enabled()) + return; + target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); target_lruvec->refaults[0] = refaults; @@ -3439,6 +6102,11 @@ static void age_active_anon(struct pglist_data *pgdat, struct mem_cgroup *memcg; struct lruvec *lruvec; + if (lru_gen_enabled()) { + lru_gen_age_node(pgdat, sc); + return; + } + if (!total_swap_pages) return; @@ -4423,12 +7091,9 @@ void check_move_unevictable_pages(struct pagevec *pvec) continue; if (page_evictable(page)) { - enum lru_list lru = page_lru_base_type(page); - - VM_BUG_ON_PAGE(PageActive(page), page); + del_page_from_lru_list(page, lruvec); ClearPageUnevictable(page); - del_page_from_lru_list(page, lruvec, LRU_UNEVICTABLE); - add_page_to_lru_list(page, lruvec, lru); + add_page_to_lru_list(page, lruvec); pgrescued += nr_pages; } } diff --git a/mm/workingset.c b/mm/workingset.c index 975a4d2dd02eeb064a440e13cdce1cf1ee6a6c55..25eaab8811927073b348e2e917fcef66590bc89b 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -185,7 +185,6 @@ static unsigned int bucket_order __read_mostly; static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, bool workingset) { - eviction >>= bucket_order; eviction &= EVICTION_MASK; eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; eviction = (eviction << NODES_SHIFT) | pgdat->node_id; @@ -210,10 +209,116 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, *memcgidp = memcgid; *pgdat = NODE_DATA(nid); - *evictionp = entry << bucket_order; + *evictionp = entry; *workingsetp = workingset; } +#ifdef CONFIG_LRU_GEN + +static int page_lru_refs(struct page *page) +{ + unsigned long flags = READ_ONCE(page->flags); + + BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); + + /* see the comment on MAX_NR_TIERS */ + return flags & BIT(PG_workingset) ? (flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF : 0; +} + +static void *lru_gen_eviction(struct page *page) +{ + int hist, tier; + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; + struct lru_gen_struct *lrugen; + int type = page_is_file_lru(page); + int refs = page_lru_refs(page); + int delta = thp_nr_pages(page); + bool workingset = PageWorkingset(page); + struct mem_cgroup *memcg = page_memcg(page); + struct pglist_data *pgdat = page_pgdat(page); + + lruvec = mem_cgroup_lruvec(memcg, pgdat); + lrugen = &lruvec->lrugen; + min_seq = READ_ONCE(lrugen->min_seq[type]); + token = (min_seq << LRU_REFS_WIDTH) | refs; + + hist = lru_hist_from_seq(min_seq); + tier = lru_tier_from_refs(refs + workingset); + atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); + + return pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset); +} + +static void lru_gen_refault(struct page *page, void *shadow) +{ + int hist, tier, refs; + int memcg_id; + bool workingset; + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; + struct lru_gen_struct *lrugen; + struct mem_cgroup *memcg; + struct pglist_data *pgdat; + int type = page_is_file_lru(page); + int delta = thp_nr_pages(page); + + unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); + + refs = token & (BIT(LRU_REFS_WIDTH) - 1); + if (refs && !workingset) + return; + + if (page_pgdat(page) != pgdat) + return; + + rcu_read_lock(); + memcg = page_memcg_rcu(page); + if (mem_cgroup_id(memcg) != memcg_id) + goto unlock; + + token >>= LRU_REFS_WIDTH; + lruvec = mem_cgroup_lruvec(memcg, pgdat); + lrugen = &lruvec->lrugen; + min_seq = READ_ONCE(lrugen->min_seq[type]); + if (token != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) + goto unlock; + + hist = lru_hist_from_seq(min_seq); + tier = lru_tier_from_refs(refs + workingset); + atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); + mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta); + + /* + * Count the following two cases as stalls: + * 1. For pages accessed through page tables, hotter pages pushed out + * hot pages which refaulted immediately. + * 2. For pages accessed through file descriptors, numbers of accesses + * might have been beyond the limit. + */ + if (lru_gen_in_fault() || refs + workingset == BIT(LRU_REFS_WIDTH)) { + SetPageWorkingset(page); + mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta); + } +unlock: + rcu_read_unlock(); +} + +#else + +static void *lru_gen_eviction(struct page *page) +{ + return NULL; +} + +static void lru_gen_refault(struct page *page, void *shadow) +{ +} + +#endif /* CONFIG_LRU_GEN */ + /** * workingset_age_nonresident - age non-resident entries as LRU ages * @lruvec: the lruvec that was aged @@ -262,11 +367,15 @@ void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg) VM_BUG_ON_PAGE(page_count(page), page); VM_BUG_ON_PAGE(!PageLocked(page), page); + if (lru_gen_enabled()) + return lru_gen_eviction(page); + lruvec = mem_cgroup_lruvec(target_memcg, pgdat); workingset_age_nonresident(lruvec, thp_nr_pages(page)); /* XXX: target_memcg can be NULL, go through lruvec */ memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); eviction = atomic_long_read(&lruvec->nonresident_age); + eviction >>= bucket_order; return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); } @@ -294,7 +403,13 @@ void workingset_refault(struct page *page, void *shadow) bool workingset; int memcgid; + if (lru_gen_enabled()) { + lru_gen_refault(page, shadow); + return; + } + unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); + eviction <<= bucket_order; rcu_read_lock(); /* diff --git a/net/9p/mod.c b/net/9p/mod.c index 5126566850bd07a21a4dbc55df0c925b2d91f5e6..94cd2d132fd7fa9796b20e4407ec69c6e0348daf 100644 --- a/net/9p/mod.c +++ b/net/9p/mod.c @@ -189,4 +189,5 @@ MODULE_AUTHOR("Latchesar Ionkov "); MODULE_AUTHOR("Eric Van Hensbergen "); MODULE_AUTHOR("Ron Minnich "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_DESCRIPTION("Plan 9 Resource Sharing Support (9P2000)"); diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 986f707e7d973a6a545a73951ae1c8163b4574ca..ee9cead7654502cf5f9b3db1de7870c88babd46d 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -164,9 +164,6 @@ static void batadv_backbone_gw_release(struct kref *ref) */ static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) { - if (!backbone_gw) - return; - kref_put(&backbone_gw->refcount, batadv_backbone_gw_release); } @@ -202,9 +199,6 @@ static void batadv_claim_release(struct kref *ref) */ static void batadv_claim_put(struct batadv_bla_claim *claim) { - if (!claim) - return; - kref_put(&claim->refcount, batadv_claim_release); } diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 338e4e9c33b8a40414ac90cd872ad56728e682d4..0e6e53e9b5f35b48cdfff8b70d4f1cd81e044d41 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -128,9 +128,6 @@ static void batadv_dat_entry_release(struct kref *ref) */ static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry) { - if (!dat_entry) - return; - kref_put(&dat_entry->refcount, batadv_dat_entry_release); } diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 62f6f13f89ffda04511a3d17dfe709759a7dedc8..ef3f85b576c4c7cc6b0a7d2c2c3e987b53218291 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -60,7 +60,7 @@ * after rcu grace period * @ref: kref pointer of the gw_node */ -void batadv_gw_node_release(struct kref *ref) +static void batadv_gw_node_release(struct kref *ref) { struct batadv_gw_node *gw_node; @@ -70,6 +70,16 @@ void batadv_gw_node_release(struct kref *ref) kfree_rcu(gw_node, rcu); } +/** + * batadv_gw_node_put() - decrement the gw_node refcounter and possibly release + * it + * @gw_node: gateway node to free + */ +void batadv_gw_node_put(struct batadv_gw_node *gw_node) +{ + kref_put(&gw_node->refcount, batadv_gw_node_release); +} + /** * batadv_gw_get_selected_gw_node() - Get currently selected gateway * @bat_priv: the bat priv with all the soft interface information diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index c5b1de586fde0b2322724cea2eab21d7306ca1a3..88b5dba843547f714d4c05677958aa2a66d3c496 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -9,7 +9,6 @@ #include "main.h" -#include #include #include #include @@ -29,7 +28,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, void batadv_gw_node_delete(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); void batadv_gw_node_free(struct batadv_priv *bat_priv); -void batadv_gw_node_release(struct kref *ref); +void batadv_gw_node_put(struct batadv_gw_node *gw_node); struct batadv_gw_node * batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); @@ -41,17 +40,4 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); -/** - * batadv_gw_node_put() - decrement the gw_node refcounter and possibly release - * it - * @gw_node: gateway node to free - */ -static inline void batadv_gw_node_put(struct batadv_gw_node *gw_node) -{ - if (!gw_node) - return; - - kref_put(&gw_node->refcount, batadv_gw_node_release); -} - #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index ba5850cfb2774958ce2cd07fc0c6f97ba3721153..b1855d9d0b062e446b1e637e5d5fa86a2c1ead54 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -113,9 +113,6 @@ int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, */ static inline void batadv_hardif_put(struct batadv_hard_iface *hard_iface) { - if (!hard_iface) - return; - kref_put(&hard_iface->refcount, batadv_hardif_release); } diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 1481b803956892049c90a568078d21eee7a313d9..35b3e03c07774b1095b290938c49a224a0c9f34e 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -222,9 +222,6 @@ static void batadv_nc_node_release(struct kref *ref) */ static void batadv_nc_node_put(struct batadv_nc_node *nc_node) { - if (!nc_node) - return; - kref_put(&nc_node->refcount, batadv_nc_node_release); } @@ -249,9 +246,6 @@ static void batadv_nc_path_release(struct kref *ref) */ static void batadv_nc_path_put(struct batadv_nc_path *nc_path) { - if (!nc_path) - return; - kref_put(&nc_path->refcount, batadv_nc_path_release); } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 2d38a09459bb53c8094a0895741efbdb9fb02b1b..805d8969bdfbc7f3012b6539bdefcee50e806aa4 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -178,7 +178,7 @@ out: * and queue for free after rcu grace period * @ref: kref pointer of the originator-vlan object */ -void batadv_orig_node_vlan_release(struct kref *ref) +static void batadv_orig_node_vlan_release(struct kref *ref) { struct batadv_orig_node_vlan *orig_vlan; @@ -187,6 +187,16 @@ void batadv_orig_node_vlan_release(struct kref *ref) kfree_rcu(orig_vlan, rcu); } +/** + * batadv_orig_node_vlan_put() - decrement the refcounter and possibly release + * the originator-vlan object + * @orig_vlan: the originator-vlan object to release + */ +void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan) +{ + kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release); +} + /** * batadv_originator_init() - Initialize all originator structures * @bat_priv: the bat priv with all the soft interface information @@ -222,7 +232,7 @@ err: * free after rcu grace period * @ref: kref pointer of the neigh_ifinfo */ -void batadv_neigh_ifinfo_release(struct kref *ref) +static void batadv_neigh_ifinfo_release(struct kref *ref) { struct batadv_neigh_ifinfo *neigh_ifinfo; @@ -234,12 +244,22 @@ void batadv_neigh_ifinfo_release(struct kref *ref) kfree_rcu(neigh_ifinfo, rcu); } +/** + * batadv_neigh_ifinfo_put() - decrement the refcounter and possibly release + * the neigh_ifinfo + * @neigh_ifinfo: the neigh_ifinfo object to release + */ +void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo) +{ + kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release); +} + /** * batadv_hardif_neigh_release() - release hardif neigh node from lists and * queue for free after rcu grace period * @ref: kref pointer of the neigh_node */ -void batadv_hardif_neigh_release(struct kref *ref) +static void batadv_hardif_neigh_release(struct kref *ref) { struct batadv_hardif_neigh_node *hardif_neigh; @@ -254,12 +274,22 @@ void batadv_hardif_neigh_release(struct kref *ref) kfree_rcu(hardif_neigh, rcu); } +/** + * batadv_hardif_neigh_put() - decrement the hardif neighbors refcounter + * and possibly release it + * @hardif_neigh: hardif neigh neighbor to free + */ +void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) +{ + kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release); +} + /** * batadv_neigh_node_release() - release neigh_node from lists and queue for * free after rcu grace period * @ref: kref pointer of the neigh_node */ -void batadv_neigh_node_release(struct kref *ref) +static void batadv_neigh_node_release(struct kref *ref) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; @@ -279,6 +309,16 @@ void batadv_neigh_node_release(struct kref *ref) kfree_rcu(neigh_node, rcu); } +/** + * batadv_neigh_node_put() - decrement the neighbors refcounter and possibly + * release it + * @neigh_node: neigh neighbor to free + */ +void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node) +{ + kref_put(&neigh_node->refcount, batadv_neigh_node_release); +} + /** * batadv_orig_router_get() - router to the originator depending on iface * @orig_node: the orig node for the router @@ -811,7 +851,7 @@ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) * free after rcu grace period * @ref: kref pointer of the orig_ifinfo */ -void batadv_orig_ifinfo_release(struct kref *ref) +static void batadv_orig_ifinfo_release(struct kref *ref) { struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *router; @@ -829,6 +869,16 @@ void batadv_orig_ifinfo_release(struct kref *ref) kfree_rcu(orig_ifinfo, rcu); } +/** + * batadv_orig_ifinfo_put() - decrement the refcounter and possibly release + * the orig_ifinfo + * @orig_ifinfo: the orig_ifinfo object to release + */ +void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo) +{ + kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release); +} + /** * batadv_orig_node_free_rcu() - free the orig_node * @rcu: rcu pointer of the orig_node @@ -852,7 +902,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) * free after rcu grace period * @ref: kref pointer of the orig_node */ -void batadv_orig_node_release(struct kref *ref) +static void batadv_orig_node_release(struct kref *ref) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; @@ -898,6 +948,16 @@ void batadv_orig_node_release(struct kref *ref) call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu); } +/** + * batadv_orig_node_put() - decrement the orig node refcounter and possibly + * release it + * @orig_node: the orig node to free + */ +void batadv_orig_node_put(struct batadv_orig_node *orig_node) +{ + kref_put(&orig_node->refcount, batadv_orig_node_release); +} + /** * batadv_originator_free() - Free all originator structures * @bat_priv: the bat priv with all the soft interface information diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 3b824a79743a252c47f2a5480ac7a633cff33555..7bc01c138b3ab8bc473c91423d7a777817ce82f4 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -22,18 +21,19 @@ bool batadv_compare_orig(const struct hlist_node *node, const void *data2); int batadv_originator_init(struct batadv_priv *bat_priv); void batadv_originator_free(struct batadv_priv *bat_priv); void batadv_purge_orig_ref(struct batadv_priv *bat_priv); -void batadv_orig_node_release(struct kref *ref); +void batadv_orig_node_put(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const u8 *addr); struct batadv_hardif_neigh_node * batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); -void batadv_hardif_neigh_release(struct kref *ref); +void +batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh); struct batadv_neigh_node * batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node, struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); -void batadv_neigh_node_release(struct kref *ref); +void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, const struct batadv_hard_iface *if_outgoing); @@ -43,7 +43,7 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); -void batadv_neigh_ifinfo_release(struct kref *ref); +void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo); int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb); int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset); @@ -54,7 +54,7 @@ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, struct batadv_orig_ifinfo * batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing); -void batadv_orig_ifinfo_release(struct kref *ref); +void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo); int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb); @@ -65,7 +65,7 @@ batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, struct batadv_orig_node_vlan * batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, unsigned short vid); -void batadv_orig_node_vlan_release(struct kref *ref); +void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan); /** * batadv_choose_orig() - Return the index of the orig entry in the hash table @@ -86,86 +86,4 @@ static inline u32 batadv_choose_orig(const void *data, u32 size) struct batadv_orig_node * batadv_orig_hash_find(struct batadv_priv *bat_priv, const void *data); -/** - * batadv_orig_node_vlan_put() - decrement the refcounter and possibly release - * the originator-vlan object - * @orig_vlan: the originator-vlan object to release - */ -static inline void -batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan) -{ - if (!orig_vlan) - return; - - kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release); -} - -/** - * batadv_neigh_ifinfo_put() - decrement the refcounter and possibly release - * the neigh_ifinfo - * @neigh_ifinfo: the neigh_ifinfo object to release - */ -static inline void -batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo) -{ - if (!neigh_ifinfo) - return; - - kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release); -} - -/** - * batadv_hardif_neigh_put() - decrement the hardif neighbors refcounter - * and possibly release it - * @hardif_neigh: hardif neigh neighbor to free - */ -static inline void -batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) -{ - if (!hardif_neigh) - return; - - kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release); -} - -/** - * batadv_neigh_node_put() - decrement the neighbors refcounter and possibly - * release it - * @neigh_node: neigh neighbor to free - */ -static inline void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node) -{ - if (!neigh_node) - return; - - kref_put(&neigh_node->refcount, batadv_neigh_node_release); -} - -/** - * batadv_orig_ifinfo_put() - decrement the refcounter and possibly release - * the orig_ifinfo - * @orig_ifinfo: the orig_ifinfo object to release - */ -static inline void -batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo) -{ - if (!orig_ifinfo) - return; - - kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release); -} - -/** - * batadv_orig_node_put() - decrement the orig node refcounter and possibly - * release it - * @orig_node: the orig node to free - */ -static inline void batadv_orig_node_put(struct batadv_orig_node *orig_node) -{ - if (!orig_node) - return; - - kref_put(&orig_node->refcount, batadv_orig_node_release); -} - #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 8f7c778255fba74f51e9f84ad094c5beb492b0f9..7496047b318a412e51d33849bd22f4d59357b5c2 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -512,7 +512,7 @@ out: * after rcu grace period * @ref: kref pointer of the vlan object */ -void batadv_softif_vlan_release(struct kref *ref) +static void batadv_softif_vlan_release(struct kref *ref) { struct batadv_softif_vlan *vlan; @@ -525,6 +525,19 @@ void batadv_softif_vlan_release(struct kref *ref) kfree_rcu(vlan, rcu); } +/** + * batadv_softif_vlan_put() - decrease the vlan object refcounter and + * possibly release it + * @vlan: the vlan object to release + */ +void batadv_softif_vlan_put(struct batadv_softif_vlan *vlan) +{ + if (!vlan) + return; + + kref_put(&vlan->refcount, batadv_softif_vlan_release); +} + /** * batadv_softif_vlan_get() - get the vlan object for a specific vid * @bat_priv: the bat priv with all the soft interface information diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 53aba17b90688b7efc478dde5a1b2d92ecf0b003..534e08d6ad919e3e244732d6646b4b48e11d5e6b 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h @@ -9,7 +9,6 @@ #include "main.h" -#include #include #include #include @@ -25,21 +24,8 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface); bool batadv_softif_is_valid(const struct net_device *net_dev); extern struct rtnl_link_ops batadv_link_ops; int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); -void batadv_softif_vlan_release(struct kref *ref); +void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan); struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid); -/** - * batadv_softif_vlan_put() - decrease the vlan object refcounter and - * possibly release it - * @vlan: the vlan object to release - */ -static inline void batadv_softif_vlan_put(struct batadv_softif_vlan *vlan) -{ - if (!vlan) - return; - - kref_put(&vlan->refcount, batadv_softif_vlan_release); -} - #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index 00d62a6c5e0efb619e18789271d86c69c395bfb4..db7e3774825b5f5871b23c0e4fa5ce7afb2accd6 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -357,9 +357,6 @@ static void batadv_tp_vars_release(struct kref *ref) */ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars) { - if (!tp_vars) - return; - kref_put(&tp_vars->refcount, batadv_tp_vars_release); } diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 5f990a2061072b8f7e024efacf9460250e079e5e..de946ea8f13c8c96d5153c62b68e480c2bbcade6 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -248,9 +248,6 @@ static void batadv_tt_local_entry_release(struct kref *ref) static void batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry) { - if (!tt_local_entry) - return; - kref_put(&tt_local_entry->common.refcount, batadv_tt_local_entry_release); } @@ -274,7 +271,7 @@ static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu) * queue for free after rcu grace period * @ref: kref pointer of the nc_node */ -void batadv_tt_global_entry_release(struct kref *ref) +static void batadv_tt_global_entry_release(struct kref *ref) { struct batadv_tt_global_entry *tt_global_entry; @@ -286,6 +283,17 @@ void batadv_tt_global_entry_release(struct kref *ref) call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu); } +/** + * batadv_tt_global_entry_put() - decrement the tt_global_entry refcounter and + * possibly release it + * @tt_global_entry: tt_global_entry to be free'd + */ +void batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) +{ + kref_put(&tt_global_entry->common.refcount, + batadv_tt_global_entry_release); +} + /** * batadv_tt_global_hash_count() - count the number of orig entries * @bat_priv: the bat priv with all the soft interface information @@ -445,9 +453,6 @@ static void batadv_tt_orig_list_entry_release(struct kref *ref) static void batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry) { - if (!orig_entry) - return; - kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); } @@ -2813,9 +2818,6 @@ static void batadv_tt_req_node_release(struct kref *ref) */ static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node) { - if (!tt_req_node) - return; - kref_put(&tt_req_node->refcount, batadv_tt_req_node_release); } diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 63cc8fd3ff66aea16fcecf9f2adbff03dc4ef63d..b24d35b9226a1f28be08e374264fd15130d53cdc 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -9,7 +9,6 @@ #include "main.h" -#include #include #include #include @@ -32,7 +31,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_tt_global_entry * batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid); -void batadv_tt_global_entry_release(struct kref *ref); +void batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry); int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid); struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, @@ -59,19 +58,4 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, int batadv_tt_cache_init(void); void batadv_tt_cache_destroy(void); -/** - * batadv_tt_global_entry_put() - decrement the tt_global_entry refcounter and - * possibly release it - * @tt_global_entry: tt_global_entry to be free'd - */ -static inline void -batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) -{ - if (!tt_global_entry) - return; - - kref_put(&tt_global_entry->common.refcount, - batadv_tt_global_entry_release); -} - #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index 99fc48efde5431c8231ebd7ac661f559cf09e94d..6a23a566cde17b1ea80bec83a30e975496e8ea2c 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -50,9 +50,6 @@ static void batadv_tvlv_handler_release(struct kref *ref) */ static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler) { - if (!tvlv_handler) - return; - kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release); } @@ -109,9 +106,6 @@ static void batadv_tvlv_container_release(struct kref *ref) */ static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv) { - if (!tvlv) - return; - kref_put(&tvlv->refcount, batadv_tvlv_container_release); } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ecd2ffcf2ba284e499dc7ab525d5fa3930c965ca..1c5a0a60292d2ae96c54553f34cf5c2261e24292 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -508,9 +508,7 @@ static void le_conn_timeout(struct work_struct *work) if (conn->role == HCI_ROLE_SLAVE) { /* Disable LE Advertising */ le_disable_advertising(hdev); - hci_dev_lock(hdev); hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); - hci_dev_unlock(hdev); return; } diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index 51a941b56ec3aab03d8151b4ce1fa169139f05cb..4dfcd0d7ff3f7920fbcb44f8b8fba960f13c7f22 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c @@ -134,3 +134,4 @@ static void __exit fini_umh(void) module_init(load_umh); module_exit(fini_umh); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); diff --git a/net/can/isotp.c b/net/can/isotp.c index 63e6e8923200bba51e8732ea5a0e412e43cfade7..d0581dc6a65fd5565969f084e95fe126e17f947b 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1003,29 +1003,26 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, { struct sock *sk = sock->sk; struct sk_buff *skb; - struct isotp_sock *so = isotp_sk(sk); - int noblock = flags & MSG_DONTWAIT; - int ret = 0; - - if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK)) - return -EINVAL; - - if (!so->bound) - return -EADDRNOTAVAIL; + int err = 0; + int noblock; + noblock = flags & MSG_DONTWAIT; flags &= ~MSG_DONTWAIT; - skb = skb_recv_datagram(sk, flags, noblock, &ret); + + skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) - return ret; + return err; if (size < skb->len) msg->msg_flags |= MSG_TRUNC; else size = skb->len; - ret = memcpy_to_msg(msg, skb->data, size); - if (ret < 0) - goto out_err; + err = memcpy_to_msg(msg, skb->data, size); + if (err < 0) { + skb_free_datagram(sk, skb); + return err; + } sock_recv_timestamp(msg, sk, skb); @@ -1035,13 +1032,9 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, memcpy(msg->msg_name, skb->cb, msg->msg_namelen); } - /* set length of return value */ - ret = (flags & MSG_TRUNC) ? skb->len : size; - -out_err: skb_free_datagram(sk, skb); - return ret; + return size; } static int isotp_release(struct socket *sock) @@ -1109,7 +1102,6 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) struct net *net = sock_net(sk); int ifindex; struct net_device *dev; - canid_t tx_id, rx_id; int err = 0; int notify_enetdown = 0; int do_rx_reg = 1; @@ -1117,18 +1109,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) if (len < ISOTP_MIN_NAMELEN) return -EINVAL; - /* sanitize tx/rx CAN identifiers */ - tx_id = addr->can_addr.tp.tx_id; - if (tx_id & CAN_EFF_FLAG) - tx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK); - else - tx_id &= CAN_SFF_MASK; - - rx_id = addr->can_addr.tp.rx_id; - if (rx_id & CAN_EFF_FLAG) - rx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK); - else - rx_id &= CAN_SFF_MASK; + if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) + return -EADDRNOTAVAIL; if (!addr->can_ifindex) return -ENODEV; @@ -1140,13 +1122,21 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) do_rx_reg = 0; /* do not validate rx address for functional addressing */ - if (do_rx_reg && rx_id == tx_id) { - err = -EADDRNOTAVAIL; - goto out; + if (do_rx_reg) { + if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) { + err = -EADDRNOTAVAIL; + goto out; + } + + if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) { + err = -EADDRNOTAVAIL; + goto out; + } } if (so->bound && addr->can_ifindex == so->ifindex && - rx_id == so->rxid && tx_id == so->txid) + addr->can_addr.tp.rx_id == so->rxid && + addr->can_addr.tp.tx_id == so->txid) goto out; dev = dev_get_by_index(net, addr->can_ifindex); @@ -1170,7 +1160,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) ifindex = dev->ifindex; if (do_rx_reg) - can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id), + can_rx_register(net, dev, addr->can_addr.tp.rx_id, + SINGLE_MASK(addr->can_addr.tp.rx_id), isotp_rcv, sk, "isotp", sk); dev_put(dev); @@ -1190,8 +1181,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) /* switch to new settings */ so->ifindex = ifindex; - so->rxid = rx_id; - so->txid = tx_id; + so->rxid = addr->can_addr.tp.rx_id; + so->txid = addr->can_addr.tp.tx_id; so->bound = 1; out: diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0c3c0c9cbe23a1e2a659acce1ee2b31c5c7d1bbe..fc36c8eddbf7200b904d8764f936617419f12258 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3669,7 +3669,7 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, unsigned int delta_len = 0; struct sk_buff *tail = NULL; struct sk_buff *nskb, *tmp; - int err; + int len_diff, err; skb_push(skb, -skb_network_offset(skb) + offset); @@ -3709,9 +3709,11 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb, skb_push(nskb, -skb_network_offset(nskb) + offset); skb_release_head_state(nskb); + len_diff = skb_network_header_len(nskb) - skb_network_header_len(skb); __copy_skb_header(nskb, skb); skb_headers_offset_update(nskb, skb_headroom(nskb) - skb_headroom(skb)); + nskb->transport_header += len_diff; skb_copy_from_linear_data_offset(skb, -tnl_hlen, nskb->data - tnl_hlen, offset + tnl_hlen); diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 545181a1ae04303a9a7ff345bb2132cceb6f277b..e4bb89599b44bc77b4712312d300997c32fa916b 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -27,7 +27,6 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, int elem_first_coalesce) { struct page_frag *pfrag = sk_page_frag(sk); - u32 osize = msg->sg.size; int ret = 0; len -= msg->sg.size; @@ -36,17 +35,13 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, u32 orig_offset; int use, i; - if (!sk_page_frag_refill(sk, pfrag)) { - ret = -ENOMEM; - goto msg_trim; - } + if (!sk_page_frag_refill(sk, pfrag)) + return -ENOMEM; orig_offset = pfrag->offset; use = min_t(int, len, pfrag->size - orig_offset); - if (!sk_wmem_schedule(sk, use)) { - ret = -ENOMEM; - goto msg_trim; - } + if (!sk_wmem_schedule(sk, use)) + return -ENOMEM; i = msg->sg.end; sk_msg_iter_var_prev(i); @@ -76,10 +71,6 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, } return ret; - -msg_trim: - sk_msg_trim(sk, msg, osize); - return ret; } EXPORT_SYMBOL_GPL(sk_msg_alloc); diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index f543fca6dfcbfd718eca7fcc430b6691afc13a6f..71c8ef7d40870b3321daba2620b43ee43c134186 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -766,7 +766,6 @@ static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) struct net_device *master; master = of_find_net_device_by_node(ethernet); - of_node_put(ethernet); if (!master) return -EPROBE_DEFER; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index d76af5ba5cc20b23d5b687befebec04f589e0b79..a3271ec3e1627fb4f6e29da0e0fb1a638fe7e789 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -448,7 +448,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; - unsigned int allocsz; /* this is non-NULL only with TCP/UDP Encapsulation */ if (x->encap) { @@ -458,10 +457,6 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * return err; } - allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); - if (allocsz > ESP_SKB_FRAG_MAXSIZE) - goto cow; - if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c72d0de8bf71432d6bce6b73ec73db7e00060ff2..ce787c38679384866687d3522f406df71d502983 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -529,15 +529,6 @@ void __ip_select_ident(struct net *net, struct iphdr *iph, int segs) } EXPORT_SYMBOL(__ip_select_ident); -static void ip_rt_fix_tos(struct flowi4 *fl4) -{ - __u8 tos = RT_FL_TOS(fl4); - - fl4->flowi4_tos = tos & IPTOS_RT_MASK; - fl4->flowi4_scope = tos & RTO_ONLINK ? - RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; -} - static void __build_flow_key(const struct net *net, struct flowi4 *fl4, const struct sock *sk, const struct iphdr *iph, @@ -862,7 +853,6 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf rt = (struct rtable *) dst; __build_flow_key(net, &fl4, sk, iph, oif, tos, prot, mark, 0); - ip_rt_fix_tos(&fl4); __ip_do_redirect(rt, skb, &fl4, true); } @@ -1087,7 +1077,6 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct flowi4 fl4; ip_rt_build_flow_key(&fl4, sk, skb); - ip_rt_fix_tos(&fl4); /* Don't make lookup fail for bridged encapsulations */ if (skb && netif_is_any_bridge_port(skb->dev)) @@ -1162,8 +1151,6 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) goto out; new = true; - } else { - ip_rt_fix_tos(&fl4); } __ip_rt_update_pmtu((struct rtable *)xfrm_dst_path(&rt->dst), &fl4, mtu); @@ -2537,6 +2524,7 @@ add: struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, const struct sk_buff *skb) { + __u8 tos = RT_FL_TOS(fl4); struct fib_result res = { .type = RTN_UNSPEC, .fi = NULL, @@ -2546,7 +2534,9 @@ struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, struct rtable *rth; fl4->flowi4_iif = LOOPBACK_IFINDEX; - ip_rt_fix_tos(fl4); + fl4->flowi4_tos = tos & IPTOS_RT_MASK; + fl4->flowi4_scope = ((tos & RTO_ONLINK) ? + RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); rcu_read_lock(); rth = ip_route_output_key_hash_rcu(net, fl4, &res, skb); diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index eaf2308c355a6ed9f9ecafc660f296fbbd1ea698..6b745ce4108c8786631bc57e704e7753d0d70356 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -218,9 +218,10 @@ int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg, struct sk_psock *psock = sk_psock_get(sk); int ret; - if (unlikely(!psock)) - return -EPIPE; - + if (unlikely(!psock)) { + sk_msg_free(sk, msg); + return 0; + } ret = ingress ? bpf_tcp_ingress(sk, psock, msg, bytes, flags) : tcp_bpf_push_locked(sk, msg, bytes, flags, false); sk_psock_put(sk, psock); @@ -370,7 +371,7 @@ more_data: cork = true; psock->cork = NULL; } - sk_msg_return(sk, msg, msg->sg.size); + sk_msg_return(sk, msg, tosend); release_sock(sk); ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags); @@ -410,11 +411,8 @@ more_data: } if (msg && msg->sg.data[msg->sg.start].page_link && - msg->sg.data[msg->sg.start].length) { - if (eval == __SK_REDIRECT) - sk_mem_charge(sk, msg->sg.size); + msg->sg.data[msg->sg.start].length) goto more_data; - } } return ret; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7fce54a2980257f71b4d2d6d8ad5656f4874d608..37e70cd46feafc9b497a77ca042d9858e242deb1 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3733,7 +3733,6 @@ static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) */ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) { - struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); struct tcp_fastopen_request *fo = tp->fastopen_req; int space, err = 0; @@ -3748,10 +3747,8 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) * private TCP options. The cost is reduced data space in SYN :( */ tp->rx_opt.mss_clamp = tcp_mss_clamp(tp, tp->rx_opt.mss_clamp); - /* Sync mss_cache after updating the mss_clamp */ - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - space = __tcp_mtu_to_mss(sk, icsk->icsk_pmtu_cookie) - + space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) - MAX_TCP_OPTION_SPACE; space = min_t(size_t, space, fo->size); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e97a2dd206e145d1754961d26e2e98b1230d981a..ef2068a60d4ad49db4dd781178b060dd78541b58 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -598,12 +598,6 @@ void udp_encap_enable(void) } EXPORT_SYMBOL(udp_encap_enable); -void udp_encap_disable(void) -{ - static_branch_dec(&udp_encap_needed_key); -} -EXPORT_SYMBOL(udp_encap_disable); - /* Handler for tunnels with arbitrary destination ports: no socket lookup, go * through error handlers in encapsulations looking for a match. */ diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 61c913b75c9e12afdd1f0c70cfbd89b98688a445..0158b0163ca8ee847a7d100ee9d6a6a8482b13a7 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -483,7 +483,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info struct page *page; struct sk_buff *trailer; int tailen = esp->tailen; - unsigned int allocsz; if (x->encap) { int err = esp6_output_encap(x, skb, esp); @@ -492,10 +491,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info return err; } - allocsz = ALIGN(skb->data_len + tailen, L1_CACHE_BYTES); - if (allocsz > ESP_SKB_FRAG_MAXSIZE) - goto cow; - if (!skb_cloned(skb)) { if (tailen <= skb_tailroom(skb)) { nfrags = 1; @@ -813,7 +808,8 @@ int esp6_input_done2(struct sk_buff *skb, int err) struct tcphdr *th; offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); - if (offset == -1) { + + if (offset < 0) { err = -EINVAL; goto out; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2aa39ce7093dfd32870f9986c762ef9a7a680791..d6f2126f461848a9e10f49863e8f059f77025a31 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1500,8 +1500,8 @@ static int __ip6_append_data(struct sock *sk, sizeof(struct frag_hdr) : 0) + rt->rt6i_nfheader_len; - if (mtu <= fragheaderlen || - ((mtu - fragheaderlen) & ~7) + fragheaderlen <= sizeof(struct frag_hdr)) + if (mtu < fragheaderlen || + ((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr)) goto emsgsize; maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 10760164a80f409c091692fad42832d7579f3b72..069551a04369e16425d8f0ae51e83add92fda2ae 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1610,10 +1610,8 @@ void udpv6_destroy_sock(struct sock *sk) if (encap_destroy) encap_destroy(sk); } - if (up->encap_enabled) { + if (up->encap_enabled) static_branch_dec(&udpv6_encap_needed_key); - udp_encap_disable(); - } } inet6_destroy_sock(sk); diff --git a/net/key/af_key.c b/net/key/af_key.c index bd9b5c573b5a4dd328d44af315a9efd5ab51bcc2..d1364b858fdf0bd546d0b90617ba2406a9bed03a 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1703,7 +1703,7 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad xfrm_probe_algs(); - supp_skb = compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO); + supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); if (!supp_skb) { if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) pfk->registered &= ~(1<sadb_msg_satype); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 99a37c411323edcf59733486a07a8a1e1ce6b3a6..ac5cadd02cfa8f6ee937ee91252a71a750d447ee 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -276,7 +276,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); - struct net_device *dev = NULL; struct llc_sap *sap; int rc = -EINVAL; @@ -288,14 +287,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) goto out; rc = -ENODEV; if (sk->sk_bound_dev_if) { - dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); - if (dev && addr->sllc_arphrd != dev->type) { - dev_put(dev); - dev = NULL; + llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + if (llc->dev && addr->sllc_arphrd != llc->dev->type) { + dev_put(llc->dev); + llc->dev = NULL; } } else - dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); - if (!dev) + llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); + if (!llc->dev) goto out; rc = -EUSERS; llc->laddr.lsap = llc_ui_autoport(); @@ -305,11 +304,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sap = llc_sap_open(llc->laddr.lsap, NULL); if (!sap) goto out; - - /* Note: We do not expect errors from this point. */ - llc->dev = dev; - dev = NULL; - memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); /* assign new connection to its SAP */ @@ -317,7 +311,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) sock_reset_flag(sk, SOCK_ZAPPED); rc = 0; out: - dev_put(dev); return rc; } @@ -340,7 +333,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); - struct net_device *dev = NULL; struct llc_sap *sap; int rc = -EINVAL; @@ -356,26 +348,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) rc = -ENODEV; rcu_read_lock(); if (sk->sk_bound_dev_if) { - dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); - if (dev) { + llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); + if (llc->dev) { if (is_zero_ether_addr(addr->sllc_mac)) - memcpy(addr->sllc_mac, dev->dev_addr, + memcpy(addr->sllc_mac, llc->dev->dev_addr, IFHWADDRLEN); - if (addr->sllc_arphrd != dev->type || + if (addr->sllc_arphrd != llc->dev->type || !ether_addr_equal(addr->sllc_mac, - dev->dev_addr)) { + llc->dev->dev_addr)) { rc = -EINVAL; - dev = NULL; + llc->dev = NULL; } } - } else { - dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, + } else + llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, addr->sllc_mac); - } - if (dev) - dev_hold(dev); + if (llc->dev) + dev_hold(llc->dev); rcu_read_unlock(); - if (!dev) + if (!llc->dev) goto out; if (!addr->sllc_sap) { rc = -EUSERS; @@ -408,11 +399,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) goto out_put; } } - - /* Note: We do not expect errors from this point. */ - llc->dev = dev; - dev = NULL; - llc->laddr.lsap = addr->sllc_sap; memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN); memcpy(&llc->addr, addr, sizeof(llc->addr)); @@ -423,7 +409,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) out_put: llc_sap_put(sap); out: - dev_put(dev); release_sock(sk); return rc; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8010967a68741447924990329b686f7e853a6ec7..d46ed4cbe771757b48b15090d33a17a8d4b83096 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2076,12 +2076,14 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, const struct mesh_setup *setup) { u8 *new_ie; + const u8 *old_ie; struct ieee80211_sub_if_data *sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); int i; /* allocate information elements */ new_ie = NULL; + old_ie = ifmsh->ie; if (setup->ie_len) { new_ie = kmemdup(setup->ie, setup->ie_len, @@ -2091,6 +2093,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, } ifmsh->ie_len = setup->ie_len; ifmsh->ie = new_ie; + kfree(old_ie); /* now copy the rest of the setup parameters */ ifmsh->mesh_id_len = setup->mesh_id_len; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 3f785bdfa942d7149bf65573ca17c3fe3ce2164a..c8fb2187ad4b2df200273acdbdf2163c831de09b 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -354,8 +354,8 @@ static void tcp_options(const struct sk_buff *skb, length, buff); BUG_ON(ptr == NULL); - state->td_scale = 0; - state->flags &= IP_CT_TCP_FLAG_BE_LIBERAL; + state->td_scale = + state->flags = 0; while (length > 0) { int opcode=*ptr++; @@ -840,16 +840,6 @@ static bool nf_conntrack_tcp_established(const struct nf_conn *ct) test_bit(IPS_ASSURED_BIT, &ct->status); } -static void nf_ct_tcp_state_reset(struct ip_ct_tcp_state *state) -{ - state->td_end = 0; - state->td_maxend = 0; - state->td_maxwin = 0; - state->td_maxack = 0; - state->td_scale = 0; - state->flags &= IP_CT_TCP_FLAG_BE_LIBERAL; -} - /* Returns verdict for packet, or -1 for invalid. */ int nf_conntrack_tcp_packet(struct nf_conn *ct, struct sk_buff *skb, @@ -956,7 +946,8 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = ct->proto.tcp.last_flags; - nf_ct_tcp_state_reset(&ct->proto.tcp.seen[dir]); + memset(&ct->proto.tcp.seen[dir], 0, + sizeof(struct ip_ct_tcp_state)); break; } ct->proto.tcp.last_index = index; diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index a61b5bf5aa0fbb1b059ef1c5ca94f94d48ecb6a2..dbc2e945c98ebce86dd498a093cd693d28030d79 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -162,7 +162,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv) struct nft_rule *const *rules; const struct nft_rule *rule; const struct nft_expr *expr, *last; - struct nft_regs regs = {}; + struct nft_regs regs; unsigned int stackptr = 0; struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; bool genbit = READ_ONCE(net->nft.gencursor); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index f37916156ca523556c0266ad50acc2e9036ba0a1..e55af5c078ac096985c842484a8a81e42bffadda 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -149,8 +149,6 @@ static const struct rhashtable_params netlink_rhashtable_params; static inline u32 netlink_group_mask(u32 group) { - if (group > 32) - return 0; return group ? 1 << (group - 1) : 0; } diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 7ff98d39ec942ccf00f1bfdb01e9aad54b7a35f0..a11b558813c10783977a52cbb00d901182072a21 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -730,57 +730,6 @@ static bool skb_nfct_cached(struct net *net, } #if IS_ENABLED(CONFIG_NF_NAT) -static void ovs_nat_update_key(struct sw_flow_key *key, - const struct sk_buff *skb, - enum nf_nat_manip_type maniptype) -{ - if (maniptype == NF_NAT_MANIP_SRC) { - __be16 src; - - key->ct_state |= OVS_CS_F_SRC_NAT; - if (key->eth.type == htons(ETH_P_IP)) - key->ipv4.addr.src = ip_hdr(skb)->saddr; - else if (key->eth.type == htons(ETH_P_IPV6)) - memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr, - sizeof(key->ipv6.addr.src)); - else - return; - - if (key->ip.proto == IPPROTO_UDP) - src = udp_hdr(skb)->source; - else if (key->ip.proto == IPPROTO_TCP) - src = tcp_hdr(skb)->source; - else if (key->ip.proto == IPPROTO_SCTP) - src = sctp_hdr(skb)->source; - else - return; - - key->tp.src = src; - } else { - __be16 dst; - - key->ct_state |= OVS_CS_F_DST_NAT; - if (key->eth.type == htons(ETH_P_IP)) - key->ipv4.addr.dst = ip_hdr(skb)->daddr; - else if (key->eth.type == htons(ETH_P_IPV6)) - memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr, - sizeof(key->ipv6.addr.dst)); - else - return; - - if (key->ip.proto == IPPROTO_UDP) - dst = udp_hdr(skb)->dest; - else if (key->ip.proto == IPPROTO_TCP) - dst = tcp_hdr(skb)->dest; - else if (key->ip.proto == IPPROTO_SCTP) - dst = sctp_hdr(skb)->dest; - else - return; - - key->tp.dst = dst; - } -} - /* Modelled after nf_nat_ipv[46]_fn(). * range is only used for new, uninitialized NAT state. * Returns either NF_ACCEPT or NF_DROP. @@ -788,7 +737,7 @@ static void ovs_nat_update_key(struct sw_flow_key *key, static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_nat_range2 *range, - enum nf_nat_manip_type maniptype, struct sw_flow_key *key) + enum nf_nat_manip_type maniptype) { int hooknum, nh_off, err = NF_ACCEPT; @@ -861,13 +810,60 @@ push: skb_push(skb, nh_off); skb_postpush_rcsum(skb, skb->data, nh_off); - /* Update the flow key if NAT successful. */ - if (err == NF_ACCEPT) - ovs_nat_update_key(key, skb, maniptype); - return err; } +static void ovs_nat_update_key(struct sw_flow_key *key, + const struct sk_buff *skb, + enum nf_nat_manip_type maniptype) +{ + if (maniptype == NF_NAT_MANIP_SRC) { + __be16 src; + + key->ct_state |= OVS_CS_F_SRC_NAT; + if (key->eth.type == htons(ETH_P_IP)) + key->ipv4.addr.src = ip_hdr(skb)->saddr; + else if (key->eth.type == htons(ETH_P_IPV6)) + memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr, + sizeof(key->ipv6.addr.src)); + else + return; + + if (key->ip.proto == IPPROTO_UDP) + src = udp_hdr(skb)->source; + else if (key->ip.proto == IPPROTO_TCP) + src = tcp_hdr(skb)->source; + else if (key->ip.proto == IPPROTO_SCTP) + src = sctp_hdr(skb)->source; + else + return; + + key->tp.src = src; + } else { + __be16 dst; + + key->ct_state |= OVS_CS_F_DST_NAT; + if (key->eth.type == htons(ETH_P_IP)) + key->ipv4.addr.dst = ip_hdr(skb)->daddr; + else if (key->eth.type == htons(ETH_P_IPV6)) + memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr, + sizeof(key->ipv6.addr.dst)); + else + return; + + if (key->ip.proto == IPPROTO_UDP) + dst = udp_hdr(skb)->dest; + else if (key->ip.proto == IPPROTO_TCP) + dst = tcp_hdr(skb)->dest; + else if (key->ip.proto == IPPROTO_SCTP) + dst = sctp_hdr(skb)->dest; + else + return; + + key->tp.dst = dst; + } +} + /* Returns NF_DROP if the packet should be dropped, NF_ACCEPT otherwise. */ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, const struct ovs_conntrack_info *info, @@ -907,7 +903,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, } else { return NF_ACCEPT; /* Connection is not NATed. */ } - err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype, key); + err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype); if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) { if (ct->status & IPS_SRC_NAT) { @@ -917,13 +913,17 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, maniptype = NF_NAT_MANIP_SRC; err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, - maniptype, key); + maniptype); } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL, - NF_NAT_MANIP_SRC, key); + NF_NAT_MANIP_SRC); } } + /* Mark NAT done if successful and update the flow key. */ + if (err == NF_ACCEPT) + ovs_nat_update_key(key, skb, maniptype); + return err; } #else /* !CONFIG_NF_NAT */ diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 8c4bdfa627ca908ebd6ed3aa2621a203adb2c1f8..4c5c2331e7648fb84c26bc791a8de914e0336e05 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -2201,8 +2201,8 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, icmpv6_key->icmpv6_type = ntohs(output->tp.src); icmpv6_key->icmpv6_code = ntohs(output->tp.dst); - if (swkey->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) || - swkey->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) { + if (icmpv6_key->icmpv6_type == NDISC_NEIGHBOUR_SOLICITATION || + icmpv6_key->icmpv6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { struct ovs_key_nd *nd_key; nla = nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key)); diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 3bad9f5f9102395eac52d393f497602bab6fac69..dce48162f6c274116f25ff6fa04b54dd7835f372 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -760,12 +760,14 @@ void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, bool, bool, enum rxrpc_propose_ack_trace); void rxrpc_process_call(struct work_struct *); -void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why); - -void rxrpc_delete_call_timer(struct rxrpc_call *call); +static inline void rxrpc_reduce_call_timer(struct rxrpc_call *call, + unsigned long expire_at, + unsigned long now, + enum rxrpc_timer_trace why) +{ + trace_rxrpc_timer(call, why, now); + timer_reduce(&call->timer, expire_at); +} /* * call_object.c @@ -789,7 +791,6 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *); bool __rxrpc_queue_call(struct rxrpc_call *); bool rxrpc_queue_call(struct rxrpc_call *); void rxrpc_see_call(struct rxrpc_call *); -bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op); void rxrpc_get_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_put_call(struct rxrpc_call *, enum rxrpc_call_trace); void rxrpc_cleanup_call(struct rxrpc_call *); diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c index 22e05de5d1ca96fccb667a0a287e0042fc5be6e9..df864e6922679140d5b7c8c3aadd65a92906e9e3 100644 --- a/net/rxrpc/call_event.c +++ b/net/rxrpc/call_event.c @@ -310,7 +310,7 @@ recheck_state: } if (call->state == RXRPC_CALL_COMPLETE) { - rxrpc_delete_call_timer(call); + del_timer_sync(&call->timer); goto out_put; } diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 043508fd8d8a5d3a57d8a805093769b0be1f3b06..4eb91d958a48d3f89c17bcf1d43eadc57a748d70 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -53,30 +53,10 @@ static void rxrpc_call_timer_expired(struct timer_list *t) if (call->state < RXRPC_CALL_COMPLETE) { trace_rxrpc_timer(call, rxrpc_timer_expired, jiffies); - __rxrpc_queue_call(call); - } else { - rxrpc_put_call(call, rxrpc_call_put); - } -} - -void rxrpc_reduce_call_timer(struct rxrpc_call *call, - unsigned long expire_at, - unsigned long now, - enum rxrpc_timer_trace why) -{ - if (rxrpc_try_get_call(call, rxrpc_call_got_timer)) { - trace_rxrpc_timer(call, why, now); - if (timer_reduce(&call->timer, expire_at)) - rxrpc_put_call(call, rxrpc_call_put_notimer); + rxrpc_queue_call(call); } } -void rxrpc_delete_call_timer(struct rxrpc_call *call) -{ - if (del_timer_sync(&call->timer)) - rxrpc_put_call(call, rxrpc_call_put_timer); -} - static struct lock_class_key rxrpc_call_user_mutex_lock_class_key; /* @@ -483,17 +463,6 @@ void rxrpc_see_call(struct rxrpc_call *call) } } -bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) -{ - const void *here = __builtin_return_address(0); - int n = atomic_fetch_add_unless(&call->usage, 1, 0); - - if (n == 0) - return false; - trace_rxrpc_call(call->debug_id, op, n, here, NULL); - return true; -} - /* * Note the addition of a ref on a call. */ @@ -541,7 +510,8 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) spin_unlock_bh(&call->lock); rxrpc_put_call_slot(call); - rxrpc_delete_call_timer(call); + + del_timer_sync(&call->timer); /* Make sure we don't get any more notifications */ write_lock_bh(&rx->recvmsg_lock); @@ -648,8 +618,6 @@ static void rxrpc_destroy_call(struct work_struct *work) struct rxrpc_call *call = container_of(work, struct rxrpc_call, processor); struct rxrpc_net *rxnet = call->rxnet; - rxrpc_delete_call_timer(call); - rxrpc_put_connection(call->conn); rxrpc_put_peer(call->peer); kfree(call->rxtx_buffer); @@ -684,6 +652,8 @@ void rxrpc_cleanup_call(struct rxrpc_call *call) memset(&call->sock_node, 0xcd, sizeof(call->sock_node)); + del_timer_sync(&call->timer); + ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags)); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 236fadc4a4399a89cf6bfba15cf4ebdcb81976bb..6c320623cdcd7c715dbc74a63bb6779212bf97aa 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -139,5 +139,6 @@ cleanup_sunrpc(void) rcu_barrier(); /* Wait for completion of call_rcu()'s */ } MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); fs_initcall(init_sunrpc); /* Ensure we're initialised before nfs */ module_exit(cleanup_sunrpc); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 46304e647c4927c1568d7a4c3327db77e0e28292..04aaca4b8bf93fa0cd2fc337153f692de6f86cea 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -2037,14 +2037,7 @@ static void xprt_destroy(struct rpc_xprt *xprt) */ wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_UNINTERRUPTIBLE); - /* - * xprt_schedule_autodisconnect() can run after XPRT_LOCKED - * is cleared. We use ->transport_lock to ensure the mod_timer() - * can only run *before* del_time_sync(), never after. - */ - spin_lock(&xprt->transport_lock); del_timer_sync(&xprt->timer); - spin_unlock(&xprt->transport_lock); /* * Destroy sockets etc from the system workqueue so they can diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 42283dc6c5b7c724cb40120050e6e9f90fd53730..8d2c98531af456389f0087660c4a83a2a0e0b4f7 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2846,8 +2846,7 @@ static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list) /* Try again later if dest link is congested */ if (tsk->cong_link_cnt) { - sk_reset_timer(sk, &sk->sk_timer, - jiffies + msecs_to_jiffies(100)); + sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100)); return; } /* Prepare SYN for retransmit */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b7edca89e0ba94b3d990db90e41fd44479260518..fa99fe5bcf6ce3ec2e86e50904027824a9dc75b7 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -3008,4 +3008,5 @@ fs_initcall(af_unix_init); module_exit(af_unix_exit); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); MODULE_ALIAS_NETPROTO(PF_UNIX); diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index c59806253a65abc62dfe763b9c123db77f5484bb..005aa701f4d522023c713149e360914a8e44e375 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -333,8 +333,7 @@ void vsock_remove_sock(struct vsock_sock *vsk) } EXPORT_SYMBOL_GPL(vsock_remove_sock); -void vsock_for_each_connected_socket(struct vsock_transport *transport, - void (*fn)(struct sock *sk)) +void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)) { int i; @@ -343,12 +342,8 @@ void vsock_for_each_connected_socket(struct vsock_transport *transport, for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) { struct vsock_sock *vsk; list_for_each_entry(vsk, &vsock_connected_table[i], - connected_table) { - if (vsk->transport != transport) - continue; - + connected_table) fn(sk_vsock(vsk)); - } } spin_unlock_bh(&vsock_table_lock); diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index e131121533ad93d718a826f4a634aa12ce2aa476..3a056f8affd1d20265cb256bb2b6eeddf8e09310 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -24,7 +24,6 @@ static struct workqueue_struct *virtio_vsock_workqueue; static struct virtio_vsock __rcu *the_virtio_vsock; static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */ -static struct virtio_transport virtio_transport; /* forward declaration */ struct virtio_vsock { struct virtio_device *vdev; @@ -384,8 +383,7 @@ static void virtio_vsock_event_handle(struct virtio_vsock *vsock, switch (le32_to_cpu(event->id)) { case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: virtio_vsock_update_guest_cid(vsock); - vsock_for_each_connected_socket(&virtio_transport.transport, - virtio_vsock_reset_sock); + vsock_for_each_connected_socket(virtio_vsock_reset_sock); break; } } @@ -637,8 +635,7 @@ static void virtio_vsock_remove(struct virtio_device *vdev) synchronize_rcu(); /* Reset all connected sockets when the device disappear */ - vsock_for_each_connected_socket(&virtio_transport.transport, - virtio_vsock_reset_sock); + vsock_for_each_connected_socket(virtio_vsock_reset_sock); /* Stop all work handlers to make sure no one is accessing the device, * so we can safely call vdev->config->reset(). diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index a9ca95a0fcdda6f1b39b2787efd3f2cea5b14762..1c9ecb18b8e644db60264354918a0ad59f12cf05 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -75,8 +75,6 @@ static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; static int PROTOCOL_OVERRIDE = -1; -static struct vsock_transport vmci_transport; /* forward declaration */ - /* Helper function to convert from a VMCI error code to a VSock error code. */ static s32 vmci_transport_error_to_vsock_error(s32 vmci_error) @@ -884,8 +882,7 @@ static void vmci_transport_qp_resumed_cb(u32 sub_id, const struct vmci_event_data *e_data, void *client_data) { - vsock_for_each_connected_socket(&vmci_transport, - vmci_transport_handle_detach); + vsock_for_each_connected_socket(vmci_transport_handle_detach); } static void vmci_transport_recv_pkt_work(struct work_struct *work) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ed99f0bcae99848918fe6ed1dab955b14632867..5d8959a5e7608f35f0b787966ee455dee70620da 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -475,7 +475,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { .len = IEEE80211_MAX_MESH_ID_LEN }, [NL80211_ATTR_MPATH_NEXT_HOP] = NLA_POLICY_ETH_ADDR_COMPAT, - [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, + /* allow 3 for NUL-termination, we used to declare this NLA_STRING */ + [NL80211_ATTR_REG_ALPHA2] = NLA_POLICY_RANGE(NLA_BINARY, 2, 3), [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED }, [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index d231d4620c38f8c63aa938ec5f92a3d21c79e3b2..03ed170b8125e5038e1714acd9b0995e26b3cb9d 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1775,15 +1775,10 @@ void x25_kill_by_neigh(struct x25_neigh *nb) write_lock_bh(&x25_list_lock); - sk_for_each(s, &x25_list) { - if (x25_sk(s)->neighbour == nb) { - write_unlock_bh(&x25_list_lock); - lock_sock(s); + sk_for_each(s, &x25_list) + if (x25_sk(s)->neighbour == nb) x25_disconnect(s, ENETUNREACH, 0, 0); - release_sock(s); - write_lock_bh(&x25_list_lock); - } - } + write_unlock_bh(&x25_list_lock); /* Remove any related forwards */ diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index cf5b0a8952254bf86adbc5496fbfbe45976a3f4c..2e4508a6cb3a7c4dec89a924c7188a2ab332ec2d 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -1520,15 +1520,14 @@ int main(int argc, char **argv) setlocale(LC_ALL, ""); - prev_time = get_nsecs(); - start_time = prev_time; - if (!opt_quiet) { ret = pthread_create(&pt, NULL, poller, NULL); if (ret) exit_with_error(ret); } + prev_time = get_nsecs(); + start_time = prev_time; if (opt_bench == BENCH_RXDROP) rx_drop_all(); diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index f1d201782346fa84f616b7b15824fc2273e98479..4852bf44e913e25b4e69c4b066c068d2254a13d4 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -22,7 +22,7 @@ dtc-objs += yamltree.o # To include installed in a non-default path HOSTCFLAGS_yamltree.o := $(shell pkg-config --cflags yaml-0.1) # To link libyaml installed in a non-default path -HOSTLDLIBS_dtc := $(shell pkg-config --libs yaml-0.1) +HOSTLDLIBS_dtc := $(shell pkg-config yaml-0.1 --libs) endif # Generated files need one more search path to include headers in source tree diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c index dacd697ffd3830b5aa32eb93535f7341ace59859..48e141e07956261e74fdb5b2f56983c285614e36 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -431,23 +431,6 @@ static unsigned int stackleak_cleanup_execute(void) return 0; } -/* - * STRING_CST may or may not be NUL terminated: - * https://gcc.gnu.org/onlinedocs/gccint/Constant-expressions.html - */ -static inline bool string_equal(tree node, const char *string, int length) -{ - if (TREE_STRING_LENGTH(node) < length) - return false; - if (TREE_STRING_LENGTH(node) > length + 1) - return false; - if (TREE_STRING_LENGTH(node) == length + 1 && - TREE_STRING_POINTER(node)[length] != '\0') - return false; - return !memcmp(TREE_STRING_POINTER(node), string, length); -} -#define STRING_EQUAL(node, str) string_equal(node, str, strlen(str)) - static bool stackleak_gate(void) { tree section; @@ -457,13 +440,13 @@ static bool stackleak_gate(void) if (section && TREE_VALUE(section)) { section = TREE_VALUE(TREE_VALUE(section)); - if (STRING_EQUAL(section, ".init.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10)) return false; - if (STRING_EQUAL(section, ".devinit.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13)) return false; - if (STRING_EQUAL(section, ".cpuinit.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13)) return false; - if (STRING_EQUAL(section, ".meminit.text")) + if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13)) return false; } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index c4e9a70a0be7a0b476ac360eb4f71287a21b265d..fab2dc30b5f47c54a9b1e6370495216caac144f4 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -62,7 +62,7 @@ static int __init evm_set_fixmode(char *str) else pr_err("invalid \"%s\" mode", str); - return 1; + return 0; } __setup("evm=", evm_set_fixmode); diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c index 63e5c646f76207959d8b3485a4733829be0c26dd..931d8dfb4a7f42172a934236d046d19de4130c86 100644 --- a/security/keys/keyctl_pkey.c +++ b/security/keys/keyctl_pkey.c @@ -135,23 +135,15 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par switch (op) { case KEYCTL_PKEY_ENCRYPT: - if (uparams.in_len > info.max_dec_size || - uparams.out_len > info.max_enc_size) - return -EINVAL; - break; case KEYCTL_PKEY_DECRYPT: if (uparams.in_len > info.max_enc_size || uparams.out_len > info.max_dec_size) return -EINVAL; break; case KEYCTL_PKEY_SIGN: - if (uparams.in_len > info.max_data_size || - uparams.out_len > info.max_sig_size) - return -EINVAL; - break; case KEYCTL_PKEY_VERIFY: - if (uparams.in_len > info.max_data_size || - uparams.in2_len > info.max_sig_size) + if (uparams.in_len > info.max_sig_size || + uparams.out_len > info.max_data_size) return -EINVAL; break; default: @@ -159,7 +151,7 @@ static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_par } params->in_len = uparams.in_len; - params->out_len = uparams.out_len; /* Note: same as in2_len */ + params->out_len = uparams.out_len; return 0; } diff --git a/security/security.c b/security/security.c index baa63edb53e29be016a5927c5a55c743887135c0..1e0f79c665a34478f301bffa48d6dd9e81139802 100644 --- a/security/security.c +++ b/security/security.c @@ -826,22 +826,9 @@ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) return call_int_hook(fs_context_dup, 0, fc, src_fc); } -int security_fs_context_parse_param(struct fs_context *fc, - struct fs_parameter *param) +int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct security_hook_list *hp; - int trc; - int rc = -ENOPARAM; - - hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param, - list) { - trc = hp->hook.fs_context_parse_param(fc, param); - if (trc == 0) - rc = 0; - else if (trc != -ENOPARAM) - return trc; - } - return rc; + return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param); } int security_sb_alloc(struct super_block *sb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3024b84e687100f788162b4763df39e085b3db49..56a6a7056388f177c6fd88d9c91645fe30783dd6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2823,9 +2823,10 @@ static int selinux_fs_context_parse_param(struct fs_context *fc, return opt; rc = selinux_add_opt(opt, param->string, &fc->security); - if (!rc) + if (!rc) { param->string = NULL; - + rc = 1; + } return rc; } @@ -3706,12 +3707,6 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, CAP_OPT_NONE, true); break; - case FIOCLEX: - case FIONCLEX: - if (!selinux_policycap_ioctl_skip_cloexec()) - error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); - break; - /* default case assumes that the command will go * to the file's ioctl() function. */ diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h index a9e572ca4fd96d00ea26c917c25f6c91d552475f..2ec038efbb03cc53d4e2c5780641f213dadd9894 100644 --- a/security/selinux/include/policycap.h +++ b/security/selinux/include/policycap.h @@ -11,7 +11,6 @@ enum { POLICYDB_CAPABILITY_CGROUPSECLABEL, POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION, POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS, - POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h index ebd64afe1defd13dfb20fd9f9fd05c54f61f218f..b89289f092c938ede5c28b293cfb3f51e7d3979c 100644 --- a/security/selinux/include/policycap_names.h +++ b/security/selinux/include/policycap_names.h @@ -12,8 +12,7 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { "always_check_network", "cgroup_seclabel", "nnp_nosuid_transition", - "genfs_seclabel_symlinks", - "ioctl_skip_cloexec" + "genfs_seclabel_symlinks" }; #endif /* _SELINUX_POLICYCAP_NAMES_H_ */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index cefd6e2a5ea88c90d1231b0ac441cb51975597f1..a2c0cf6293cad1257974014946e8992332992b69 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -221,13 +221,6 @@ static inline bool selinux_policycap_genfs_seclabel_symlinks(void) return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]); } -static inline bool selinux_policycap_ioctl_skip_cloexec(void) -{ - struct selinux_state *state = &selinux_state; - - return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_IOCTL_SKIP_CLOEXEC]); -} - static inline bool selinux_android_nlroute_getlink(void) { struct selinux_state *state = &selinux_state; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d893c2280f595e084cab2089593cd1410eb8b167..2b745ae8cb9814a5862534c93f9da482072d1136 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -2124,8 +2124,6 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) } ret = sel_make_avc_files(dentry); - if (ret) - goto err; dentry = sel_make_dir(sb->s_root, "ss", &fsi->last_ino); if (IS_ERR(dentry)) { diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 00e95f8bd7c73ff05a2105e902b547540754f8cb..7314196185d15f4f357cc2553d860a69af6fe80e 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -346,7 +346,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, int rc; struct xfrm_sec_ctx *ctx; char *ctx_str = NULL; - u32 str_len; + int str_len; if (!polsec) return 0; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d24b9700ebf92685a45cc16ba51849a2ec028eff..fe8d33b287f5c9d65a0f28aa73311933b29690c3 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2507,7 +2507,7 @@ static int smk_ipv6_check(struct smack_known *subject, #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = PF_INET6; - ad.a.u.net->dport = address->sin6_port; + ad.a.u.net->dport = ntohs(address->sin6_port); if (act == SMK_RECEIVING) ad.a.u.net->v6info.saddr = address->sin6_addr; else diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c index 363b65be87ab768ed4993df1e5a361892958b3ab..3445ae6fd4794eaf430384ec63622004bc93f8fb 100644 --- a/security/tomoyo/load_policy.c +++ b/security/tomoyo/load_policy.c @@ -24,7 +24,7 @@ static const char *tomoyo_loader; static int __init tomoyo_loader_setup(char *str) { tomoyo_loader = str; - return 1; + return 0; } __setup("TOMOYO_loader=", tomoyo_loader_setup); @@ -64,7 +64,7 @@ static const char *tomoyo_trigger; static int __init tomoyo_trigger_setup(char *str) { tomoyo_trigger = str; - return 1; + return 0; } __setup("TOMOYO_trigger=", tomoyo_trigger_setup); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index f88de74da1eb36d889886b9637264719b21bb182..d79febeebf0c591725703112330e020426ab7669 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -774,11 +774,6 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, if (oss_period_size < 16) return -EINVAL; - - /* don't allocate too large period; 1MB period must be enough */ - if (oss_period_size > 1024 * 1024) - return -ENOMEM; - runtime->oss.period_bytes = oss_period_size; runtime->oss.period_frames = 1; runtime->oss.periods = oss_periods; @@ -1047,9 +1042,10 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) goto failure; } #endif - oss_period_size = array_size(oss_period_size, oss_frame_size); - oss_buffer_size = array_size(oss_period_size, runtime->oss.periods); - if (oss_buffer_size <= 0) { + oss_period_size *= oss_frame_size; + + oss_buffer_size = oss_period_size * runtime->oss.periods; + if (oss_buffer_size < 0) { err = -EINVAL; goto failure; } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 1e2d1b35c1946cdc768d4b453833c5b4e0b90778..d5ca161d588c504fa79257a300a958313b98c74d 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -61,10 +61,7 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t } if ((width = snd_pcm_format_physical_width(format->format)) < 0) return width; - size = array3_size(frames, format->channels, width); - /* check for too large period size once again */ - if (size > 1024 * 1024) - return -ENOMEM; + size = frames * format->channels * width; if (snd_BUG_ON(size % 8)) return -ENXIO; size /= 8; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 59d222446d77738b25af374aa15dab527767a2e2..a8ae5928decdad11d29699114ea8dea3757a37c2 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -969,8 +969,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, init_waitqueue_head(&runtime->tsleep); runtime->status->state = SNDRV_PCM_STATE_OPEN; - mutex_init(&runtime->buffer_mutex); - atomic_set(&runtime->buffer_accessing, 0); substream->runtime = runtime; substream->private_data = pcm->private_data; @@ -1004,7 +1002,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) } else { substream->runtime = NULL; } - mutex_destroy(&runtime->buffer_mutex); kfree(runtime); put_pid(substream->pid); substream->pid = NULL; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 289f52af15b96b16a94b3572fb73eee720fafc8b..5e04c4b9e02399cd1cd697dbadd1a23ceb8a7da6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2221,15 +2221,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, err = -EINVAL; goto _end_unlock; } - if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) { - err = -EBUSY; - goto _end_unlock; - } snd_pcm_stream_unlock_irq(substream); err = writer(substream, appl_ofs, data, offset, frames, transfer); snd_pcm_stream_lock_irq(substream); - atomic_dec(&runtime->buffer_accessing); if (err < 0) goto _end_unlock; err = pcm_accessible_state(runtime); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index a9a0d74f31656c976c1102aa3978179b7b6e6c66..4f03ba8ed0ae597ca01547c811f3e6058e8efb87 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -164,20 +164,19 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, size_t size; struct snd_dma_buffer new_dmab; - mutex_lock(&substream->pcm->open_mutex); if (substream->runtime) { buffer->error = -EBUSY; - goto unlock; + return; } if (!snd_info_get_line(buffer, line, sizeof(line))) { snd_info_get_str(str, line, sizeof(str)); size = simple_strtoul(str, NULL, 10) * 1024; if ((size != 0 && size < 8192) || size > substream->dma_max) { buffer->error = -EINVAL; - goto unlock; + return; } if (substream->dma_buffer.bytes == size) - goto unlock; + return; memset(&new_dmab, 0, sizeof(new_dmab)); new_dmab.dev = substream->dma_buffer.dev; if (size > 0) { @@ -186,7 +185,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, substream->dma_buffer.dev.dev, size, &new_dmab) < 0) { buffer->error = -ENOMEM; - goto unlock; + return; } substream->buffer_bytes_max = size; } else { @@ -198,8 +197,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, } else { buffer->error = -EINVAL; } - unlock: - mutex_unlock(&substream->pcm->open_mutex); } static inline void preallocate_info_init(struct snd_pcm_substream *substream) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 6cc7c2a9fe732de3c32392428d05e95fff7f9b51..c5ef5182fcf1907676bca812d544a3624ffb1fa0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -667,30 +667,6 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, return 0; } -/* acquire buffer_mutex; if it's in r/w operation, return -EBUSY, otherwise - * block the further r/w operations - */ -static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime) -{ - if (!atomic_dec_unless_positive(&runtime->buffer_accessing)) - return -EBUSY; - mutex_lock(&runtime->buffer_mutex); - return 0; /* keep buffer_mutex, unlocked by below */ -} - -/* release buffer_mutex and clear r/w access flag */ -static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) -{ - mutex_unlock(&runtime->buffer_mutex); - atomic_inc(&runtime->buffer_accessing); -} - -#if IS_ENABLED(CONFIG_SND_PCM_OSS) -#define is_oss_stream(substream) ((substream)->oss.oss) -#else -#define is_oss_stream(substream) false -#endif - static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -702,25 +678,22 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - err = snd_pcm_buffer_access_lock(runtime); - if (err < 0) - return err; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: - if (!is_oss_stream(substream) && - atomic_read(&substream->mmap_count)) - err = -EBADFD; break; default: - err = -EBADFD; - break; + snd_pcm_stream_unlock_irq(substream); + return -EBADFD; } snd_pcm_stream_unlock_irq(substream); - if (err) - goto unlock; +#if IS_ENABLED(CONFIG_SND_PCM_OSS) + if (!substream->oss.oss) +#endif + if (atomic_read(&substream->mmap_count)) + return -EBADFD; snd_pcm_sync_stop(substream, true); @@ -807,21 +780,16 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if ((usecs = period_to_usecs(runtime)) >= 0) cpu_latency_qos_add_request(&substream->latency_pm_qos_req, usecs); - err = 0; + return 0; _error: - if (err) { - /* hardware might be unusable from this time, - * so we force application to retry to set - * the correct hardware parameter settings - */ - snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); - if (substream->ops->hw_free != NULL) - substream->ops->hw_free(substream); - if (substream->managed_buffer_alloc) - snd_pcm_lib_free_pages(substream); - } - unlock: - snd_pcm_buffer_access_unlock(runtime); + /* hardware might be unusable from this time, + so we force application to retry to set + the correct hardware parameter settings */ + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); + if (substream->ops->hw_free != NULL) + substream->ops->hw_free(substream); + if (substream->managed_buffer_alloc) + snd_pcm_lib_free_pages(substream); return err; } @@ -861,33 +829,26 @@ static int do_hw_free(struct snd_pcm_substream *substream) static int snd_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - int result = 0; + int result; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - result = snd_pcm_buffer_access_lock(runtime); - if (result < 0) - return result; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: - if (atomic_read(&substream->mmap_count)) - result = -EBADFD; break; default: - result = -EBADFD; - break; + snd_pcm_stream_unlock_irq(substream); + return -EBADFD; } snd_pcm_stream_unlock_irq(substream); - if (result) - goto unlock; + if (atomic_read(&substream->mmap_count)) + return -EBADFD; result = do_hw_free(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); - unlock: - snd_pcm_buffer_access_unlock(runtime); return result; } @@ -1193,17 +1154,15 @@ struct action_ops { static int snd_pcm_action_group(const struct action_ops *ops, struct snd_pcm_substream *substream, snd_pcm_state_t state, - bool stream_lock) + bool do_lock) { struct snd_pcm_substream *s = NULL; struct snd_pcm_substream *s1; int res = 0, depth = 1; snd_pcm_group_for_each_entry(s, substream) { - if (s != substream) { - if (!stream_lock) - mutex_lock_nested(&s->runtime->buffer_mutex, depth); - else if (s->pcm->nonatomic) + if (do_lock && s != substream) { + if (s->pcm->nonatomic) mutex_lock_nested(&s->self_group.mutex, depth); else spin_lock_nested(&s->self_group.lock, depth); @@ -1231,18 +1190,18 @@ static int snd_pcm_action_group(const struct action_ops *ops, ops->post_action(s, state); } _unlock: - /* unlock streams */ - snd_pcm_group_for_each_entry(s1, substream) { - if (s1 != substream) { - if (!stream_lock) - mutex_unlock(&s1->runtime->buffer_mutex); - else if (s1->pcm->nonatomic) - mutex_unlock(&s1->self_group.mutex); - else - spin_unlock(&s1->self_group.lock); + if (do_lock) { + /* unlock streams */ + snd_pcm_group_for_each_entry(s1, substream) { + if (s1 != substream) { + if (s1->pcm->nonatomic) + mutex_unlock(&s1->self_group.mutex); + else + spin_unlock(&s1->self_group.lock); + } + if (s1 == s) /* end */ + break; } - if (s1 == s) /* end */ - break; } return res; } @@ -1372,15 +1331,10 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, /* Guarantee the group members won't change during non-atomic action */ down_read(&snd_pcm_link_rwsem); - res = snd_pcm_buffer_access_lock(substream->runtime); - if (res < 0) - goto unlock; if (snd_pcm_stream_linked(substream)) res = snd_pcm_action_group(ops, substream, state, false); else res = snd_pcm_action_single(ops, substream, state); - snd_pcm_buffer_access_unlock(substream->runtime); - unlock: up_read(&snd_pcm_link_rwsem); return res; } @@ -1875,13 +1829,11 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); if (err < 0) return err; - snd_pcm_stream_lock_irq(substream); runtime->hw_ptr_base = 0; runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; - snd_pcm_stream_unlock_irq(substream); return 0; } @@ -1889,12 +1841,10 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); runtime->control->appl_ptr = runtime->status->hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - snd_pcm_stream_unlock_irq(substream); } static const struct action_ops snd_pcm_action_reset = { diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c index df44dd5dc4b229785e3dac955105e4da27dbcccf..bbfbebf4affbc20964e52c5553381facbd7f4118 100644 --- a/sound/firewire/fcp.c +++ b/sound/firewire/fcp.c @@ -240,7 +240,9 @@ int fcp_avc_transaction(struct fw_unit *unit, t.response_match_bytes = response_match_bytes; t.state = STATE_PENDING; init_waitqueue_head(&t.wait); - t.deferrable = (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03); + + if (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03) + t.deferrable = true; spin_lock_irq(&transactions_lock); list_add_tail(&t.list, &transactions); diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 9ee3a312c6793248e7752bf8b3691b4b43fd5dce..fa3c39cff5f854a88b602feb832fa174624f3a84 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -544,7 +544,7 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, static int dev; int err; struct snd_card *card; - struct pnp_dev *cdev, *iter; + struct pnp_dev *cdev; char cid[PNP_ID_LEN]; if (pnp_device_is_isapnp(pdev)) @@ -560,11 +560,9 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev, strcpy(cid, pdev->id[0].id); cid[5] = '1'; cdev = NULL; - list_for_each_entry(iter, &(pdev->protocol->devices), protocol_list) { - if (!strcmp(iter->id[0].id, cid)) { - cdev = iter; + list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) { + if (!strcmp(cdev->id[0].id, cid)) break; - } } err = snd_cs423x_card_new(&pdev->dev, dev, &card); if (err < 0) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 963731cf0d8c880f6c5ba5c9235dad01ca040ac5..012a7ee849e8aad424e82752c73250b5d0a0d845 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -938,8 +938,8 @@ static int snd_ac97_ad18xx_pcm_get_volume(struct snd_kcontrol *kcontrol, struct int codec = kcontrol->private_value & 3; mutex_lock(&ac97->page_mutex); - ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); - ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); + ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); + ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); mutex_unlock(&ac97->page_mutex); return 0; } diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 120dd8b33ac81ca825dc11748e3202f12b47adbb..7363d61eaec23fc6754d5d39dbf8717dfc9d1d89 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -302,6 +302,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_MICGAINZ 0x01 /* mic boost */ #define CM_MICGAINZ_SHIFT 0 +#define CM_REG_MIXER3 0x24 #define CM_REG_AUX_VOL 0x26 #define CM_VAUXL_MASK 0xf0 #define CM_VAUXR_MASK 0x0f @@ -3290,7 +3291,7 @@ static void snd_cmipci_remove(struct pci_dev *pci) */ static const unsigned char saved_regs[] = { CM_REG_FUNCTRL1, CM_REG_CHFORMAT, CM_REG_LEGACY_CTRL, CM_REG_MISC_CTRL, - CM_REG_MIXER0, CM_REG_MIXER1, CM_REG_MIXER2, CM_REG_AUX_VOL, CM_REG_PLL, + CM_REG_MIXER0, CM_REG_MIXER1, CM_REG_MIXER2, CM_REG_MIXER3, CM_REG_PLL, CM_REG_CH0_FRAME1, CM_REG_CH0_FRAME2, CM_REG_CH1_FRAME1, CM_REG_CH1_FRAME2, CM_REG_EXT_MISC, CM_REG_INT_STATUS, CM_REG_INT_HLDCLR, CM_REG_FUNCTRL0, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71e11481ba41c553d4c6860df329733da9678c2d..fe725f0f093124d8f9bbe867a7034d4c796a04a8 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1608,7 +1608,6 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, struct hda_codec *codec = per_pin->codec; struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld = &spec->temp_eld; - struct device *dev = hda_codec_dev(codec); hda_nid_t pin_nid = per_pin->pin_nid; int dev_id = per_pin->dev_id; /* @@ -1622,13 +1621,8 @@ static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, int present; int ret; -#ifdef CONFIG_PM - if (dev->power.runtime_status == RPM_SUSPENDING) - return; -#endif - ret = snd_hda_power_up_pm(codec); - if (ret < 0 && pm_runtime_suspended(dev)) + if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec))) goto out; present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b886326ce9b96a2a6cef3ac691dc985c5f1830c3..ed0cfcb05ef0d4ee0243a1ed4d47ea17a494313f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3615,8 +3615,8 @@ static void alc256_shutup(struct hda_codec *codec) /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly * when booting with headset plugged. So skip setting it for the codec alc257 */ - if (codec->core.vendor_id != 0x10ec0236 && - codec->core.vendor_id != 0x10ec0257) + if (spec->codec_variant != ALC269_TYPE_ALC257 && + spec->codec_variant != ALC269_TYPE_ALC256) alc_update_coef_idx(codec, 0x46, 0, 3 << 12); if (!spec->no_shutup_pins) @@ -6762,7 +6762,6 @@ enum { ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, - ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS, ALC269VC_FIXUP_ACER_HEADSET_MIC, @@ -8084,14 +8083,6 @@ static const struct hda_fixup alc269_fixups[] = { { } }, }, - [ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x08}, - { 0x20, AC_VERB_SET_PROC_COEF, 0x2fcf}, - { } - }, - }, [ALC295_FIXUP_ASUS_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -8810,7 +8801,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), @@ -8844,7 +8834,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), @@ -8895,8 +8884,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x8561, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[5|7][0-9]RZ[Q]", ALC269_FIXUP_DMIC), SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x866d, "Clevo NP5[05]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1558, 0x867d, "Clevo NP7[01]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME), SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -9187,7 +9174,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"}, - {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"}, {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, {.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"}, @@ -10853,7 +10839,6 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), - SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 97533412ce11e8457d7513e8b804ffbaf9dd69e7..6a63e8797a0b6b5ecd58076dd1cd751dd81a1afd 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -280,10 +280,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, /* Enable PMC peripheral clock for this SSC */ pr_debug("atmel_ssc_dai: Starting clock\n"); - ret = clk_enable(ssc_p->ssc->clk); - if (ret) - return ret; - + clk_enable(ssc_p->ssc->clk); ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk); /* Reset the SSC unless initialized to keep it in a clean state */ diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 8a55d59a6c2aa97bc7680287479d0a1c9dd2859d..ed1f69b570244f7078cc2c31a987a21c6153b901 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -214,7 +214,6 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); if (!cpu_np) { dev_err(&pdev->dev, "dai and pcm info missing\n"); - of_node_put(codec_np); return -EINVAL; } at91sam9g20ek_dai.cpus->of_node = cpu_np; diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c index 529604a06c53207303cf76e968e7f6a31a2d132e..9fbc3c1113cc5ecb2bb6bb7b3ad6e73ddb2ec04c 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -142,7 +142,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) if (!cpu_np) { dev_err(&pdev->dev, "atmel,ssc-controller node missing\n"); ret = -EINVAL; - goto out_put_codec_np; + goto out; } dai->cpus->of_node = cpu_np; dai->platforms->of_node = cpu_np; @@ -153,10 +153,13 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "Failed to set SSC %d for audio: %d\n", ret, priv->ssc_id); - goto out_put_cpu_np; + goto out; } - ret = devm_snd_soc_register_card(&pdev->dev, card); + of_node_put(codec_np); + of_node_put(cpu_np); + + ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "Platform device allocation failed\n"); goto out_put_audio; @@ -164,14 +167,10 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s ok\n", __func__); - goto out_put_cpu_np; + return ret; out_put_audio: atmel_ssc_put_audio(priv->ssc_id); -out_put_cpu_np: - of_node_put(cpu_np); -out_put_codec_np: - of_node_put(codec_np); out: return ret; } @@ -181,6 +180,7 @@ static int sam9x5_wm8731_driver_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct sam9x5_drvdata *priv = card->drvdata; + snd_soc_unregister_card(card); atmel_ssc_put_audio(priv->ssc_id); return 0; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 52c89a6f54e9a6b53e6ea41d88fd5cf8700e220d..34c6dd04b85a3c9e2619fa1d27a210bf2e484a8f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -659,7 +659,6 @@ config SND_SOC_CS4349 config SND_SOC_CS47L15 tristate - depends on MFD_CS47L15 config SND_SOC_CS47L24 tristate @@ -667,19 +666,15 @@ config SND_SOC_CS47L24 config SND_SOC_CS47L35 tristate - depends on MFD_CS47L35 config SND_SOC_CS47L85 tristate - depends on MFD_CS47L85 config SND_SOC_CS47L90 tristate - depends on MFD_CS47L90 config SND_SOC_CS47L92 tristate - depends on MFD_CS47L92 # Cirrus Logic Quad-Channel ADC config SND_SOC_CS53L30 diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 971b8360b5b1be05a73afa6c412332c6092b1c42..3ddd822240e3aa05fc8381f1aebf11be933fb723 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1221,10 +1221,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1236,10 +1234,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1250,10 +1246,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) { - ret = irq; - goto err_disable_clk; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, @@ -1270,10 +1264,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &pm8916_wcd_analog, pm8916_wcd_analog_dai, ARRAY_SIZE(pm8916_wcd_analog_dai)); - -err_disable_clk: - clk_disable_unprepare(priv->mclk); - return ret; } static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 9ad7fc0baf072678b40063b96fa8450738b06d70..fcc10c8bc625951c9ffb12699cf05f3fb6f4b50b 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1201,7 +1201,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) ret = clk_prepare_enable(priv->mclk); if (ret < 0) { dev_err(dev, "failed to enable mclk %d\n", ret); - goto err_clk; + return ret; } dev_set_drvdata(dev, priv); @@ -1209,9 +1209,6 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) return devm_snd_soc_register_component(dev, &msm8916_wcd_digital, msm8916_wcd_digital_dai, ARRAY_SIZE(msm8916_wcd_digital_dai)); -err_clk: - clk_disable_unprepare(priv->ahbclk); - return ret; } static int msm8916_wcd_digital_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 456d9b24d0249e9bad4ced42de6d82ab0677dd4c..1f39d5998cf67518807f04fd30ddd7306af7132c 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -107,7 +107,6 @@ int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, priv->mtkaif_protocol = mtkaif_protocol; return 0; } -EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_protocol); static void playback_gpio_set(struct mt6358_priv *priv) { @@ -274,7 +273,6 @@ int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); return 0; } -EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable); int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) { @@ -298,7 +296,6 @@ int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) capture_gpio_reset(priv); return 0; } -EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable); int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, int phase_1, int phase_2) @@ -313,7 +310,6 @@ int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); return 0; } -EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase); /* dl pga gain */ enum { diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 4423e61bf1abf611380a2ffbff14427a0f8f6e06..db8a41aaa3859c15a5735852126c4383575fee92 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3478,8 +3478,6 @@ static int rt5663_parse_dp(struct rt5663_priv *rt5663, struct device *dev) table_size = sizeof(struct impedance_mapping_table) * rt5663->pdata.impedance_sensing_num; rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL); - if (!rt5663->imp_table) - return -ENOMEM; ret = device_property_read_u32_array(dev, "realtek,impedance_sensing_table", (u32 *)rt5663->imp_table, table_size); diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 8540ac230d0eda3115736cc608789c4412d1ea7f..01df3f4e045a9e18bcd5a7a396348d2fcd776c6b 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -2522,16 +2522,13 @@ static int wcd934x_rx_hph_mode_put(struct snd_kcontrol *kc, mode_val = ucontrol->value.enumerated.item[0]; - if (mode_val == wcd->hph_mode) - return 0; - if (mode_val == 0) { dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); mode_val = CLS_H_LOHIFI; } wcd->hph_mode = mode_val; - return 1; + return 0; } static int slim_rx_mux_get(struct snd_kcontrol *kc, @@ -5047,7 +5044,6 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd) } wcd->sidev = of_slim_get_device(wcd->sdev->ctrl, ifc_dev_np); - of_node_put(ifc_dev_np); if (!wcd->sidev) { dev_err(dev, "Unable to get SLIM Interface device\n"); return -EINVAL; diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index ec5d997725b9c10f3c875972aef7870af53547b2..a6aa212fa0c89faa2865755cf68da635226f27a6 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1536,38 +1536,18 @@ static int wm8350_component_probe(struct snd_soc_component *component) wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, wm8350_hpl_jack_handler, 0, "Left jack detect", priv); - if (ret != 0) - goto err; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, wm8350_hpr_jack_handler, 0, "Right jack detect", priv); - if (ret != 0) - goto free_jck_det_l; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, wm8350_mic_handler, 0, "Microphone short", priv); - if (ret != 0) - goto free_jck_det_r; - - ret = wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, wm8350_mic_handler, 0, "Microphone detect", priv); - if (ret != 0) - goto free_micscd; return 0; - -free_micscd: - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv); -free_jck_det_r: - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); -free_jck_det_l: - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); -err: - return ret; } static void wm8350_component_remove(struct snd_soc_component *component) diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 36da0f01571a111f899fc12c60bab3cde08efde6..fd4160289faca7b44b8f6feb13d60bf8b4f4c491 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -403,13 +403,9 @@ static int dw_i2s_runtime_suspend(struct device *dev) static int dw_i2s_runtime_resume(struct device *dev) { struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); - int ret; - if (dw_dev->capability & DW_I2S_MASTER) { - ret = clk_enable(dw_dev->clk); - if (ret) - return ret; - } + if (dw_dev->capability & DW_I2S_MASTER) + clk_enable(dw_dev->clk); return 0; } @@ -426,13 +422,10 @@ static int dw_i2s_resume(struct snd_soc_component *component) { struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); struct snd_soc_dai *dai; - int stream, ret; + int stream; - if (dev->capability & DW_I2S_MASTER) { - ret = clk_enable(dev->clk); - if (ret) - return ret; - } + if (dev->capability & DW_I2S_MASTER) + clk_enable(dev->clk); for_each_component_dais(component, dai) { for_each_pcm_streams(stream) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index d01e8d516df1f8da072031f5cdf77fc2fff76f50..15bcb0f38ec9e89f5a6c9f161b8d00572ff4e390 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -544,8 +544,6 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; - /* Disable TX clock */ - regmap_update_bits(regmap, REG_SPDIF_STC, STC_TXCLK_ALL_EN_MASK, 0); } else { scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 9e602c3456196c5a86ddfb4abf084b577da4ee91..fad1eb6253d53e66aa7646337fc0de34c5745f78 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -87,7 +87,6 @@ static int imx_es8328_probe(struct platform_device *pdev) if (int_port > MUX_PORT_MAX || int_port == 0) { dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", MUX_PORT_MAX); - ret = -EINVAL; goto fail; } diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d0d79f47bfdd50401099c9ce2a0ab9aba3817eb4..6cada4c1e283befe3c52848bda0340f082696a88 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -255,7 +255,7 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream, struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; - int ret; + int ret = 0; if (dai_props->mclk_fs) mclk_fs = dai_props->mclk_fs; diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index f2eda81985e27fd151a5ce7430c9f2a2ea516396..07f8cf9980e31afe73d3b695e7dd2f8f3f1a3de2 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -455,10 +455,7 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, * basic clock which should be fast enough for the internal * logic. */ - ret = clk_enable(saif->clk); - if (ret) - return ret; - + clk_enable(saif->clk); ret = clk_set_rate(saif->clk, 24000000); clk_disable(saif->clk); if (ret) diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index fb721bc499496b18b68057b467fa9ae14082503f..a6407f4388de7de3fde2ebb8cb9ec032f6c09eaa 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -118,9 +118,6 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) codec_np = of_parse_phandle(np, "audio-codec", 0); if (!saif_np[0] || !saif_np[1] || !codec_np) { dev_err(&pdev->dev, "phandle missing or invalid\n"); - of_node_put(codec_np); - of_node_put(saif_np[0]); - of_node_put(saif_np[1]); return -EINVAL; } diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 785baf98f9da25387a568cb0f1efd2b70c3cd3b5..fa84ec695b5251903e661cc05567e5796a1c27a9 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -624,23 +624,20 @@ static int rockchip_i2s_probe(struct platform_device *pdev) i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); if (IS_ERR(i2s->mclk)) { dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); - ret = PTR_ERR(i2s->mclk); - goto err_clk; + return PTR_ERR(i2s->mclk); } - regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); - goto err_clk; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &rockchip_i2s_regmap_config); if (IS_ERR(i2s->regmap)) { dev_err(&pdev->dev, "Failed to initialise managed register map\n"); - ret = PTR_ERR(i2s->regmap); - goto err_clk; + return PTR_ERR(i2s->regmap); } i2s->playback_dma_data.addr = res->start + I2S_TXDR; @@ -699,8 +696,7 @@ err_suspend: i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk: - clk_disable_unprepare(i2s->hclk); + return ret; } diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0fa72907d5bf14658be2e23ec08fcec358a2b483..3c574792231bc5c376d201838f497bd3cb063744 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -816,27 +816,14 @@ static int fsi_clk_enable(struct device *dev, return ret; } - ret = clk_enable(clock->xck); - if (ret) - goto err; - ret = clk_enable(clock->ick); - if (ret) - goto disable_xck; - ret = clk_enable(clock->div); - if (ret) - goto disable_ick; + clk_enable(clock->xck); + clk_enable(clock->ick); + clk_enable(clock->div); clock->count++; } return ret; - -disable_ick: - clk_disable(clock->ick); -disable_xck: - clk_disable(clock->xck); -err: - return ret; } static int fsi_clk_disable(struct device *dev, diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index d0f3ff8edd904e2b9765c939c219786412dd9163..3a6a60215e815cf1535828759d86a6667a416712 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -766,11 +766,6 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) return -EINVAL; } - if (!codec_dai) { - dev_err(rtd->card->dev, "Missing codec\n"); - return -EINVAL; - } - /* check client and interface hw capabilities */ if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ea145eedcb68d93b7d2e82fd83823b6fcaeeecca..19f6ff047cddc9fdb47dd2d27dd87bfb4439be6a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3053,7 +3053,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, for_each_component(pos) { component_of_node = soc_component_to_node(pos); - if (component_of_node != args->np || !pos->num_dai) + if (component_of_node != args->np) continue; ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 0d100b4e43f7ef6489cbc4a12ff7de91bde2f7dd..9ef80a48707eb6583ff51ec278c1a5b035970ba1 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -83,10 +83,10 @@ static int dmaengine_pcm_hw_params(struct snd_soc_component *component, memset(&slave_config, 0, sizeof(slave_config)); - if (pcm->config && pcm->config->prepare_slave_config) - prepare_slave_config = pcm->config->prepare_slave_config; - else + if (!pcm->config) prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; + else + prepare_slave_config = pcm->config->prepare_slave_config; if (prepare_slave_config) { ret = prepare_slave_config(substream, params, &slave_config); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 23a5f9a52da0fddf8ea0b95d3910811893deee70..4d24ac255d2532a64def67a2b04a9011a05ef087 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -578,8 +578,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, if (le32_to_cpu(hdr->ops.info) == SND_SOC_TPLG_CTL_BYTES && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER - && (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ - || k->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) + && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { struct soc_bytes_ext *sbe; struct snd_soc_tplg_bytes_control *be; diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 6943c05273ae7b7068cc33c7682b3d0860598ec2..cb822d9537678d0e9e9972bd47375054cfdefaa0 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -191,7 +191,6 @@ static int imx8m_probe(struct snd_sof_dev *sdev) } ret = of_address_to_resource(res_node, 0, &res); - of_node_put(res_node); if (ret) { dev_err(&pdev->dev, "failed to get reserved region address\n"); goto exit_pdev_unregister; diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 347636a80b48765109274604b6d9e775775a7162..2707a16c6a4d3db863fe6d322f705f468fdde48d 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -47,7 +47,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); if (ret < 0) { dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret); - goto out_put; + goto error; } hstream->period_bytes = 0;/* initialize period_bytes */ @@ -58,23 +58,22 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret); - goto out_free; + goto error; } } else { ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); - goto out_free; + goto error; } hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); } return dsp_stream; -out_free: - snd_dma_free_pages(dmab); -out_put: +error: hda_dsp_stream_put(sdev, direction, hstream->stream_tag); + snd_dma_free_pages(dmab); return ERR_PTR(ret); } diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index dd9013c4766491af0980e74020c4dcfb4d4d17a2..2ed92c990b97c1c0d663b9a4c9b023507db580f2 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -91,7 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); /* Stop the player */ - snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(player->substream); } ret = IRQ_HANDLED; @@ -105,7 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); /* Stop the player */ - snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(player->substream); ret = IRQ_HANDLED; } @@ -138,7 +138,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) dev_err(player->dev, "Underflow recovery failed\n"); /* Stop the player */ - snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(player->substream); ret = IRQ_HANDLED; } diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 065c5f0d1f5f00c65715ccde98360816ddbf67a9..136059331211d2c37da46dff52e332534f95bb39 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -65,7 +65,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { dev_err(reader->dev, "FIFO error detected\n"); - snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stop_xrun(reader->substream); ret = IRQ_HANDLED; } diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 4895bcee1f5578c24bf5da64505317f74b536d3f..dd34504c09ba8178ab5fff4882a3735df46181f6 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -708,9 +708,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return -ENODEV; - ret = clk_enable(dev->clk); - if (ret) - goto err_put_clk; + clk_enable(dev->clk); dev->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, dev); @@ -732,7 +730,6 @@ err_unregister_component: snd_soc_unregister_component(&pdev->dev); err_release_clk: clk_disable(dev->clk); -err_put_clk: clk_put(dev->clk); return ret; } diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index 5c4158069a5a893ebf7cfec6d7a6249c353c68df..ce19a6058b27964dfcd45336770b2e7cdd417cec 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -84,7 +84,6 @@ struct xlnx_pcm_drv_data { struct snd_pcm_substream *play_stream; struct snd_pcm_substream *capture_stream; struct clk *axi_clk; - unsigned int sysclk; }; /* @@ -315,15 +314,6 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg) return IRQ_NONE; } -static int xlnx_formatter_set_sysclk(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, int dir) -{ - struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); - - adata->sysclk = freq; - return 0; -} - static int xlnx_formatter_pcm_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -460,25 +450,11 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component, u64 size; struct snd_pcm_runtime *runtime = substream->runtime; struct xlnx_pcm_stream_param *stream_data = runtime->private_data; - struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); active_ch = params_channels(params); if (active_ch > stream_data->ch_limit) return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - adata->sysclk) { - unsigned int mclk_fs = adata->sysclk / params_rate(params); - - if (adata->sysclk % params_rate(params) != 0) { - dev_warn(component->dev, "sysclk %u not divisible by rate %u\n", - adata->sysclk, params_rate(params)); - return -EINVAL; - } - - writel(mclk_fs, stream_data->mmio + XLNX_AUD_FS_MULTIPLIER); - } - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && stream_data->xfer_mode == AES_TO_PCM) { val = readl(stream_data->mmio + XLNX_AUD_STS); @@ -576,7 +552,6 @@ static int xlnx_formatter_pcm_new(struct snd_soc_component *component, static const struct snd_soc_component_driver xlnx_asoc_component = { .name = DRV_NAME, - .set_sysclk = xlnx_formatter_set_sysclk, .open = xlnx_formatter_pcm_open, .close = xlnx_formatter_pcm_close, .hw_params = xlnx_formatter_pcm_hw_params, diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 8a2da6b1012eb97a004f0ac20d244bbc8f8cc390..76c0e37a838cf430f1fdec54b07368c11a05c010 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -218,9 +218,7 @@ static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) runtime->hw = snd_at73c213_playback_hw; chip->substream = substream; - err = clk_enable(chip->ssc->clk); - if (err) - return err; + clk_enable(chip->ssc->clk); return 0; } @@ -778,9 +776,7 @@ static int snd_at73c213_chip_init(struct snd_at73c213 *chip) goto out; /* Enable DAC master clock. */ - retval = clk_enable(chip->board->dac_clk); - if (retval) - goto out; + clk_enable(chip->board->dac_clk); /* Initialize at73c213 on SPI bus. */ retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); @@ -893,9 +889,7 @@ static int snd_at73c213_dev_init(struct snd_card *card, chip->card = card; chip->irq = -1; - retval = clk_enable(chip->ssc->clk); - if (retval) - return retval; + clk_enable(chip->ssc->clk); retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); if (retval) { @@ -1014,9 +1008,7 @@ static int snd_at73c213_remove(struct spi_device *spi) int retval; /* Stop playback. */ - retval = clk_enable(chip->ssc->clk); - if (retval) - goto out; + clk_enable(chip->ssc->clk); ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); clk_disable(chip->ssc->clk); @@ -1096,16 +1088,9 @@ static int snd_at73c213_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct snd_at73c213 *chip = card->private_data; - int retval; - retval = clk_enable(chip->board->dac_clk); - if (retval) - return retval; - retval = clk_enable(chip->ssc->clk); - if (retval) { - clk_disable(chip->board->dac_clk); - return retval; - } + clk_enable(chip->board->dac_clk); + clk_enable(chip->ssc->clk); ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); return 0; diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 81ace832d7e42da21935ef4e2c4c06dbcf17eeb7..8f6823df944fffe5af6e91b83a6fb799d0445a2f 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -542,16 +542,6 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x25c4, 0x0003), .map = scms_usb3318_map, }, - { - /* Corsair Virtuoso SE Latest (wired mode) */ - .id = USB_ID(0x1b1c, 0x0a3f), - .map = corsair_virtuoso_map, - }, - { - /* Corsair Virtuoso SE Latest (wireless mode) */ - .id = USB_ID(0x1b1c, 0x0a40), - .map = corsair_virtuoso_map, - }, { .id = USB_ID(0x30be, 0x0101), /* Schiit Hel */ .ignore_ctl_error = 1, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 99f2203bf51f140c3ddfd13ab9277a48edea1341..86fdd669f3fd76694234ddfd2c9b36dde2acc744 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3135,10 +3135,9 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, if (unitid == 7 && cval->control == UAC_FU_VOLUME) snd_dragonfly_quirk_db_scale(mixer, cval, kctl); break; - /* lowest playback value is muted on some devices */ - case USB_ID(0x0d8c, 0x000c): /* C-Media */ - case USB_ID(0x0d8c, 0x0014): /* C-Media */ - case USB_ID(0x19f7, 0x0003): /* RODE NT-USB */ + /* lowest playback value is muted on C-Media devices */ + case USB_ID(0x0d8c, 0x000c): + case USB_ID(0x0d8c, 0x0014): if (strstr(kctl->id.name, "Playback")) cval->min_mute = 1; break; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f3571fb3e65e18f4a10b32b693ea4f41cb563813..26b6bee72039a995a5faa06e698201002520d548 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1491,8 +1491,8 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 1, if current task belongs to the cgroup2. - * * 0, if current task does not belong to the cgroup2. + * * 0, if current task belongs to the cgroup2. + * * 1, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index bd22853be4a6b6c4ad710d5f870467235ab01571..0911aea4cdbe5c68406b5bc9c15ec58c37058c94 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -1416,11 +1416,6 @@ static const char *btf_dump_resolve_name(struct btf_dump *d, __u32 id, if (s->name_resolved) return *cached_name ? *cached_name : orig_name; - if (btf_is_fwd(t) || (btf_is_enum(t) && btf_vlen(t) == 0)) { - s->name_resolved = 1; - return orig_name; - } - dup_cnt = btf_dump_name_dups(d, name_map, orig_name); if (dup_cnt > 1) { const size_t max_len = 256; diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 61df26f048d91aba858a013116e160001f3f0782..b337d6f29098bfda5a4f1732ce022d0413fa3f2e 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -10923,9 +10923,6 @@ void bpf_object__detach_skeleton(struct bpf_object_skeleton *s) void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s) { - if (!s) - return; - if (s->progs) bpf_object__detach_skeleton(s); if (s->obj) diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c index c4390ef98b1929e410275fbbd6d02072df57caf5..3028f932e10c072a60fd517086aa4fe1dabfe259 100644 --- a/tools/lib/bpf/xsk.c +++ b/tools/lib/bpf/xsk.c @@ -895,23 +895,12 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname, int xsk_umem__delete(struct xsk_umem *umem) { - struct xdp_mmap_offsets off; - int err; - if (!umem) return 0; if (umem->refcount) return -EBUSY; - err = xsk_get_mmap_offsets(umem->fd, &off); - if (!err && umem->fill_save && umem->comp_save) { - munmap(umem->fill_save->ring - off.fr.desc, - off.fr.desc + umem->config.fill_size * sizeof(__u64)); - munmap(umem->comp_save->ring - off.cr.desc, - off.cr.desc + umem->config.comp_size * sizeof(__u64)); - } - close(umem->fd); free(umem); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3609da7cce0abb781889f39887dbf4b2a73915e0..4d569ad7db02dd9a3b823503f2e8434b226eb911 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -231,7 +231,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols) prev = curr; curr = rb_entry(nd, struct symbol, rb_node); - if (prev->end == prev->start || prev->end != curr->start) + if (prev->end == prev->start && prev->end != curr->start) arch__symbols__fixup_end(prev, curr); } diff --git a/tools/testing/selftests/bpf/prog_tests/timer_crash.c b/tools/testing/selftests/bpf/prog_tests/timer_crash.c new file mode 100644 index 0000000000000000000000000000000000000000..f74b82305da8c88488117b0b908029d2d2364250 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/timer_crash.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "timer_crash.skel.h" + +enum { + MODE_ARRAY, + MODE_HASH, +}; + +static void test_timer_crash_mode(int mode) +{ + struct timer_crash *skel; + + skel = timer_crash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "timer_crash__open_and_load")) + return; + skel->bss->pid = getpid(); + skel->bss->crash_map = mode; + if (!ASSERT_OK(timer_crash__attach(skel), "timer_crash__attach")) + goto end; + usleep(1); +end: + timer_crash__destroy(skel); +} + +void test_timer_crash(void) +{ + if (test__start_subtest("array")) + test_timer_crash_mode(MODE_ARRAY); + if (test__start_subtest("hash")) + test_timer_crash_mode(MODE_HASH); +} diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields.c b/tools/testing/selftests/bpf/progs/test_sock_fields.c index 7967348b11af69efbf6de34515903983b79d0a1e..81b57b9aaaeae2e68d81db22410594dc02fc6060 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields.c @@ -113,7 +113,7 @@ static void tpcpy(struct bpf_tcp_sock *dst, #define RET_LOG() ({ \ linum = __LINE__; \ - bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_ANY); \ + bpf_map_update_elem(&linum_map, &linum_idx, &linum, BPF_NOEXIST); \ return CG_OK; \ }) diff --git a/tools/testing/selftests/bpf/progs/timer_crash.c b/tools/testing/selftests/bpf/progs/timer_crash.c new file mode 100644 index 0000000000000000000000000000000000000000..f8f7944e70dae40317340ae995ecfed7783cd686 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/timer_crash.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +struct map_elem { + struct bpf_timer timer; + struct bpf_spin_lock lock; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct map_elem); +} amap SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, int); + __type(value, struct map_elem); +} hmap SEC(".maps"); + +int pid = 0; +int crash_map = 0; /* 0 for amap, 1 for hmap */ + +SEC("fentry/do_nanosleep") +int sys_enter(void *ctx) +{ + struct map_elem *e, value = {}; + void *map = crash_map ? (void *)&hmap : (void *)&amap; + + if (bpf_get_current_task_btf()->tgid != pid) + return 0; + + *(void **)&value = (void *)0xdeadcaf3; + + bpf_map_update_elem(map, &(int){0}, &value, 0); + /* For array map, doing bpf_map_update_elem will do a + * check_and_free_timer_in_array, which will trigger the crash if timer + * pointer was overwritten, for hmap we need to use bpf_timer_cancel. + */ + if (crash_map == 1) { + e = bpf_map_lookup_elem(map, &(int){0}); + if (!e) + return 0; + bpf_timer_cancel(&e->timer); + } + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_lirc_mode2.sh b/tools/testing/selftests/bpf/test_lirc_mode2.sh index 5252b91f48a18c7d632f47cf7140a2282bbf38bb..ec4e15948e40631cdb063a5d700310796e3386de 100755 --- a/tools/testing/selftests/bpf/test_lirc_mode2.sh +++ b/tools/testing/selftests/bpf/test_lirc_mode2.sh @@ -3,7 +3,6 @@ # Kselftest framework requirement - SKIP code is 4. ksft_skip=4 -ret=$ksft_skip msg="skip all tests:" if [ $UID != 0 ]; then @@ -26,7 +25,7 @@ do fi done -if [ -n "$LIRCDEV" ]; +if [ -n $LIRCDEV ]; then TYPE=lirc_mode2 ./test_lirc_mode2_user $LIRCDEV $INPUTDEV @@ -37,5 +36,3 @@ then echo -e ${GREEN}"PASS: $TYPE"${NC} fi fi - -exit $ret diff --git a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh index 6c69c42b1d607075646d1db87804dafd65055a04..b497bb85b667f78f0bfa393e5ffaca0766b345f0 100755 --- a/tools/testing/selftests/bpf/test_lwt_ip_encap.sh +++ b/tools/testing/selftests/bpf/test_lwt_ip_encap.sh @@ -120,14 +120,6 @@ setup() ip netns exec ${NS2} sysctl -wq net.ipv4.conf.default.rp_filter=0 ip netns exec ${NS3} sysctl -wq net.ipv4.conf.default.rp_filter=0 - # disable IPv6 DAD because it sometimes takes too long and fails tests - ip netns exec ${NS1} sysctl -wq net.ipv6.conf.all.accept_dad=0 - ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.accept_dad=0 - ip netns exec ${NS3} sysctl -wq net.ipv6.conf.all.accept_dad=0 - ip netns exec ${NS1} sysctl -wq net.ipv6.conf.default.accept_dad=0 - ip netns exec ${NS2} sysctl -wq net.ipv6.conf.default.accept_dad=0 - ip netns exec ${NS3} sysctl -wq net.ipv6.conf.default.accept_dad=0 - ip link add veth1 type veth peer name veth2 ip link add veth3 type veth peer name veth4 ip link add veth5 type veth peer name veth6 @@ -297,7 +289,7 @@ test_ping() ip netns exec ${NS1} ping -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/null RET=$? elif [ "${PROTO}" == "IPv6" ] ; then - ip netns exec ${NS1} ping6 -c 1 -W 1 -I veth1 ${IPv6_DST} 2>&1 > /dev/null + ip netns exec ${NS1} ping6 -c 1 -W 6 -I veth1 ${IPv6_DST} 2>&1 > /dev/null RET=$? else echo " test_ping: unknown PROTO: ${PROTO}" diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8a3f2cd9fec0c65b8d88f7ff1b891c7ef6746c0b --- /dev/null +++ b/tools/testing/selftests/damon/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for damon selftests + +TEST_FILES = _chk_dependency.sh +TEST_PROGS = debugfs_attrs.sh + +include ../lib.mk diff --git a/tools/testing/selftests/damon/_chk_dependency.sh b/tools/testing/selftests/damon/_chk_dependency.sh new file mode 100644 index 0000000000000000000000000000000000000000..0189db81550be9f196cee04c6ed3ad1614db4248 --- /dev/null +++ b/tools/testing/selftests/damon/_chk_dependency.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +DBGFS=/sys/kernel/debug/damon + +if [ $EUID -ne 0 ]; +then + echo "Run as root" + exit $ksft_skip +fi + +if [ ! -d "$DBGFS" ] +then + echo "$DBGFS not found" + exit $ksft_skip +fi + +for f in attrs target_ids monitor_on +do + if [ ! -f "$DBGFS/$f" ] + then + echo "$f not found" + exit 1 + fi +done diff --git a/tools/testing/selftests/damon/debugfs_attrs.sh b/tools/testing/selftests/damon/debugfs_attrs.sh new file mode 100644 index 0000000000000000000000000000000000000000..196b6640bf3783601833f348447d720f71f9f7ec --- /dev/null +++ b/tools/testing/selftests/damon/debugfs_attrs.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +test_write_result() { + file=$1 + content=$2 + orig_content=$3 + expect_reason=$4 + expected=$5 + + echo "$content" > "$file" + if [ $? -ne "$expected" ] + then + echo "writing $content to $file doesn't return $expected" + echo "expected because: $expect_reason" + echo "$orig_content" > "$file" + exit 1 + fi +} + +test_write_succ() { + test_write_result "$1" "$2" "$3" "$4" 0 +} + +test_write_fail() { + test_write_result "$1" "$2" "$3" "$4" 1 +} + +test_content() { + file=$1 + orig_content=$2 + expected=$3 + expect_reason=$4 + + content=$(cat "$file") + if [ "$content" != "$expected" ] + then + echo "reading $file expected $expected but $content" + echo "expected because: $expect_reason" + echo "$orig_content" > "$file" + exit 1 + fi +} + +source ./_chk_dependency.sh + +# Test attrs file +# =============== + +file="$DBGFS/attrs" +orig_content=$(cat "$file") + +test_write_succ "$file" "1 2 3 4 5" "$orig_content" "valid input" +test_write_fail "$file" "1 2 3 4" "$orig_content" "no enough fields" +test_write_fail "$file" "1 2 3 5 4" "$orig_content" \ + "min_nr_regions > max_nr_regions" +test_content "$file" "$orig_content" "1 2 3 4 5" "successfully written" +echo "$orig_content" > "$file" + +# Test schemes file +# ================= + +file="$DBGFS/schemes" +orig_content=$(cat "$file") + +test_write_succ "$file" "1 2 3 4 5 6 4 0 0 0 1 2 3 1 100 3 2 1" \ + "$orig_content" "valid input" +test_write_fail "$file" "1 2 +3 4 5 6 3 0 0 0 1 2 3 1 100 3 2 1" "$orig_content" "multi lines" +test_write_succ "$file" "" "$orig_content" "disabling" +echo "$orig_content" > "$file" + +# Test target_ids file +# ==================== + +file="$DBGFS/target_ids" +orig_content=$(cat "$file") + +test_write_succ "$file" "1 2 3 4" "$orig_content" "valid input" +test_write_succ "$file" "1 2 abc 4" "$orig_content" "still valid input" +test_content "$file" "$orig_content" "1 2" "non-integer was there" +test_write_succ "$file" "abc 2 3" "$orig_content" "the file allows wrong input" +test_content "$file" "$orig_content" "" "wrong input written" +test_write_succ "$file" "" "$orig_content" "empty input" +test_content "$file" "$orig_content" "" "empty input written" +echo "$orig_content" > "$file" + +echo "PASS" diff --git a/tools/testing/selftests/filesystems/fuse/fd_bpf.c b/tools/testing/selftests/filesystems/fuse/fd_bpf.c index f9102058515ff9c4da308153f627254fb824dab7..ebf5c92c92972f22779c71faf720ef040a1406fa 100644 --- a/tools/testing/selftests/filesystems/fuse/fd_bpf.c +++ b/tools/testing/selftests/filesystems/fuse/fd_bpf.c @@ -74,7 +74,7 @@ SEC("maps") struct fuse_bpf_map test_map2 = { SEC("test_daemon") -int trace_daemon(struct fuse_args *fa) +int trace_daemon(struct fuse_bpf_args *fa) { uint64_t uid_gid = bpf_get_current_uid_gid(); uint32_t uid = uid_gid & 0xffffffff; diff --git a/tools/testing/selftests/filesystems/fuse/fuse_test.c b/tools/testing/selftests/filesystems/fuse/fuse_test.c index 857484b90ae71b3f5994c98173e15af00f3108ef..7adc6bdb2241645f316ffeb6d8b1cd0af14e23cf 100644 --- a/tools/testing/selftests/filesystems/fuse/fuse_test.c +++ b/tools/testing/selftests/filesystems/fuse/fuse_test.c @@ -485,7 +485,7 @@ static int bpf_test_redact_readdir(const char *mount_dir) TESTSYSCALL(closedir(dir)); dir = NULL; FUSE_DAEMON - bool skip = true; + bool skip = true; for (int i = 0; i < ARRAY_SIZE(names) + 1; i++) { uint8_t bytes_in[FUSE_MIN_READ_BUFFER]; uint8_t bytes_out[FUSE_MIN_READ_BUFFER]; diff --git a/tools/testing/selftests/filesystems/fuse/test_bpf.c b/tools/testing/selftests/filesystems/fuse/test_bpf.c index 8afef42b4657af89bc956e257310d34d58d8f59a..3f4a9e727b6832cafbca0afd112248e9137ab42a 100644 --- a/tools/testing/selftests/filesystems/fuse/test_bpf.c +++ b/tools/testing/selftests/filesystems/fuse/test_bpf.c @@ -35,7 +35,7 @@ inline int strcmp(const char *a, const char *b) } SEC("test_readdir_redact") /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */ -int readdir_test(struct fuse_args *fa) +int readdir_test(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_READDIR | FUSE_PREFILTER: { @@ -60,7 +60,7 @@ int readdir_test(struct fuse_args *fa) SEC("test_trace") /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */ -int trace_test(struct fuse_args *fa) +int trace_test(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_LOOKUP | FUSE_PREFILTER: { @@ -361,7 +361,7 @@ int trace_test(struct fuse_args *fa) SEC("test_hidden") -int trace_hidden(struct fuse_args *fa) +int trace_hidden(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_LOOKUP | FUSE_PREFILTER: { @@ -418,7 +418,7 @@ int trace_hidden(struct fuse_args *fa) } SEC("test_simple") -int trace_simple(struct fuse_args *fa) +int trace_simple(struct fuse_bpf_args *fa) { if (fa->opcode & FUSE_PREFILTER) bpf_printk("prefilter opcode: %d", @@ -432,7 +432,7 @@ int trace_simple(struct fuse_args *fa) } SEC("test_passthrough") -int trace_daemon(struct fuse_args *fa) +int trace_daemon(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_LOOKUP | FUSE_PREFILTER: { @@ -468,7 +468,7 @@ int trace_daemon(struct fuse_args *fa) SEC("test_error") /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */ -int error_test(struct fuse_args *fa) +int error_test(struct fuse_bpf_args *fa) { switch (fa->opcode) { case FUSE_MKDIR | FUSE_PREFILTER: { diff --git a/tools/testing/selftests/filesystems/incfs/Makefile b/tools/testing/selftests/filesystems/incfs/Makefile index f3798029247a37af19d647328766b82895ca5d1b..5a2f6301c4b27173176e533149667e524dfa12b7 100644 --- a/tools/testing/selftests/filesystems/incfs/Makefile +++ b/tools/testing/selftests/filesystems/incfs/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -CFLAGS += -D_FILE_OFFSET_BITS=64 -Wall -Werror -I../.. -I../../../../.. -LDLIBS := -llz4 -lzstd -lcrypto -lpthread +CFLAGS += -D_FILE_OFFSET_BITS=64 -Wall -Werror -I../.. -I../../../../.. -fno-omit-frame-pointer -fsanitize=address -g +LDLIBS := -llz4 -lzstd -lcrypto -lpthread -fsanitize=address TEST_GEN_PROGS := incfs_test incfs_stress incfs_perf include ../../lib.mk diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c index e3ba304f39cadb10bb9fbeaaea41156ebe00ba12..b3773bd1df91f02840a190d40895bb6c32719dcb 100644 --- a/tools/testing/selftests/filesystems/incfs/incfs_test.c +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #define FS_IOC_GETFLAGS _IOR('f', 1, long) #define FS_VERITY_FL 0x00100000 /* Verity protected inode */ +#define TEST_SKIP 2 #define TEST_FAILURE 1 #define TEST_SUCCESS 0 @@ -2793,14 +2795,16 @@ failure: return TEST_FAILURE; } +#define THREE_GB (3LL * 1024 * 1024 * 1024) +#define FOUR_GB (4LL * 1024 * 1024 * 1024) /* Have 1GB of margin */ static int large_file_test(const char *mount_dir) { char *backing_dir; int cmd_fd = -1; int i; - int result = TEST_FAILURE; + int result = TEST_FAILURE, ret; uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {}; - int block_count = 3LL * 1024 * 1024 * 1024 / INCFS_DATA_FILE_BLOCK_SIZE; + int block_count = THREE_GB / INCFS_DATA_FILE_BLOCK_SIZE; struct incfs_fill_block *block_buf = calloc(block_count, sizeof(struct incfs_fill_block)); struct incfs_fill_blocks fill_blocks = { @@ -2809,6 +2813,22 @@ static int large_file_test(const char *mount_dir) }; incfs_uuid_t id; int fd = -1; + struct statvfs svfs; + unsigned long long free_disksz; + + ret = statvfs(mount_dir, &svfs); + if (ret) { + ksft_print_msg("Can't get disk size. Skipping %s...\n", __func__); + return TEST_SKIP; + } + + free_disksz = (unsigned long long)svfs.f_bavail * svfs.f_bsize; + + if (FOUR_GB > free_disksz) { + ksft_print_msg("Not enough free disk space (%lldMB). Skipping %s...\n", + free_disksz >> 20, __func__); + return TEST_SKIP; + } backing_dir = create_backing_dir(mount_dir); if (!backing_dir) @@ -2849,6 +2869,7 @@ static int large_file_test(const char *mount_dir) failure: close(fd); close(cmd_fd); + unlink("very_large_file"); umount(mount_dir); free(backing_dir); return result; @@ -4688,9 +4709,15 @@ struct test_case { void run_one_test(const char *mount_dir, struct test_case *test_case) { + int ret; + ksft_print_msg("Running %s\n", test_case->name); - if (test_case->pfunc(mount_dir) == TEST_SUCCESS) + ret = test_case->pfunc(mount_dir); + + if (ret == TEST_SUCCESS) ksft_test_result_pass("%s\n", test_case->name); + else if (ret == TEST_SKIP) + ksft_test_result_skip("%s\n", test_case->name); else ksft_test_result_fail("%s\n", test_case->name); } diff --git a/tools/testing/selftests/filesystems/incfs/utils.c b/tools/testing/selftests/filesystems/incfs/utils.c index e60b0d36f49dfcda9295ddc9ea776a5687c41eee..d7deb5321c3e2af926c4d02bd9319f12bced2fbe 100644 --- a/tools/testing/selftests/filesystems/incfs/utils.c +++ b/tools/testing/selftests/filesystems/incfs/utils.c @@ -81,6 +81,16 @@ int mount_fs(const char *mount_dir, const char *backing_dir, return result; } +int umount_fs(const char *mount_dir) +{ + int result; + + result = umount(mount_dir); + if (result != 0) + perror("Error unmounting fs."); + return result; +} + int mount_fs_opt(const char *mount_dir, const char *backing_dir, const char *opt, bool remount) { @@ -116,6 +126,9 @@ size_t format_signature(void **buf, const char *root_hash, const char *add_data) size_t size = sizeof(struct signature_blob) + strlen(add_data) + 1; struct signature_blob *sb = malloc(size); + if (!sb) + return 0; + *sb = (struct signature_blob){ .version = INCFS_SIGNATURE_VERSION, .hash_section_size = sizeof(struct hash_section), @@ -126,7 +139,7 @@ size_t format_signature(void **buf, const char *root_hash, const char *add_data) .salt_size = 0, .hash_size = SHA256_DIGEST_SIZE, }, - .signing_section_size = sizeof(uint32_t) + strlen(add_data) + 1, + .signing_section_size = strlen(add_data) + 1, }; memcpy(sb->hash_section.hash, root_hash, SHA256_DIGEST_SIZE); diff --git a/tools/testing/selftests/filesystems/incfs/utils.h b/tools/testing/selftests/filesystems/incfs/utils.h index f5ed8dc5f0ff2820cf6a4c7d24f5c72039c59197..17a1ac5eef7d80c1596a4ba5afd324d4e264d38f 100644 --- a/tools/testing/selftests/filesystems/incfs/utils.h +++ b/tools/testing/selftests/filesystems/incfs/utils.h @@ -29,6 +29,8 @@ int drop_caches(void); int mount_fs(const char *mount_dir, const char *backing_dir, int read_timeout_ms); +int umount_fs(const char *mount_dir); + int mount_fs_opt(const char *mount_dir, const char *backing_dir, const char *opt, bool remount); diff --git a/tools/testing/selftests/net/test_vxlan_under_vrf.sh b/tools/testing/selftests/net/test_vxlan_under_vrf.sh index a44b9aca7427234346b58a2477324e3bcddfb684..09f9ed92cbe4c8b6e1837698aa273b2f7848145b 100755 --- a/tools/testing/selftests/net/test_vxlan_under_vrf.sh +++ b/tools/testing/selftests/net/test_vxlan_under_vrf.sh @@ -118,11 +118,11 @@ echo "[ OK ]" # Move the underlay to a non-default VRF ip -netns hv-1 link set veth0 vrf vrf-underlay -ip -netns hv-1 link set vxlan0 down -ip -netns hv-1 link set vxlan0 up +ip -netns hv-1 link set veth0 down +ip -netns hv-1 link set veth0 up ip -netns hv-2 link set veth0 vrf vrf-underlay -ip -netns hv-2 link set vxlan0 down -ip -netns hv-2 link set vxlan0 up +ip -netns hv-2 link set veth0 down +ip -netns hv-2 link set veth0 up echo -n "Check VM connectivity through VXLAN (underlay in a VRF) " ip netns exec vm-1 ping -c 1 -W 1 10.0.0.2 &> /dev/null || (echo "[FAIL]"; false) diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 01ec6876e8f586af65286b7a92de45102db9a529..2cf32e6b376e1cc2363fcf15e4ecb7aac159ef71 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -40,9 +40,9 @@ TEST_GEN_FILES += userfaultfd TEST_GEN_FILES += khugepaged ifeq ($(MACHINE),x86_64) -CAN_BUILD_I386 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_32bit_program.c -m32) -CAN_BUILD_X86_64 := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_64bit_program.c) -CAN_BUILD_WITH_NOPIE := $(shell ./../x86/check_cc.sh "$(CC)" ../x86/trivial_program.c -no-pie) +CAN_BUILD_I386 := $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_32bit_program.c -m32) +CAN_BUILD_X86_64 := $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_64bit_program.c) +CAN_BUILD_WITH_NOPIE := $(shell ./../x86/check_cc.sh $(CC) ../x86/trivial_program.c -no-pie) TARGETS := protection_keys BINARIES_32 := $(TARGETS:%=%_32) diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index f1b675a4040b743ab3ebfd693345c76bd82947e0..6703c7906b714bf4fe9fc7170e70419fde080d98 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -6,9 +6,9 @@ include ../lib.mk .PHONY: all all_32 all_64 warn_32bit_failure clean UNAME_M := $(shell uname -m) -CAN_BUILD_I386 := $(shell ./check_cc.sh "$(CC)" trivial_32bit_program.c -m32) -CAN_BUILD_X86_64 := $(shell ./check_cc.sh "$(CC)" trivial_64bit_program.c) -CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh "$(CC)" trivial_program.c -no-pie) +CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) +CAN_BUILD_X86_64 := $(shell ./check_cc.sh $(CC) trivial_64bit_program.c) +CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ diff --git a/tools/testing/selftests/x86/check_cc.sh b/tools/testing/selftests/x86/check_cc.sh index 8c669c0d662ee275f27132d2fcab174660ab4c81..3e2089c8cf54967fdd375ec151a15827e104fc53 100755 --- a/tools/testing/selftests/x86/check_cc.sh +++ b/tools/testing/selftests/x86/check_cc.sh @@ -7,7 +7,7 @@ CC="$1" TESTPROG="$2" shift 2 -if [ -n "$CC" ] && $CC -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then +if "$CC" -o /dev/null "$TESTPROG" -O0 "$@" 2>/dev/null; then echo 1 else echo 0 diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 23f142af544ad796146361cc81ce3315d303f42e..cb3f29c09aff3522b6225f1710d71e27097de9a2 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -130,7 +130,6 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features) memset(dev, 0, sizeof *dev); dev->vdev.features = features; INIT_LIST_HEAD(&dev->vdev.vqs); - spin_lock_init(&dev->vdev.vqs_list_lock); dev->buf_size = 1024; dev->buf = malloc(dev->buf_size); assert(dev->buf); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f30ae932efb5a961a86d4ac2a044466368ba3260..a07bfa9beda3cb2f39e726383c6baf42826ceae8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -114,8 +114,6 @@ EXPORT_SYMBOL_GPL(kvm_debugfs_dir); static int kvm_debugfs_num_entries; static const struct file_operations stat_fops_per_vm; -static struct file_operations kvm_chardev_ops; - static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, unsigned long arg); #ifdef CONFIG_KVM_COMPAT @@ -810,16 +808,6 @@ static struct kvm *kvm_create_vm(unsigned long type) preempt_notifier_inc(); - /* - * When the fd passed to this ioctl() is opened it pins the module, - * but try_module_get() also prevents getting a reference if the module - * is in MODULE_STATE_GOING (e.g. if someone ran "rmmod --wait"). - */ - if (!try_module_get(kvm_chardev_ops.owner)) { - r = -ENODEV; - goto out_err; - } - return kvm; out_err: @@ -898,7 +886,6 @@ static void kvm_destroy_vm(struct kvm *kvm) preempt_notifier_dec(); hardware_disable_all(); mmdrop(mm); - module_put(kvm_chardev_ops.owner); } void kvm_get_kvm(struct kvm *kvm)