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 */
|
||||
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.
|
||||
*
|
||||
|
@ -439,7 +442,6 @@ out:
|
|||
static unsigned long
|
||||
ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
struct ashmem_range *range, *next;
|
||||
unsigned long freed = 0;
|
||||
|
||||
/* 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))
|
||||
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 end = (range->pgend + 1) * PAGE_SIZE;
|
||||
struct file *f = range->asma->file;
|
||||
|
||||
range->asma->file->f_op->fallocate(range->asma->file,
|
||||
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||
start, end - start);
|
||||
get_file(f);
|
||||
atomic_inc(&ashmem_shrink_inflight);
|
||||
range->purged = ASHMEM_WAS_PURGED;
|
||||
lru_del(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)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&ashmem_mutex);
|
||||
out:
|
||||
return freed;
|
||||
}
|
||||
|
||||
|
@ -714,6 +728,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
|
|||
return -EFAULT;
|
||||
|
||||
mutex_lock(&ashmem_mutex);
|
||||
wait_event(ashmem_shrink_wait, !atomic_read(&ashmem_shrink_inflight));
|
||||
|
||||
if (!asma->file)
|
||||
goto out_unlock;
|
||||
|
|
Загрузка…
Ссылка в новой задаче