1/*-
2 * Copyright (c) 2010 Isilon Systems, Inc.
3 * Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io)
4 * Copyright (c) 2017 Mellanox Technologies, Ltd.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/rwlock.h>
35
36#include <vm/vm.h>
37#include <vm/pmap.h>
38#include <vm/vm_object.h>
39#include <vm/vm_map.h>
40#include <vm/vm_page.h>
41#include <vm/vm_pager.h>
42
43#include <linux/fs.h>
44#include <linux/mm.h>
45#include <linux/shmem_fs.h>
46
47struct page *
48linux_shmem_read_mapping_page_gfp(vm_object_t obj, int pindex, gfp_t gfp)
49{
50	vm_page_t page;
51	int rv;
52
53	if ((gfp & GFP_NOWAIT) != 0)
54		panic("GFP_NOWAIT is unimplemented");
55
56	VM_OBJECT_WLOCK(obj);
57	rv = vm_page_grab_valid(&page, obj, pindex, VM_ALLOC_NORMAL |
58	    VM_ALLOC_NOBUSY | VM_ALLOC_WIRED);
59	VM_OBJECT_WUNLOCK(obj);
60	if (rv != VM_PAGER_OK)
61		return (ERR_PTR(-EINVAL));
62	return (page);
63}
64
65struct linux_file *
66linux_shmem_file_setup(const char *name, loff_t size, unsigned long flags)
67{
68	struct fileobj {
69		struct linux_file file __aligned(sizeof(void *));
70		struct vnode vnode __aligned(sizeof(void *));
71	};
72	struct fileobj *fileobj;
73	struct linux_file *filp;
74	struct vnode *vp;
75	int error;
76
77	fileobj = kzalloc(sizeof(*fileobj), GFP_KERNEL);
78	if (fileobj == NULL) {
79		error = -ENOMEM;
80		goto err_0;
81	}
82	filp = &fileobj->file;
83	vp = &fileobj->vnode;
84
85	filp->f_count = 1;
86	filp->f_vnode = vp;
87	filp->f_shmem = vm_pager_allocate(OBJT_DEFAULT, NULL, size,
88	    VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred);
89	if (filp->f_shmem == NULL) {
90		error = -ENOMEM;
91		goto err_1;
92	}
93	return (filp);
94err_1:
95	kfree(filp);
96err_0:
97	return (ERR_PTR(error));
98}
99
100static vm_ooffset_t
101linux_invalidate_mapping_pages_sub(vm_object_t obj, vm_pindex_t start,
102    vm_pindex_t end, int flags)
103{
104	int start_count, end_count;
105
106	VM_OBJECT_WLOCK(obj);
107	start_count = obj->resident_page_count;
108	vm_object_page_remove(obj, start, end, flags);
109	end_count = obj->resident_page_count;
110	VM_OBJECT_WUNLOCK(obj);
111	return (start_count - end_count);
112}
113
114unsigned long
115linux_invalidate_mapping_pages(vm_object_t obj, pgoff_t start, pgoff_t end)
116{
117
118	return (linux_invalidate_mapping_pages_sub(obj, start, end, OBJPR_CLEANONLY));
119}
120
121void
122linux_shmem_truncate_range(vm_object_t obj, loff_t lstart, loff_t lend)
123{
124	vm_pindex_t start = OFF_TO_IDX(lstart + PAGE_SIZE - 1);
125	vm_pindex_t end = OFF_TO_IDX(lend + 1);
126
127	(void) linux_invalidate_mapping_pages_sub(obj, start, end, 0);
128}
129