Commit fb4415a1 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by Greg Kroah-Hartman
Browse files

staging: android: ashmem: Don't call fallocate() with ashmem_mutex held.

parent f54a7401
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -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 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
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;