111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love/* mm/ashmem.c
22258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop *
32258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * Anonymous Shared Memory Subsystem, ashmem
42258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop *
52258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * Copyright (C) 2008 Google, Inc.
62258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop *
72258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * Robert Love <rlove@google.com>
82258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop *
92258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * This software is licensed under the terms of the GNU General Public
102258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * License version 2, as published by the Free Software Foundation, and
112258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * may be copied, distributed, and modified under those terms.
122258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop *
132258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * This program is distributed in the hope that it will be useful,
142258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * but WITHOUT ANY WARRANTY; without even the implied warranty of
152258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
162258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop * GNU General Public License for more details.
172258937b2137214bae796ec929394a282f531ed7Cruz Julian Bishop */
1811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
19c810a399798022d545191e2daaca0368623c15d3Sachin Kamat#define pr_fmt(fmt) "ashmem: " fmt
20c810a399798022d545191e2daaca0368623c15d3Sachin Kamat
2111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/module.h>
2211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/file.h>
2311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/fs.h>
243f31d07571eeea18a7d34db9af21d2285b807a17Hugh Dickins#include <linux/falloc.h>
2511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/miscdevice.h>
2611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/security.h>
2711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/mm.h>
2811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/mman.h>
2911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/uaccess.h>
3011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/personality.h>
3111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/bitops.h>
3211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/mutex.h>
3311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include <linux/shmem_fs.h>
3411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#include "ashmem.h"
3511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
3611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define ASHMEM_NAME_PREFIX "dev/ashmem/"
3711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1)
3811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define ASHMEM_FULL_NAME_LEN (ASHMEM_NAME_LEN + ASHMEM_NAME_PREFIX_LEN)
3911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
404d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
414d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * struct ashmem_area - The anonymous shared memory area
424d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @name:		The optional name in /proc/pid/maps
434d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @unpinned_list:	The list of all ashmem areas
444d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @file:		The shmem-based backing file
454d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @size:		The size of the mapping, in bytes
464d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @prot_masks:		The allowed protection bits, as vm_flags
474d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop *
484d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * The lifecycle of this structure is from our parent file's open() until
494d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * its release(). It is also protected by 'ashmem_mutex'
504d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop *
514d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * Warning: Mappings do NOT pin this structure; It dies on close()
5211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love */
5311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestruct ashmem_area {
544d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	char name[ASHMEM_FULL_NAME_LEN];
554d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	struct list_head unpinned_list;
564d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	struct file *file;
574d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	size_t size;
584d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	unsigned long prot_mask;
5911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love};
6011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
614d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
624d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * struct ashmem_range - A range of unpinned/evictable pages
634d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @lru:	         The entry in the LRU list
644d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @unpinned:	         The entry in its area's unpinned list
654d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @asma:	         The associated anonymous shared memory area.
664d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @pgstart:	         The starting page (inclusive)
674d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @pgend:	         The ending page (inclusive)
684d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @purged:	         The purge status (ASHMEM_NOT or ASHMEM_WAS_PURGED)
694d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop *
704d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * The lifecycle of this structure is from unpin to pin.
714d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * It is protected by 'ashmem_mutex'
7211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love */
7311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestruct ashmem_range {
744d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	struct list_head lru;
754d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	struct list_head unpinned;
764d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	struct ashmem_area *asma;
774d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	size_t pgstart;
784d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	size_t pgend;
794d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop	unsigned int purged;
8011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love};
8111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
8211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love/* LRU list of unpinned pages, protected by ashmem_mutex */
8311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic LIST_HEAD(ashmem_lru_list);
8411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
854d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
864d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * long lru_count - The count of pages on our LRU list.
874d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop *
884d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * This is protected by ashmem_mutex.
894d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop */
9011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic unsigned long lru_count;
9111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
924d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
9311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love * ashmem_mutex - protects the list of and each individual ashmem_area
9411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love *
9511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love * Lock Ordering: ashmex_mutex -> i_mutex -> i_alloc_sem
9611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love */
9711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic DEFINE_MUTEX(ashmem_mutex);
9811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
9911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic struct kmem_cache *ashmem_area_cachep __read_mostly;
10011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic struct kmem_cache *ashmem_range_cachep __read_mostly;
10111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
10211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define range_size(range) \
1031efb34394a694b458d66f25072318c375e22afe2John Stultz	((range)->pgend - (range)->pgstart + 1)
10411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
10511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define range_on_lru(range) \
1061efb34394a694b458d66f25072318c375e22afe2John Stultz	((range)->purged == ASHMEM_NOT_PURGED)
10711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
10811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define page_range_subsumes_range(range, start, end) \
1091efb34394a694b458d66f25072318c375e22afe2John Stultz	(((range)->pgstart >= (start)) && ((range)->pgend <= (end)))
11011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
11111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define page_range_subsumed_by_range(range, start, end) \
1121efb34394a694b458d66f25072318c375e22afe2John Stultz	(((range)->pgstart <= (start)) && ((range)->pgend >= (end)))
11311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
11411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define page_in_range(range, page) \
1151efb34394a694b458d66f25072318c375e22afe2John Stultz	(((range)->pgstart <= (page)) && ((range)->pgend >= (page)))
11611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
11711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define page_range_in_range(range, start, end) \
1181efb34394a694b458d66f25072318c375e22afe2John Stultz	(page_in_range(range, start) || page_in_range(range, end) || \
1191efb34394a694b458d66f25072318c375e22afe2John Stultz		page_range_subsumes_range(range, start, end))
12011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
12111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define range_before_page(range, page) \
1221efb34394a694b458d66f25072318c375e22afe2John Stultz	((range)->pgend < (page))
12311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
12411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love#define PROT_MASK		(PROT_EXEC | PROT_READ | PROT_WRITE)
12511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
1264d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
1274d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * lru_add() - Adds a range of memory to the LRU list
1284d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @range:     The memory range being added.
1294d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop *
1304d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * The range is first added to the end (tail) of the LRU list.
1314d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * After this, the size of the range is added to @lru_count
1324d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop */
13311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic inline void lru_add(struct ashmem_range *range)
13411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love{
13511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	list_add_tail(&range->lru, &ashmem_lru_list);
13611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	lru_count += range_size(range);
13711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love}
13811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
1394d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
1404d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * lru_del() - Removes a range of memory from the LRU list
1414d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @range:     The memory range being removed
1424d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop *
1434d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * The range is first deleted from the LRU list.
1444d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * After this, the size of the range is removed from @lru_count
1454d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop */
14611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic inline void lru_del(struct ashmem_range *range)
14711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love{
14811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	list_del(&range->lru);
14911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	lru_count -= range_size(range);
15011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love}
15111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
1524d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
1534d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * range_alloc() - Allocates and initializes a new ashmem_range structure
1544d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @asma:	   The associated ashmem_area
1554d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @prev_range:	   The previous ashmem_range in the sorted asma->unpinned list
1564d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @purged:	   Initial purge status (ASMEM_NOT_PURGED or ASHMEM_WAS_PURGED)
1574d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @start:	   The starting page (inclusive)
1584d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @end:	   The ending page (inclusive)
15911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love *
1604d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * This function is protected by ashmem_mutex.
16111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love *
1624d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * Return: 0 if successful, or -ENOMEM if there is an error
16311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love */
16411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic int range_alloc(struct ashmem_area *asma,
16511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		       struct ashmem_range *prev_range, unsigned int purged,
16611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		       size_t start, size_t end)
16711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love{
16811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	struct ashmem_range *range;
16911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
17011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range = kmem_cache_zalloc(ashmem_range_cachep, GFP_KERNEL);
17111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	if (unlikely(!range))
17211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		return -ENOMEM;
17311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
17411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range->asma = asma;
17511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range->pgstart = start;
17611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range->pgend = end;
17711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range->purged = purged;
17811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
17911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	list_add_tail(&range->unpinned, &prev_range->unpinned);
18011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
18111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	if (range_on_lru(range))
18211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		lru_add(range);
18311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
18411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	return 0;
18511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love}
18611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
1874d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop/**
1884d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * range_del() - Deletes and dealloctes an ashmem_range structure
1894d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop * @range:	 The associated ashmem_range that has previously been allocated
1904d2c9d5ddc3a38abb12253b4fd6ac05bfc3b4462Cruz Julian Bishop */
19111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic void range_del(struct ashmem_range *range)
19211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love{
19311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	list_del(&range->unpinned);
19411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	if (range_on_lru(range))
19511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		lru_del(range);
19611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	kmem_cache_free(ashmem_range_cachep, range);
19711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love}
19811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
199781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop/**
200781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * range_shrink() - Shrinks an ashmem_range
201781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * @range:	    The associated ashmem_range being shrunk
202781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * @start:	    The starting byte of the new range
203781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * @end:	    The ending byte of the new range
204781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop *
205781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * This does not modify the data inside the existing range in any way - It
206781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * simply shrinks the boundaries of the range.
20711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love *
208781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * Theoretically, with a little tweaking, this could eventually be changed
209781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * to range_resize, and expand the lru_count if the new range is larger.
21011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love */
21111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic inline void range_shrink(struct ashmem_range *range,
21211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love				size_t start, size_t end)
21311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love{
21411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	size_t pre = range_size(range);
21511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
21611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range->pgstart = start;
21711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	range->pgend = end;
21811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
21911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	if (range_on_lru(range))
22011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		lru_count -= pre - range_size(range);
22111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love}
22211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
223781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop/**
224781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * ashmem_open() - Opens an Anonymous Shared Memory structure
225781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * @inode:	   The backing file's index node(?)
226781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * @file:	   The backing file
227781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop *
228781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * Please note that the ashmem_area is not returned by this function - It is
229781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * instead written to "file->private_data".
230781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop *
231781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop * Return: 0 if successful, or another code if unsuccessful.
232781114ced258bac3cff00342c9dafda1afe93c6dCruz Julian Bishop */
23311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Lovestatic int ashmem_open(struct inode *inode, struct file *file)
23411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love{
23511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	struct ashmem_area *asma;
23611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	int ret;
23711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
2385154b93b8eceb57bdab4e77030bf21ead15b42e4Bjorn Bringert	ret = generic_file_open(inode, file);
23911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	if (unlikely(ret))
24011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		return ret;
24111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
24211980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL);
24311980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	if (unlikely(!asma))
24411980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love		return -ENOMEM;
24511980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
24611980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	INIT_LIST_HEAD(&asma->unpinned_list);
24711980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN);
24811980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	asma->prot_mask = PROT_MASK;
24911980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	file->private_data = asma;
25011980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love
25111980c2ac4ccfad21a5f8ee9e12059f1e687bb40Robert Love	return 0;
252