On Mon, 26 Jun 2023 09:56:47 +0200, Jaroslav Kysela wrote: > > On 26. 06. 23 9:33, Takashi Iwai wrote: > > On Mon, 26 Jun 2023 09:31:18 +0200, > > Tuo Li wrote: > >> > >> > >> Hello, > >> > >> Thank you for your reply! > > > > FWIW, the simplest fix would be something like below, just extending > > the mutex coverage. But it'll serialize the all calls, so it might > > influence on the performance, while it's the safest way. > > It may be better to update total_pcm_alloc_bytes before > snd_dma_alloc_dir_pages() call and decrease this value when allocation > fails to allow parallel allocations. Then the mutex can be held only > for the total_pcm_alloc_bytes variable update. Yes, it'd work. But a tricky part is that the actual allocation size can be bigger, and we need to correct the total_pcm_alloc_bytes after the allocation result. So the end result would be a patch like below, which is a bit more complex than the previous simpler approach. But it might be OK. > Eventually, total_pcm_alloc_bytes may be atomic. Possible, but the same problem like the above applies, so I believe the mutex is good enough. Another alternative would be to move the size check after the successful allocation, assuming that the size exceeds a very exceptional scenario. The code flow would be a bit simpler. thanks, Takashi --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -37,9 +37,14 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev, enum dma_data_direction dir; int err; + mutex_lock(&card->memory_mutex); if (max_alloc_per_card && - card->total_pcm_alloc_bytes + size > max_alloc_per_card) + card->total_pcm_alloc_bytes + size > max_alloc_per_card) { + mutex_unlock(&card->memory_mutex); return -ENOMEM; + } + card->total_pcm_alloc_bytes += size + mutex_unlock(&card->memory_mutex); if (str == SNDRV_PCM_STREAM_PLAYBACK) dir = DMA_TO_DEVICE; @@ -47,8 +52,18 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev, dir = DMA_FROM_DEVICE; err = snd_dma_alloc_dir_pages(type, dev, dir, size, dmab); if (!err) { + /* the actual allocation size might be bigger than requested, + * and we need to correct the account + */ + if (dmab->bytes != size) { + mutex_lock(&card->memory_mutex); + card->total_pcm_alloc_bytes += dmab->bytes - size; + mutex_unlock(&card->memory_mutex); + } + } else { + /* allocation failure, take back */ mutex_lock(&card->memory_mutex); - card->total_pcm_alloc_bytes += dmab->bytes; + card->total_pcm_alloc_bytes -= size; mutex_unlock(&card->memory_mutex); } return err;