Skip to content

Commit 1f9ad14

Browse files
yangdongshengMikulas Patocka
authored andcommitted
dm-pcache: remove ctrl_lock for pcache_cache_segment
The smatch checker reports a “scheduler in atomic context” problem in the following call chain: miss_read_end_req() -> cache_seg_put() -> cache_seg_invalidate() -> cache_seg_gen_increase() -> mutex_lock(&cache_seg->ctrl_lock); In practice, this `mutex_lock` will not actually schedule, because it is only called when `cache_seg_put()` drops the last reference, which is single-threaded. That is also why the issue never shows up during real testing. However, the code is still buggy. The original purpose of `ctrl_lock` was to prevent read/write conflicts on the cache segment control information. Looking at the current usage, all control information accesses are single-threaded: reads only occur during the init phase, where no conflicts are possible, and writes happen once in the init phase (also single-threaded) and once when `cache_seg_put()` drops the last reference (again single-threaded). Therefore, this patch removes `ctrl_lock` entirely and adds comments in the appropriate places to document this logic. Signed-off-by: Dongsheng Yang <dongsheng.yang@linux.dev> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
1 parent 8d33a03 commit 1f9ad14

2 files changed

Lines changed: 17 additions & 6 deletions

File tree

drivers/md/dm-pcache/cache.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ struct pcache_cache_segment {
9090
u32 gen_index;
9191

9292
struct pcache_cache_seg_ctrl *cache_seg_ctrl;
93-
struct mutex ctrl_lock;
9493
};
9594

9695
/* rbtree for cache entries */

drivers/md/dm-pcache/cache_segment.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ static int cache_seg_ctrl_load(struct pcache_cache_segment *cache_seg)
7272
struct pcache_cache_seg_gen cache_seg_gen, *cache_seg_gen_addr;
7373
int ret = 0;
7474

75-
mutex_lock(&cache_seg->ctrl_lock);
7675
cache_seg_gen_addr = pcache_meta_find_latest(&cache_seg_ctrl->gen->header,
7776
sizeof(struct pcache_cache_seg_gen),
7877
sizeof(struct pcache_cache_seg_gen),
@@ -93,7 +92,6 @@ static int cache_seg_ctrl_load(struct pcache_cache_segment *cache_seg)
9392
cache_seg->gen_seq = cache_seg_gen.header.seq;
9493
cache_seg->gen_index = (cache_seg_gen_addr - cache_seg_ctrl->gen);
9594
out:
96-
mutex_unlock(&cache_seg->ctrl_lock);
9795

9896
return ret;
9997
}
@@ -105,11 +103,27 @@ static inline struct pcache_cache_seg_gen *get_cache_seg_gen_addr(struct pcache_
105103
return (cache_seg_ctrl->gen + cache_seg->gen_index);
106104
}
107105

106+
/*
107+
* cache_seg_ctrl_write - write cache segment control information
108+
* @seg: the cache segment to update
109+
*
110+
* This function writes the control information of a cache segment to media.
111+
*
112+
* Although this updates shared control data, we intentionally do not use
113+
* any locking here. All accesses to control information are single-threaded:
114+
*
115+
* - All reads occur during the init phase, where no concurrent writes
116+
* can happen.
117+
* - Writes happen once during init and once when the last reference
118+
* to the segment is dropped in cache_seg_put().
119+
*
120+
* Both cases are guaranteed to be single-threaded, so there is no risk
121+
* of concurrent read/write races.
122+
*/
108123
static void cache_seg_ctrl_write(struct pcache_cache_segment *cache_seg)
109124
{
110125
struct pcache_cache_seg_gen cache_seg_gen;
111126

112-
mutex_lock(&cache_seg->ctrl_lock);
113127
cache_seg_gen.gen = cache_seg->gen;
114128
cache_seg_gen.header.seq = ++cache_seg->gen_seq;
115129
cache_seg_gen.header.crc = pcache_meta_crc(&cache_seg_gen.header,
@@ -119,7 +133,6 @@ static void cache_seg_ctrl_write(struct pcache_cache_segment *cache_seg)
119133
pmem_wmb();
120134

121135
cache_seg->gen_index = (cache_seg->gen_index + 1) % PCACHE_META_INDEX_MAX;
122-
mutex_unlock(&cache_seg->ctrl_lock);
123136
}
124137

125138
static void cache_seg_ctrl_init(struct pcache_cache_segment *cache_seg)
@@ -177,7 +190,6 @@ int cache_seg_init(struct pcache_cache *cache, u32 seg_id, u32 cache_seg_id,
177190
spin_lock_init(&cache_seg->gen_lock);
178191
atomic_set(&cache_seg->refs, 0);
179192
mutex_init(&cache_seg->info_lock);
180-
mutex_init(&cache_seg->ctrl_lock);
181193

182194
/* init pcache_segment */
183195
seg_options.type = PCACHE_SEGMENT_TYPE_CACHE_DATA;

0 commit comments

Comments
 (0)