Linux kernel patch suggestions (FSD 2026)
Written by David Tadokoro
Written on , last modified onTo finalise the first phase of the Free Software Development 2026 course, each group will send one or more contributions to the Linux project. There are no restrictions on which subsystems the groups can send patches to, and this post includes a few directions to help you devise your contributions. The mentors of FSD 2026 have curated these suggestions, but always rely on the Linux community and maintainers, as well as on your own critical sense when developing for the kernel.
Important: Before proceeding to the patch suggestions, make sure you are comfortable with the submission part of the process by consulting the patch submission guidelines pad: https://pad.riseup.net/p/DSL-USP-2026-kernel-patch-submission-keep
This is an WIP version that may be altered in the future.
Suggestions summary
- Suggestion 1.1) Replace
mutex_lock(&lock)andmutex_unlock(&lock)calls withguard(mutex)(&lock) - Suggestion 2.1) Replace manual bitfield manipulations with
FIELD_GET(),FIELD_PREP(), andFIELD_MODIFY() - Suggestion 2.2) Update IIO drivers to be Include-What-You-Use (IWYU) compliant
- Suggestion 2.3) Improvements in the IIO area of staging
- Suggestion 3.1) Convert logging to drm_* functions with drm_device parameter
- Suggestion 3.2) Read and expand the subsystem documentation
- Suggestion 4.1) Duplications with 100% similarity
- Suggestion 4.2) Duplications with 90% similarity
1. Any subsystem/subproject
Suggestion 1.1) Replace mutex_lock(&lock) and mutex_unlock(&lock) calls with guard(mutex)(&lock)
Synchronisation is fundamental in the Linux kernel, as you need to be mindful of concurrency issues such as data inconsistency, race conditions, and deadlocks. A common synchronisation primitive is a mutex, which is implemented in Linux. An example of initialising a mutex, acquiring it, and unlocking it would be
struct mutex lock; // declaring a mutex
mutex_init(&lock); // dynamically initialising the mutex
mutex_lock(&lock); // acquiring the mutex
... // critical section
mutex_unlock(&lock); // unlocking the mutex
However, there are two problems with this approach that compromise cleanup after calling mutex_lock():
- The developer needs to remember to call
mutex_unlock() - Depending on the conditional paths of the critical section, many
mutex_unlock()calls need to be placed
To circumvent these problems, developers may use the goto error pattern, where the mutex_unlock() is centralised at the end of the critical section. For instance, this template of a function is pretty common:
int function_with_mutex_and_goto_error_pattern(void)
{
int ret = 0;
mutex_lock(&lock); // lock is a struct mutex that has been initialised
switch (var) {
case FOO:
do_foo(); // suppose this function never fails
break;
case BAR:
ret = do_first_bar(); // suppose this function can fail
if (ret) // i.e., if do_first_bar() failed
goto out;
ret = do_second_bar(); // suppose this function can fail
if (ret) // i.e., if do_second_bar() failed
goto out;
do_third_bar(); // suppose this function never fails
break;
default:
ret = -EINVAL;
}
out:
mutex_unlock(&lock);
return ret;
}
The kernel provides what it calls Scope-based Cleanup Helpers (defined in include/linux/cleanup.h), which, in a very broad sense, allow transparent cleanup when resources go out of scope. For mutexes, the guard(mutex)(&lock) macro basically solves the two mentioned problems associated with cleaning up acquired mutexes. In the above example, if we were to use guard(mutex)(&lock), the code could be rewritten without any functional change as
int function_with_guard_mutex(void)
{
int ret = 0;
guard(mutex)(&lock); // lock is a struct mutex that has been initialised
switch (var) {
case FOO:
do_foo(); // suppose this function never fails
return 0;
case BAR:
ret = do_first_bar(); // suppose this function can fail
if (ret) // i.e., if do_first_bar() failed
return ret;
ret = do_second_bar(); // suppose this function can fail
if (ret) // i.e., if do_second_bar() failed
return ret;
do_third_bar(); // suppose this function never fails
return 0;
default:
return -EINVAL;
}
}
Note that in this example, as guard(mutex)(&lock) is called “at the root scope” of the function, the mutex is unlocked if and only if it goes out of the function scope (in the example, in any of the return statements). There is a similar macro, scoped_guard(mutex, &lock), that creates an explicit block scope where the mutex is unlocked when it goes out of this block. For example, if we have a sequence in which we only want a small part of it to represent our critical section, we can use scoped_guard(mutex, &lock):
int function_with_scoped_guard_mutex(void)
{
... // do some stuff with no mutex active
scoped_guard(mutex, &lock) { // lock is a struct mutex that has been initialised
... // inside these curly braces, the mutex is active
} // from here on, the mutex is unlocked
... // do some other stuff with no mutex active
}
Important observations
- Obs.1:
guard(mutex)(&lock)andscoped_guard(mutex, &lock)are only a specific type of guard cleanups, and guard cleanups are only part of these Scope-based Cleanup Helpers. You can check the documentation https://docs.kernel.org/core-api/cleanup.html to understand this better, if you are interested. - Obs.2: The
goto errorpattern isn’t solely used formutex_unlock(&lock), as other unwind operations can happen in the same goto (deallocate memory, unregister char device, and so on). In these cases, you can’t simply throw away the gotos and enforce the guard mutex cleanups. - Obs.3: We exemplified the use of
mutex_lock(&lock)andmutex_unlock(&lock)with thegoto errorpattern, but even in cases where multiple explicitmutex_unlock(&lock)calls are made to avoid gotos, refactoring with guard mutex cleanups can make the code more robust. { .warning}
Patch examples
- https://lore.kernel.org/linux-iio/20250618031638.26477-4-andrew.lopes@alumni.usp.br/
- https://lore.kernel.org/amd-gfx/20251002174245.1691343-7-mario.limonciello@amd.com/
- https://lore.kernel.org/netdev/20250516230734.2564775-7-seanjc@google.com/
2. Industrial I/O (IIO)
The suggestions below were pointed by Marcelo Schmitt and refined by us.
Suggestion 2.1) Replace manual bitfield manipulations with FIELD_GET(), FIELD_PREP(), and FIELD_MODIFY()
Although we normally think of numbers in the decimal system, we can represent them in different bases. Take the number 26, for example. In binary, it is:
\[\begin{aligned} (11010)_2 &= (2^4*1 + 2^3*1 + 2^2*0 + 2^1*1 + 2^0*0)_{10} \\ &= (16*1 + 8*1 + 4*0 + 2*1 + 1*0)_{10} \\ &= (16 + 8 + 0 + 2 + 0)_{10} \\ &= (26)_{10} \end{aligned}\]We can also represent 26 in the hexadecimal system:
\[\begin{aligned} (1\textrm{A})_{16} &= (16^1*1 + 16^0*10)_{10} \\ &= (16*1 + 1*10)_{10} \\ &= (16 + 10)_{10} \\ &= (26)_{10} \end{aligned}\]In kernel development, it is common to treat numbers as bitfields, where each bit or bit sequence encodes a different attribute. As an analogy, imagine a 4-bit bitfield dish that encodes an order at a restaurant serving 4 dishes, with each dish having two sizes (small and large) and two spice levels (regular and spicy). We can define how the bits in dish represent every possible dish as such (“bigger bits” to the left):
- Bits 0-1 -> Dish ID: \((00)_2\) is dish 0, \((01)_2\) is dish 1, \((10)_2\) is dish 2, and \((11)_2\) is dish 3.
- Bit 2 -> Dish size: \((0)_2\) is the small size and \((1)_2\) is the large size.
- Bit 3 -> Dish spiciness: \((0)_2\) is regular and \((1)_2\) is spicy.
In this analogy, the bitfield dish that represents the spicy small dish 1 is \((1001)_2\) (or \((9)_{10}\), in decimal). Now, imagine I want to query the bitfield dish for the dish size, i.e., isolate bit 2 from this 4-bit bitfield. The way to compute this value is to perform a mask (target specific bits) and a shift (move the bits left/right) operation. More specifically, these are the operations in pseudocode:
size = dish AND (0100)_2 // MASK: "selects" only bit 2
size = size >> 2 // SHIFT: "moves" bit 2 to bit 0
Alternatively, if you were handed a bit spiceness and you had to modify dish to have this spiceness. In this case, there would be a shift, a mask, then an OR operation:
val = spiceness << 3 // SHIFT: "moves" spiceness to bit 3
val = val AND (1000)_2 // MASK: "selects" only bit 3
dish = val OR dish // MODIFY: "updates" dish with spiceness
This simple analogy illustrates the core common bitfield manipulations in the kernel, and the pseudocodes aren’t too far from the real implementations. These manipulations are so frequent that the kernel provides macros that simplify them, while making them more secure. These macros are the FIELD_GET(mask, bitfield) (e.g., get dish size), FIELD_PREP(mask, field_val) (e.g., prepare dish spiceness), and FIELD_MODIFY(mask, bitfield, field_val) (e.g., prepare dish spiceness and modify dish). These macros are defined in include/linux/bitfield.h.
In the context of IIO, you can check for manual bitfield (also referred to as registers) manipulations and see if they can be replaced by one of the above macros.
Patch examples
…
Suggestion 2.2) Update IIO drivers to be Include-What-You-Use (IWYU) compliant
IWYU is a Clang-based tool developed by Google to optimize #include directives in C/C++ code (https://include-what-you-use.org/). Check the patch examples for guidelines on how to pursue this suggestion.
Patch examples
- https://lore.kernel.org/linux-iio/20260119212110.726941-1-jic23@kernel.org/
- https://lore.kernel.org/linux-iio/20250629194336.34a03946@jic23-huawei/
- https://lore.kernel.org/linux-iio/20260123081640.590335bd@jic23-huawei/T/#m39327915c3ccea954ecdd81a3cd6ef2068a410d3
Suggestion 2.3) Improvements in the IIO area of staging
Linux has its own “quarantine zone” for drivers, where code that is either entering or leaving the kernel lives, due to it not being quite refined or being problematic, respectively. This area is located in the drivers/staging directory, and the IIO-related drivers of staging are in drivers/staging/iio.
Usually, staging drivers are really rough, in terms of following the kernel conventions, coding style, and other requirements, so some patch opportunities can be considered newcomer friendly. (Un)fortunately, the IIO staging drivers are already well developed, making these easier tasks more rare.
Nevertheless, see this message from Marcelo Schmitt on the mailing list regarding possible tasks for IIO staging drivers: https://lore.kernel.org/linux-iio/Z8U0lsntJpTuBzyT@debian-BULLSEYE-live-builder-AMD64/
Patch examples
…
3. DRM AMDGPU DRIVERS
The suggestions below were taken from https://dri.freedesktop.org/docs/drm/gpu/todo.html and from https://dri.freedesktop.org/docs/drm/gpu/amdgpu/display/display-contributing.html. If you want to dig for other TODOs feel free to investigate these lists.
Suggestion 3.1) Convert logging to drm_* functions with drm_device parameter
For drivers which could have multiple instances, it is necessary to differentiate between which is which in the logs. Since DRM_INFO/WARN/ERROR don’t do this, drivers used dev_info/warn/err to make this differentiation. We now have drm_* variants of the DRM print functions, so we can start to convert those drivers back to using DRM-formatted specific log messages. This should only work in files inside drivers/gpu/drm/amd/display/amdgpu_dm/.
Before you start this conversion please contact the relevant maintainers to make sure your work will be merged - not everyone agrees that the DRM dmesg macros are better. The documentation mentions contacting Sean Paul and the maintainer of the driver you plan to convert.
Patch examples
…
Suggestion 3.2) Read and expand the subsystem documentation
Graphics is already a complicated field, but when it comes to 3D-accelerated graphics in the kernel, things can be get really complex really fast. So reading through the GPU Driver Developer’s Guide (https://docs.kernel.org/gpu/index.html), the DRM AMDGPU drivers doc (https://docs.kernel.org/gpu/amdgpu/index.html), and the display part of DRM AMDGPU drivers doc (https://docs.kernel.org/gpu/amdgpu/display/index.html), can be a great way to grasp some knowledge, whilst contributing to it.
An important observation is that we don’t encourage you to simply correct typos, but to dive deep into the documentation, reading the code, and updating/expanding parts that seem incorrect/unclear.
Patch examples
…
4. Code duplications
Suggestion 4.1) Duplications with 100% similarity
1) 3 sets of correlated duplications. Feel free to try to solve one or all of them. The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
jpeg_v5_0_1.c::jpeg_v5_0_1_process_interrupt AND jpeg_v5_0_2.c::jpeg_v5_0_2_process_interrupt , TOTAL NUMBER LINES IN FUNCTIONS: 59
jpeg_v5_0_0.c::jpeg_v5_0_0_process_interrupt AND jpeg_v5_3_0.c::jpeg_v5_3_0_process_interrupt , TOTAL NUMBER LINES IN FUNCTIONS: 18
jpeg_v2_0.c::jpeg_v2_0_process_interrupt AND jpeg_v3_0.c::jpeg_v3_0_process_interrupt , TOTAL NUMBER LINES IN FUNCTIONS: 18
2) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gfx_v11_0.c::gfx_v11_0_eop_irq AND gfx_v12_0.c::gfx_v12_0_eop_irq , TOTAL NUMBER LINES IN FUNCTIONS: 52
3) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gfx_v11_0.c::gfx_v11_0_ring_preempt_ib AND gfx_v12_0.c::gfx_v12_0_ring_preempt_ib , TOTAL NUMBER LINES IN FUNCTIONS: 49
4) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gmc_v10_0.c::gmc_v10_0_get_vm_pte AND gmc_v11_0.c::gmc_v11_0_get_vm_pte , TOTAL NUMBER LINES IN FUNCTIONS: 46
5) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gfx_v11_0.c::gfx_v11_0_set_userq_eop_interrupts AND gfx_v12_0.c::gfx_v12_0_set_userq_eop_interrupts , TOTAL NUMBER LINES IN FUNCTIONS: 42
6) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gfx_v11_0.c::gfx11_kiq_map_queues AND gfx_v12_0.c::gfx_v12_0_kiq_map_queues , TOTAL NUMBER LINES IN FUNCTIONS: 42
7) 2 sets of correlated duplications. Feel free to try to solve one or all of them. The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
Functions find: cik_sdma.c::cik_sdma_process_trap_irq AND sdma_v2_4.c::sdma_v2_4_process_trap_irq , TOTAL NUMBER LINES IN FUNCTIONS: 40
Functions find: cik_sdma.c::cik_sdma_process_trap_irq AND sdma_v3_0.c::sdma_v3_0_process_trap_irq , TOTAL NUMBER LINES IN FUNCTIONS: 40
8) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gmc_v10_0.c::gmc_v10_0_vm_fault_interrupt_state AND gmc_v12_0.c::gmc_v12_0_vm_fault_interrupt_state , TOTAL NUMBER LINES IN FUNCTIONS: 36
9) The specified files are in the directory drivers/gpu/drm/amd/amdgpu/:
gfx_v11_0.c::gfx_v11_0_handle_priv_fault AND gfx_v12_0.c::gfx_v12_0_handle_priv_fault , TOTAL NUMBER LINES IN FUNCTIONS: 36
10) drivers/iio/: the cluster only identifies these 6 files. However, it is possible to find other functions that exhibit minor variations in their signature, for example, receiving only a pointer to a channel (chan) or using an explicit index (channel) within the channels array.
Cluster #3 (Files: 6, Pairs: 15, Lines: 270)
---------------------
Function find: accel/hid-sensor-accel-3d.c::accel_3d_adjust_channel_bit_mask, TOTAL NUMBER LINES IN FUNCTION: 9
Function find: pressure/hid-sensor-press.c::press_adjust_channel_bit_mask, TOTAL NUMBER LINES IN FUNCTION: 9
Function find: magnetometer/hid-sensor-magn-3d.c::magn_3d_adjust_channel_bit_mask, TOTAL NUMBER LINES IN FUNCTION: 9
Function find: light/hid-sensor-prox.c::prox_adjust_channel_bit_mask, TOTAL NUMBER LINES IN FUNCTION: 9
Function find: light/hid-sensor-als.c::als_adjust_channel_bit_mask, TOTAL NUMBER LINES IN FUNCTION: 9
Function find: gyro/hid-sensor-gyro-3d.c::gyro_3d_adjust_channel_bit_mask, TOTAL NUMBER LINES IN FUNCTION: 9
11) drivers/iio/: bidirectional mappings of the same table.
Cluster #5 (Files: 2, Pairs: 1, Lines: 74)
---------------------
Function find: light/tsl2591.c::tsl2591_persist_cycle_to_lit, TOTAL NUMBER LINES IN FUNCTION: 37
Function find: light/tsl2591.c::tsl2591_persist_lit_to_cycle, TOTAL NUMBER LINES IN FUNCTION: 37
Suggestion 4.2) Duplications with 90% similarity
1) drivers/iio/: There is a common configuration sanitization step for both functions (retained from 2025)
imu/inv_icm42600/inv_icm42600_core.c::inv_icm42600_set_accel_conf AND imu/inv_icm42600/inv_icm42600_core.c::inv_icm42600_set_gyro_conf , TOTAL NUMBER LINES IN FUNCTIONS: 60
2) drivers/iio/: Possibly a refactoring opportunity (retained from 2025)
light/veml6030.c::veml6030_hw_init AND light/veml6030.c::veml6035_hw_init , TOTAL NUMBER LINES IN FUNCTIONS: 49
Difference in the configuration of register 0x00: https://www.vishay.com/docs/84366/veml6030.pdf and https://www.vishay.com/docs/84889/veml6035.pdf
Deduplications from last year (2025)
https://github.com/arkanjo-tool/arkanjo/blob/main/docs/PATCHES_MAC0470_5856_2025.md
History
- V0.1: First work-in-progress version for the FSD 2026 workshop of 07/04/2026.
comments powered by Disqus
FLUSP - FLOSS at USP