Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / infiniband / hw / ipath / ipath_user_pages.c
1 /*
2  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32
33 #include <linux/mm.h>
34 #include <linux/device.h>
35 #include <linux/vs_memory.h>
36
37 #include "ipath_kernel.h"
38
39 static void __ipath_release_user_pages(struct page **p, size_t num_pages,
40                                    int dirty)
41 {
42         size_t i;
43
44         for (i = 0; i < num_pages; i++) {
45                 ipath_cdbg(MM, "%lu/%lu put_page %p\n", (unsigned long) i,
46                            (unsigned long) num_pages, p[i]);
47                 if (dirty)
48                         set_page_dirty_lock(p[i]);
49                 put_page(p[i]);
50         }
51 }
52
53 /* call with current->mm->mmap_sem held */
54 static int __get_user_pages(unsigned long start_page, size_t num_pages,
55                         struct page **p, struct vm_area_struct **vma)
56 {
57         unsigned long lock_limit;
58         size_t got;
59         int ret;
60
61 #if 0
62         /*
63          * XXX - causes MPI programs to fail, haven't had time to check
64          * yet
65          */
66         if (!capable(CAP_IPC_LOCK)) {
67                 ret = -EPERM;
68                 goto bail;
69         }
70 #endif
71
72         lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >>
73                 PAGE_SHIFT;
74
75         if (num_pages > lock_limit ||
76                 !vx_vmlocked_avail(current->mm, num_pages)) {
77                 ret = -ENOMEM;
78                 goto bail;
79         }
80
81         ipath_cdbg(VERBOSE, "pin %lx pages from vaddr %lx\n",
82                    (unsigned long) num_pages, start_page);
83
84         for (got = 0; got < num_pages; got += ret) {
85                 ret = get_user_pages(current, current->mm,
86                                      start_page + got * PAGE_SIZE,
87                                      num_pages - got, 1, 1,
88                                      p + got, vma);
89                 if (ret < 0)
90                         goto bail_release;
91         }
92
93         vx_vmlocked_add(current->mm, num_pages);
94
95         ret = 0;
96         goto bail;
97
98 bail_release:
99         __ipath_release_user_pages(p, got, 0);
100 bail:
101         return ret;
102 }
103
104 /**
105  * ipath_get_user_pages - lock user pages into memory
106  * @start_page: the start page
107  * @num_pages: the number of pages
108  * @p: the output page structures
109  *
110  * This function takes a given start page (page aligned user virtual
111  * address) and pins it and the following specified number of pages.  For
112  * now, num_pages is always 1, but that will probably change at some point
113  * (because caller is doing expected sends on a single virtually contiguous
114  * buffer, so we can do all pages at once).
115  */
116 int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
117                          struct page **p)
118 {
119         int ret;
120
121         down_write(&current->mm->mmap_sem);
122
123         ret = __get_user_pages(start_page, num_pages, p, NULL);
124
125         up_write(&current->mm->mmap_sem);
126
127         return ret;
128 }
129
130 /**
131  * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared
132  * @start_page: the page to lock
133  * @p: the output page structure
134  *
135  * This is similar to ipath_get_user_pages, but it's always one page, and we
136  * mark the page as locked for I/O, and shared.  This is used for the user
137  * process page that contains the destination address for the rcvhdrq tail
138  * update, so we need to have the vma. If we don't do this, the page can be
139  * taken away from us on fork, even if the child never touches it, and then
140  * the user process never sees the tail register updates.
141  */
142 int ipath_get_user_pages_nocopy(unsigned long page, struct page **p)
143 {
144         struct vm_area_struct *vma;
145         int ret;
146
147         down_write(&current->mm->mmap_sem);
148
149         ret = __get_user_pages(page, 1, p, &vma);
150
151         up_write(&current->mm->mmap_sem);
152
153         return ret;
154 }
155
156 void ipath_release_user_pages(struct page **p, size_t num_pages)
157 {
158         down_write(&current->mm->mmap_sem);
159
160         __ipath_release_user_pages(p, num_pages, 1);
161
162         vx_vmlocked_sub(current->mm, num_pages);
163
164         up_write(&current->mm->mmap_sem);
165 }
166
167 struct ipath_user_pages_work {
168         struct work_struct work;
169         struct mm_struct *mm;
170         unsigned long num_pages;
171 };
172
173 static void user_pages_account(void *ptr)
174 {
175         struct ipath_user_pages_work *work = ptr;
176
177         down_write(&work->mm->mmap_sem);
178         vx_vmlocked_sub(work->mm, work->num_pages);
179         up_write(&work->mm->mmap_sem);
180         mmput(work->mm);
181         kfree(work);
182 }
183
184 void ipath_release_user_pages_on_close(struct page **p, size_t num_pages)
185 {
186         struct ipath_user_pages_work *work;
187         struct mm_struct *mm;
188
189         __ipath_release_user_pages(p, num_pages, 1);
190
191         mm = get_task_mm(current);
192         if (!mm)
193                 goto bail;
194
195         work = kmalloc(sizeof(*work), GFP_KERNEL);
196         if (!work)
197                 goto bail_mm;
198
199         goto bail;
200
201         INIT_WORK(&work->work, user_pages_account, work);
202         work->mm = mm;
203         work->num_pages = num_pages;
204
205 bail_mm:
206         mmput(mm);
207 bail:
208         return;
209 }