aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-02-20 16:57:53 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-20 20:10:13 -0500
commitbc56bba8f31bd99f350a5ebfd43d50f411b620c7 (patch)
tree68213ce8da2f7af8e3f39b77c078d6162776a95c /ipc
parent8ef8286689c6b5bc76212437b85bdd2ba749ee44 (diff)
[PATCH] shm: make sysv ipc shared memory use stacked files
The current ipc shared memory code runs into several problems because it does not quite use files like the rest of the kernel. With the option of backing ipc shared memory with either hugetlbfs or ordinary shared memory the problems got worse. With the added support for ipc namespaces things behaved so unexpected that we now have several bad namespace reference counting bugs when using what appears at first glance to be a reasonable idiom. So to attack these problems and hopefully make the code more maintainable this patch simply uses the files provided by other parts of the kernel and builds it's own files out of them. The shm files are allocated in do_shmat and freed when their reference count drops to zero with their last unmap. The file and vm operations that we don't want to implement or we don't implement completely we just delegate to the operations of our backing file. This means that we now get an accurate shm_nattch count for we have a hugetlbfs inode for backing store, and the shm accounting of last attach and last detach time work as well. This means that getting a reference to the ipc namespace when we create the file and dropping the referenece in the release method is now safe and correct. This means we no longer need a special case for clearing VM_MAYWRITE as our file descriptor now only has write permissions when we have requested write access when calling shmat. Although VM_SHARED is now cleared as well which I believe is harmless and is mostly likely a minor bug fix. By using the same set of operations for both the hugetlb case and regular shared memory case shmdt is not simplified and made slightly more correct as now the test "vma->vm_ops == &shm_vm_ops" is 100% accurate in spotting all shared memory regions generated from sysvipc shared memory. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Michal Piotrowski <michal.k.k.piotrowski@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/shm.c240
1 files changed, 155 insertions, 85 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 5bb617f6306e..eb57e2254304 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -37,11 +37,21 @@
37#include <linux/seq_file.h> 37#include <linux/seq_file.h>
38#include <linux/mutex.h> 38#include <linux/mutex.h>
39#include <linux/nsproxy.h> 39#include <linux/nsproxy.h>
40#include <linux/mount.h>
40 41
41#include <asm/uaccess.h> 42#include <asm/uaccess.h>
42 43
43#include "util.h" 44#include "util.h"
44 45
46struct shm_file_data {
47 int id;
48 struct ipc_namespace *ns;
49 struct file *file;
50 const struct vm_operations_struct *vm_ops;
51};
52
53#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
54
45static const struct file_operations shm_file_operations; 55static const struct file_operations shm_file_operations;
46static struct vm_operations_struct shm_vm_ops; 56static struct vm_operations_struct shm_vm_ops;
47 57
@@ -60,8 +70,8 @@ static struct ipc_ids init_shm_ids;
60 70
61static int newseg (struct ipc_namespace *ns, key_t key, 71static int newseg (struct ipc_namespace *ns, key_t key,
62 int shmflg, size_t size); 72 int shmflg, size_t size);
63static void shm_open (struct vm_area_struct *shmd); 73static void shm_open(struct vm_area_struct *vma);
64static void shm_close (struct vm_area_struct *shmd); 74static void shm_close(struct vm_area_struct *vma);
65static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); 75static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
66#ifdef CONFIG_PROC_FS 76#ifdef CONFIG_PROC_FS
67static int sysvipc_shm_proc_show(struct seq_file *s, void *it); 77static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
@@ -150,11 +160,14 @@ static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
150 160
151 161
152 162
153static inline void shm_inc(struct ipc_namespace *ns, int id) 163/* This is called by fork, once for every shm attach. */
164static void shm_open(struct vm_area_struct *vma)
154{ 165{
166 struct file *file = vma->vm_file;
167 struct shm_file_data *sfd = shm_file_data(file);
155 struct shmid_kernel *shp; 168 struct shmid_kernel *shp;
156 169
157 shp = shm_lock(ns, id); 170 shp = shm_lock(sfd->ns, sfd->id);
158 BUG_ON(!shp); 171 BUG_ON(!shp);
159 shp->shm_atim = get_seconds(); 172 shp->shm_atim = get_seconds();
160 shp->shm_lprid = current->tgid; 173 shp->shm_lprid = current->tgid;
@@ -162,15 +175,6 @@ static inline void shm_inc(struct ipc_namespace *ns, int id)
162 shm_unlock(shp); 175 shm_unlock(shp);
163} 176}
164 177
165#define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data))
166
167/* This is called by fork, once for every shm attach. */
168static void shm_open(struct vm_area_struct *shmd)
169{
170 shm_inc(shm_file_ns(shmd->vm_file),
171 shmd->vm_file->f_path.dentry->d_inode->i_ino);
172}
173
174/* 178/*
175 * shm_destroy - free the struct shmid_kernel 179 * shm_destroy - free the struct shmid_kernel
176 * 180 *
@@ -195,23 +199,21 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
195} 199}
196 200
197/* 201/*
198 * remove the attach descriptor shmd. 202 * remove the attach descriptor vma.
199 * free memory for segment if it is marked destroyed. 203 * free memory for segment if it is marked destroyed.
200 * The descriptor has already been removed from the current->mm->mmap list 204 * The descriptor has already been removed from the current->mm->mmap list
201 * and will later be kfree()d. 205 * and will later be kfree()d.
202 */ 206 */
203static void shm_close (struct vm_area_struct *shmd) 207static void shm_close(struct vm_area_struct *vma)
204{ 208{
205 struct file * file = shmd->vm_file; 209 struct file * file = vma->vm_file;
206 int id = file->f_path.dentry->d_inode->i_ino; 210 struct shm_file_data *sfd = shm_file_data(file);
207 struct shmid_kernel *shp; 211 struct shmid_kernel *shp;
208 struct ipc_namespace *ns; 212 struct ipc_namespace *ns = sfd->ns;
209
210 ns = shm_file_ns(file);
211 213
212 mutex_lock(&shm_ids(ns).mutex); 214 mutex_lock(&shm_ids(ns).mutex);
213 /* remove from the list of attaches of the shm segment */ 215 /* remove from the list of attaches of the shm segment */
214 shp = shm_lock(ns, id); 216 shp = shm_lock(ns, sfd->id);
215 BUG_ON(!shp); 217 BUG_ON(!shp);
216 shp->shm_lprid = current->tgid; 218 shp->shm_lprid = current->tgid;
217 shp->shm_dtim = get_seconds(); 219 shp->shm_dtim = get_seconds();
@@ -224,46 +226,91 @@ static void shm_close (struct vm_area_struct *shmd)
224 mutex_unlock(&shm_ids(ns).mutex); 226 mutex_unlock(&shm_ids(ns).mutex);
225} 227}
226 228
229struct page *shm_nopage(struct vm_area_struct *vma, unsigned long address,
230 int *type)
231{
232 struct file *file = vma->vm_file;
233 struct shm_file_data *sfd = shm_file_data(file);
234
235 return sfd->vm_ops->nopage(vma, address, type);
236}
237
238#ifdef CONFIG_NUMA
239int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
240{
241 struct file *file = vma->vm_file;
242 struct shm_file_data *sfd = shm_file_data(file);
243 int err = 0;
244 if (sfd->vm_ops->set_policy)
245 err = sfd->vm_ops->set_policy(vma, new);
246 return err;
247}
248
249struct mempolicy *shm_get_policy(struct vm_area_struct *vma, unsigned long addr)
250{
251 struct file *file = vma->vm_file;
252 struct shm_file_data *sfd = shm_file_data(file);
253 struct mempolicy *pol = NULL;
254
255 if (sfd->vm_ops->get_policy)
256 pol = sfd->vm_ops->get_policy(vma, addr);
257 else
258 pol = vma->vm_policy;
259 return pol;
260}
261#endif
262
227static int shm_mmap(struct file * file, struct vm_area_struct * vma) 263static int shm_mmap(struct file * file, struct vm_area_struct * vma)
228{ 264{
265 struct shm_file_data *sfd = shm_file_data(file);
229 int ret; 266 int ret;
230 267
231 ret = shmem_mmap(file, vma); 268 ret = sfd->file->f_op->mmap(sfd->file, vma);
232 if (ret == 0) { 269 if (ret != 0)
233 vma->vm_ops = &shm_vm_ops; 270 return ret;
234 if (!(vma->vm_flags & VM_WRITE)) 271 sfd->vm_ops = vma->vm_ops;
235 vma->vm_flags &= ~VM_MAYWRITE; 272 vma->vm_ops = &shm_vm_ops;
236 shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino); 273 shm_open(vma);
237 }
238 274
239 return ret; 275 return ret;
240} 276}
241 277
242static int shm_release(struct inode *ino, struct file *file) 278static int shm_release(struct inode *ino, struct file *file)
243{ 279{
244 struct ipc_namespace *ns; 280 struct shm_file_data *sfd = shm_file_data(file);
245 281
246 ns = shm_file_ns(file); 282 put_ipc_ns(sfd->ns);
247 put_ipc_ns(ns); 283 shm_file_data(file) = NULL;
248 shm_file_ns(file) = NULL; 284 kfree(sfd);
249 return 0; 285 return 0;
250} 286}
251 287
288#ifndef CONFIG_MMU
289static unsigned long shm_get_unmapped_area(struct file *file,
290 unsigned long addr, unsigned long len, unsigned long pgoff,
291 unsigned long flags)
292{