ILD

explain down_read_nested / down_write_nested
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2026-3-18 站点:Inside Linux Development

最近在阅读vfs的代码时,发现inode的rw_semaphore,上写锁的时候,有的是执行:

static inline void inode_lock(struct inode *inode)

{

        down_write(&inode->i_rwsem);

}


有的是执行:

static inline void inode_lock_nested(struct inode *inode, unsigned subclass)

{

        down_write_nested(&inode->i_rwsem, subclass);

}


阅读代码发现,只有在开启lockdep的时候,down_write()/down_write_nested()才有区别。

https://docs.kernel.org/locking/lockdep-design.html


原来lockdep是内核用来调试lock的一个工具,它不影响原来的功能。在发生死锁的时候,能打印足够的信息用来定位问题。

lockdep有一个lock class的功能。不同的lock可以属于同一个class。


写一个代码:

static struct rw_semaphore rwsem_1;
static struct rw_semaphore rwsem_2;
static struct lock_class_key key;

static int __init test_init(void)
{
        init_rwsem(&rwsem_1);
        lockdep_set_class(&rwsem_1, &key);

        init_rwsem(&rwsem_2);
        lockdep_set_class(&rwsem_2, &key);

#if 1
        down_write(&rwsem_1);
        down_write(&rwsem_2);
        up_write(&rwsem_2);
        up_write(&rwsem_1);
#else
        down_write_nested(&rwsem_1, 0);
        down_write_nested(&rwsem_2, 1);

        up_write(&rwsem_2);
        up_write(&rwsem_1);
#endif

        return 0;
}


运行后报告警,但是实际功能是正常的。

# insmod /mnt/host0/app/test_ko/test.ko
[   15.927235] test: loading out-of-tree module taints kernel.
[   15.935408]
[   15.935669] ============================================
[   15.936092] WARNING: possible recursive locking detected
[   15.936801] 6.12.37+ #13 Tainted: G           O
[   15.937146] --------------------------------------------
[   15.937591] insmod/113 is trying to acquire lock:
[   15.939295] ffff80007922c638 (&key){+.+.}-{4:4}, at: test_init+0xa8/0x1000 [test]
[   15.941229]
[   15.941229] but task is already holding lock:
[   15.941620] ffff80007922c580 (&key){+.+.}-{4:4}, at: test_init+0xa0/0x1000 [test]
[   15.942854]
[   15.942854] other info that might help us debug this:
[   15.943396]  Possible unsafe locking scenario:
[   15.943396]
[   15.943788]        CPU0
[   15.943922]        ----
[   15.944103]   lock(&key);
[   15.944394]   lock(&key);
[   15.944692]
[   15.944692]  *** DEADLOCK ***
[   15.944692]
[   15.944986]  May be due to missing lock nesting notation


rw semaphore是不允许嵌套锁的(recursive)。比如 down_write(&lock); down_write(&lock); 这里会死锁。

但是上面两个是不同的锁。由于设置了同一个class。所以lockdep也告警了。尽管实际上没有死锁。


这种场景下,就需要使用_nested()接口,带不同的subclass。使用#else的代码,lockdep就没有告警了。

# insmod /mnt/host0/app/test_ko/test.ko
[   21.126974] test: loading out-of-tree module taints kernel.


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.