staging: android: ashmem: Don't call fallocate() with ashmem_mutex held.
syzbot is hitting lockdep warnings [1][2][3]. This patch tries to fix the warning by eliminating ashmem_shrink_scan() => {shmem|vfs}_fallocate() sequence. [1] https://syzkaller.appspot.com/bug?id=87c399f6fa6955006080b24142e2ce7680295ad4 [2] https://syzkaller.appspot.com/bug?id=7ebea492de7521048355fc84210220e1038a7908 [3] https://syzkaller.appspot.com/bug?id=e02419c12131c24e2a957ea050c2ab6dcbbc3270 Reported-by: syzbot <syzbot+a76129f18c89f3e2ddd4@syzkaller.appspotmail.com> Reported-by: syzbot <syzbot+148c2885d71194f18d28@syzkaller.appspotmail.com> Reported-by: syzbot <syzbot+4b8b031b89e6b96c4b2e@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Cc: stable@vger.kernel.org Acked-by: Joel Fernandes (Google) <joel@joelfernandes.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
f54a740176
Коммит
fb4415a126
|
@ -75,6 +75,9 @@ struct ashmem_range {
|
||||||
/* LRU list of unpinned pages, protected by ashmem_mutex */
|
/* LRU list of unpinned pages, protected by ashmem_mutex */
|
||||||
static LIST_HEAD(ashmem_lru_list);
|
static LIST_HEAD(ashmem_lru_list);
|
||||||
|
|
||||||
|
static atomic_t ashmem_shrink_inflight = ATOMIC_INIT(0);
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(ashmem_shrink_wait);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* long lru_count - The count of pages on our LRU list.
|
* long lru_count - The count of pages on our LRU list.
|
||||||
*
|
*
|
||||||
|
@ -439,7 +442,6 @@ out:
|
||||||
static unsigned long
|
static unsigned long
|
||||||
ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||||
{
|
{
|
||||||
struct ashmem_range *range, *next;
|
|
||||||
unsigned long freed = 0;
|
unsigned long freed = 0;
|
||||||
|
|
||||||
/* We might recurse into filesystem code, so bail out if necessary */
|
/* We might recurse into filesystem code, so bail out if necessary */
|
||||||
|
@ -449,21 +451,33 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||||
if (!mutex_trylock(&ashmem_mutex))
|
if (!mutex_trylock(&ashmem_mutex))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
|
while (!list_empty(&ashmem_lru_list)) {
|
||||||
|
struct ashmem_range *range =
|
||||||
|
list_first_entry(&ashmem_lru_list, typeof(*range), lru);
|
||||||
loff_t start = range->pgstart * PAGE_SIZE;
|
loff_t start = range->pgstart * PAGE_SIZE;
|
||||||
loff_t end = (range->pgend + 1) * PAGE_SIZE;
|
loff_t end = (range->pgend + 1) * PAGE_SIZE;
|
||||||
|
struct file *f = range->asma->file;
|
||||||
|
|
||||||
range->asma->file->f_op->fallocate(range->asma->file,
|
get_file(f);
|
||||||
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
atomic_inc(&ashmem_shrink_inflight);
|
||||||
start, end - start);
|
|
||||||
range->purged = ASHMEM_WAS_PURGED;
|
range->purged = ASHMEM_WAS_PURGED;
|
||||||
lru_del(range);
|
lru_del(range);
|
||||||
|
|
||||||
freed += range_size(range);
|
freed += range_size(range);
|
||||||
|
mutex_unlock(&ashmem_mutex);
|
||||||
|
f->f_op->fallocate(f,
|
||||||
|
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||||
|
start, end - start);
|
||||||
|
fput(f);
|
||||||
|
if (atomic_dec_and_test(&ashmem_shrink_inflight))
|
||||||
|
wake_up_all(&ashmem_shrink_wait);
|
||||||
|
if (!mutex_trylock(&ashmem_mutex))
|
||||||
|
goto out;
|
||||||
if (--sc->nr_to_scan <= 0)
|
if (--sc->nr_to_scan <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mutex_unlock(&ashmem_mutex);
|
mutex_unlock(&ashmem_mutex);
|
||||||
|
out:
|
||||||
return freed;
|
return freed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,6 +728,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
mutex_lock(&ashmem_mutex);
|
mutex_lock(&ashmem_mutex);
|
||||||
|
wait_event(ashmem_shrink_wait, !atomic_read(&ashmem_shrink_inflight));
|
||||||
|
|
||||||
if (!asma->file)
|
if (!asma->file)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче