Blame view

ipc/shm.c 29.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * linux/ipc/shm.c
   * Copyright (C) 1992, 1993 Krishna Balasubramanian
   *	 Many improvements/fixes by Bruno Haible.
   * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
   * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
   *
   * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
   * BIGMEM support, Andrea Arcangeli <andrea@suse.de>
   * SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
   * HIGHMEM support, Ingo Molnar <mingo@redhat.com>
   * Make shmmax, shmall, shmmni sysctl'able, Christoph Rohland <cr@sap.com>
   * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
   * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
   *
073115d6b   Steve Grubb   [PATCH] Rework of...
16
17
   * support for audit of ipc object properties and permission changes
   * Dustin Kirkland <dustin.kirkland@us.ibm.com>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
18
19
20
21
   *
   * namespaces support
   * OpenVZ, SWsoft Inc.
   * Pavel Emelianov <xemul@openvz.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/hugetlb.h>
  #include <linux/shm.h>
  #include <linux/init.h>
  #include <linux/file.h>
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  #include <linux/shmem_fs.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
  #include <linux/audit.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
34
  #include <linux/capability.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
35
  #include <linux/ptrace.h>
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
36
  #include <linux/seq_file.h>
3e148c799   Nadia Derbey   fix idr_find() lo...
37
  #include <linux/rwsem.h>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
38
  #include <linux/nsproxy.h>
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
39
  #include <linux/mount.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
40
  #include <linux/ipc_namespace.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
41

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  #include <asm/uaccess.h>
  
  #include "util.h"
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
45
46
47
48
49
50
51
52
  struct shm_file_data {
  	int id;
  	struct ipc_namespace *ns;
  	struct file *file;
  	const struct vm_operations_struct *vm_ops;
  };
  
  #define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
53
  static const struct file_operations shm_file_operations;
f0f37e2f7   Alexey Dobriyan   const: mark struc...
54
  static const struct vm_operations_struct shm_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

ed2ddbf88   Pierre Peiffer   IPC: make struct ...
56
  #define shm_ids(ns)	((ns)->ids[IPC_SHM_IDS])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

4e9823111   Kirill Korotaev   [PATCH] IPC names...
58
59
  #define shm_unlock(shp)			\
  	ipc_unlock(&(shp)->shm_perm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

7748dbfaa   Nadia Derbey   ipc: unify the sy...
61
  static int newseg(struct ipc_namespace *, struct ipc_params *);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
62
63
  static void shm_open(struct vm_area_struct *vma);
  static void shm_close(struct vm_area_struct *vma);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
64
  static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
66
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  #endif
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
68
  void shm_init_ns(struct ipc_namespace *ns)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
69
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
70
71
72
  	ns->shm_ctlmax = SHMMAX;
  	ns->shm_ctlall = SHMALL;
  	ns->shm_ctlmni = SHMMNI;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
73
  	ns->shm_rmid_forced = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
74
  	ns->shm_tot = 0;
e8148f758   WANG Cong   ipc: clean up ipc...
75
  	ipc_init_ids(&shm_ids(ns));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
76
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
77
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
78
79
   * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
   * Only shm_ids.rw_mutex remains locked on exit.
f4566f048   Nadia Derbey   ipc: fix wrong co...
80
   */
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
81
  static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
82
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
83
84
  	struct shmid_kernel *shp;
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
85
86
87
88
89
90
91
92
  	if (shp->shm_nattch){
  		shp->shm_perm.mode |= SHM_DEST;
  		/* Do not find it any more */
  		shp->shm_perm.key = IPC_PRIVATE;
  		shm_unlock(shp);
  	} else
  		shm_destroy(ns, shp);
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
93
  #ifdef CONFIG_IPC_NS
4e9823111   Kirill Korotaev   [PATCH] IPC names...
94
95
  void shm_exit_ns(struct ipc_namespace *ns)
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
96
  	free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
7d6feeb28   Serge E. Hallyn   ipc ns: fix memor...
97
  	idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
98
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
99
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

140d0b210   Linus Torvalds   Do 'shm_init_ns()...
101
  static int __init ipc_ns_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
103
  	shm_init_ns(&init_ipc_ns);
140d0b210   Linus Torvalds   Do 'shm_init_ns()...
104
105
106
107
108
109
110
  	return 0;
  }
  
  pure_initcall(ipc_ns_init);
  
  void __init shm_init (void)
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
111
  	ipc_init_proc_interface("sysvipc/shm",
b79521807   Helge Deller   ipc/shm.c: add RS...
112
113
114
115
116
117
118
  #if BITS_PER_LONG <= 32
  				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap
  ",
  #else
  				"       key      shmid perms                  size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime                   rss                  swap
  ",
  #endif
4e9823111   Kirill Korotaev   [PATCH] IPC names...
119
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  }
3e148c799   Nadia Derbey   fix idr_find() lo...
121
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
122
   * shm_lock_(check_) routines are called in the paths where the rw_mutex
00c2bf85d   Nadia Derbey   ipc: get rid of i...
123
   * is not necessarily held.
3e148c799   Nadia Derbey   fix idr_find() lo...
124
   */
023a53557   Nadia Derbey   ipc: integrate ip...
125
  static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  {
03f02c765   Nadia Derbey   Storing ipcs into...
127
  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
128
129
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
130
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
023a53557   Nadia Derbey   ipc: integrate ip...
131
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
132
133
134
135
136
  static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
  {
  	rcu_read_lock();
  	spin_lock(&ipcp->shm_perm.lock);
  }
023a53557   Nadia Derbey   ipc: integrate ip...
137
138
139
  static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
  						int id)
  {
03f02c765   Nadia Derbey   Storing ipcs into...
140
  	struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
141
142
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
143
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  }
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
145
  static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
147
  	ipc_rmid(&shm_ids(ns), &s->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
150
151
  /* This is called by fork, once for every shm attach. */
  static void shm_open(struct vm_area_struct *vma)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
152
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
153
154
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
156
  	shp = shm_lock(sfd->ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
157
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	shp->shm_atim = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
159
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
166
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
   * @shp: struct to free
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
169
   * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
172
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
174
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
175
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
  	shm_unlock(shp);
  	if (!is_file_hugepages(shp->shm_file))
  		shmem_lock(shp->shm_file, 0, shp->mlock_user);
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
179
  	else if (shp->mlock_user)
6d63079ad   Josef Sipek   [PATCH] struct pa...
180
  		user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
  						shp->mlock_user);
  	fput (shp->shm_file);
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  }
  
  /*
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
   * shm_may_destroy - identifies whether shm segment should be destroyed now
   *
   * Returns true if and only if there are no active users of the segment and
   * one of the following is true:
   *
   * 1) shmctl(id, IPC_RMID, NULL) was called for this shp
   *
   * 2) sysctl kernel.shm_rmid_forced is set to 1.
   */
  static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
  {
  	return (shp->shm_nattch == 0) &&
  	       (ns->shm_rmid_forced ||
  		(shp->shm_perm.mode & SHM_DEST));
  }
  
  /*
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
205
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
   * free memory for segment if it is marked destroyed.
   * The descriptor has already been removed from the current->mm->mmap list
   * and will later be kfree()d.
   */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
210
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
212
213
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
215
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
216

3e148c799   Nadia Derbey   fix idr_find() lo...
217
  	down_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	/* remove from the list of attaches of the shm segment */
00c2bf85d   Nadia Derbey   ipc: get rid of i...
219
  	shp = shm_lock(ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
220
  	BUG_ON(IS_ERR(shp));
b488893a3   Pavel Emelyanov   pid namespaces: c...
221
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  	shp->shm_dtim = get_seconds();
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
224
225
226
227
228
229
  	if (shm_may_destroy(ns, shp))
  		shm_destroy(ns, shp);
  	else
  		shm_unlock(shp);
  	up_write(&shm_ids(ns).rw_mutex);
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
230
  /* Called with ns->shm_ids(ns).rw_mutex locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
231
232
233
  static int shm_try_destroy_current(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
234
235
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
236

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
237
  	if (shp->shm_creator != current)
5774ed014   Vasiliy Kulikov   shm: handle separ...
238
  		return 0;
5774ed014   Vasiliy Kulikov   shm: handle separ...
239
240
241
242
243
244
245
246
247
248
249
250
  
  	/*
  	 * Mark it as orphaned to destroy the segment when
  	 * kernel.shm_rmid_forced is changed.
  	 * It is noop if the following shm_may_destroy() returns true.
  	 */
  	shp->shm_creator = NULL;
  
  	/*
  	 * Don't even try to destroy it.  If shm_rmid_forced=0 and IPC_RMID
  	 * is not set, it shouldn't be deleted here.
  	 */
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
251
  	if (!ns->shm_rmid_forced)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
252
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
253

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
254
255
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
256
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
257
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
258
259
  	return 0;
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
260
  /* Called with ns->shm_ids(ns).rw_mutex locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
261
262
263
  static int shm_try_destroy_orphaned(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
264
265
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
266
267
268
269
  
  	/*
  	 * We want to destroy segments without users and with already
  	 * exit'ed originating process.
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
270
271
  	 *
  	 * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
272
  	 */
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
273
  	if (shp->shm_creator != NULL)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
274
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
275

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
276
277
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
278
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
279
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
280
281
282
283
284
285
  	return 0;
  }
  
  void shm_destroy_orphaned(struct ipc_namespace *ns)
  {
  	down_write(&shm_ids(ns).rw_mutex);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
286
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
287
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
288
289
290
291
292
293
  	up_write(&shm_ids(ns).rw_mutex);
  }
  
  
  void exit_shm(struct task_struct *task)
  {
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
294
  	struct ipc_namespace *ns = task->nsproxy->ipc_ns;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
295

298507d4d   Vasiliy Kulikov   shm: optimize exi...
296
297
  	if (shm_ids(ns).in_use == 0)
  		return;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
298
299
  	/* Destroy all already created segments, but not mapped yet */
  	down_write(&shm_ids(ns).rw_mutex);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
300
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
301
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
3e148c799   Nadia Derbey   fix idr_find() lo...
302
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
304
  static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
305
306
307
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
d0217ac04   Nick Piggin   mm: fault feedbac...
308
  	return sfd->vm_ops->fault(vma, vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
309
310
311
  }
  
  #ifdef CONFIG_NUMA
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
312
  static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
313
314
315
316
317
318
319
320
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
  	int err = 0;
  	if (sfd->vm_ops->set_policy)
  		err = sfd->vm_ops->set_policy(vma, new);
  	return err;
  }
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
321
322
  static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
323
324
325
326
327
328
329
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
  	struct mempolicy *pol = NULL;
  
  	if (sfd->vm_ops->get_policy)
  		pol = sfd->vm_ops->get_policy(vma, addr);
52cd3b074   Lee Schermerhorn   mempolicy: rework...
330
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
331
  		pol = vma->vm_policy;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
332

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
333
334
335
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
338
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
339
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
340
341
342
343
  	ret = sfd->file->f_op->mmap(sfd->file, vma);
  	if (ret != 0)
  		return ret;
  	sfd->vm_ops = vma->vm_ops;
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
344
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
345
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
346
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
347
348
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
349
350
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
352
353
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
354
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
355

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
356
357
358
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
359
360
  	return 0;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
361
  static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
516dffdcd   Adam Litke   [PATCH] Fix get_u...
362
  {
516dffdcd   Adam Litke   [PATCH] Fix get_u...
363
  	struct shm_file_data *sfd = shm_file_data(file);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
364

7ea808591   Christoph Hellwig   drop unused dentr...
365
366
  	if (!sfd->file->f_op->fsync)
  		return -EINVAL;
02c24a821   Josef Bacik   fs: push i_mutex ...
367
  	return sfd->file->f_op->fsync(sfd->file, start, end, datasync);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
368
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
369
370
371
372
373
  static unsigned long shm_get_unmapped_area(struct file *file,
  	unsigned long addr, unsigned long len, unsigned long pgoff,
  	unsigned long flags)
  {
  	struct shm_file_data *sfd = shm_file_data(file);
c4caa7781   Al Viro   file ->get_unmapp...
374
375
  	return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len,
  						pgoff, flags);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
376
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
377

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
378
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
379
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
380
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
381
  	.release	= shm_release,
ed5e5894b   David Howells   nommu: fix SYSV S...
382
383
384
  #ifndef CONFIG_MMU
  	.get_unmapped_area	= shm_get_unmapped_area,
  #endif
6038f373a   Arnd Bergmann   llseek: automatic...
385
  	.llseek		= noop_llseek,
c4caa7781   Al Viro   file ->get_unmapp...
386
387
388
389
390
391
  };
  
  static const struct file_operations shm_file_operations_huge = {
  	.mmap		= shm_mmap,
  	.fsync		= shm_fsync,
  	.release	= shm_release,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
392
  	.get_unmapped_area	= shm_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
393
  	.llseek		= noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  };
c4caa7781   Al Viro   file ->get_unmapp...
395
396
397
398
  int is_file_shm_hugepages(struct file *file)
  {
  	return file->f_op == &shm_file_operations_huge;
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
399
  static const struct vm_operations_struct shm_vm_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  	.open	= shm_open,	/* callback for a new vm-area open */
  	.close	= shm_close,	/* callback for when the vm-area is released */
54cb8821d   Nick Piggin   mm: merge populat...
402
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
403
404
405
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
408
409
410
411
412
  /**
   * newseg - Create a new shared memory segment
   * @ns: namespace
   * @params: ptr to the structure that contains key, size and shmflg
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
413
   * Called with shm_ids.rw_mutex held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
414
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
415
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
417
418
419
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
  	int error;
  	struct shmid_kernel *shp;
  	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
  	struct file * file;
  	char name[13];
  	int id;
ca16d140a   KOSAKI Motohiro   mm: don't access ...
426
  	vm_flags_t acctflag = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427

4e9823111   Kirill Korotaev   [PATCH] IPC names...
428
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
430
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
435
436
437
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
438
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
  	shp->mlock_user = NULL;
  
  	shp->shm_perm.security = NULL;
  	error = security_shm_alloc(shp);
  	if (error) {
  		ipc_rcu_putref(shp);
  		return error;
  	}
9d66586f7   Eric W. Biederman   shm: fix the file...
447
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  	if (shmflg & SHM_HUGETLB) {
5a6fe1259   Mel Gorman   Do not account fo...
449
450
451
  		/* hugetlb_file_setup applies strict accounting */
  		if (shmflg & SHM_NORESERVE)
  			acctflag = VM_NORESERVE;
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
452
  		file = hugetlb_file_setup(name, size, acctflag,
6bfde05bf   Eric B Munson   hugetlbfs: allow ...
453
  					&shp->mlock_user, HUGETLB_SHMFS_INODE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
455
456
457
458
459
460
  		/*
  		 * Do not allow no accounting for OVERCOMMIT_NEVER, even
  	 	 * if it's asked for.
  		 */
  		if  ((shmflg & SHM_NORESERVE) &&
  				sysctl_overcommit_memory != OVERCOMMIT_NEVER)
fc8744adc   Linus Torvalds   Stop playing sill...
461
  			acctflag = VM_NORESERVE;
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
462
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
48dea404e   Pierre Peiffer   IPC: use ipc_buil...
467
  	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
283bb7fad   Pierre Peiffer   IPC: fix error ca...
468
469
  	if (id < 0) {
  		error = id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  		goto no_id;
283bb7fad   Pierre Peiffer   IPC: fix error ca...
471
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

b488893a3   Pavel Emelyanov   pid namespaces: c...
473
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
  	shp->shm_lprid = 0;
  	shp->shm_atim = shp->shm_dtim = 0;
  	shp->shm_ctim = get_seconds();
  	shp->shm_segsz = size;
  	shp->shm_nattch = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	shp->shm_file = file;
5774ed014   Vasiliy Kulikov   shm: handle separ...
480
  	shp->shm_creator = current;
30475cc12   Badari Pulavarty   Restore shmid as ...
481
482
483
484
  	/*
  	 * shmid gets reported as "inode#" in /proc/pid/maps.
  	 * proc-ps tools use this. Changing this will break them.
  	 */
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
485
  	file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
486

4e9823111   Kirill Korotaev   [PATCH] IPC names...
487
  	ns->shm_tot += numpages;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
488
  	error = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  	shm_unlock(shp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
490
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  
  no_id:
2195d2818   Hugh Dickins   fix undefined ref...
493
  	if (is_file_hugepages(file) && shp->mlock_user)
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
494
  		user_shm_unlock(size, shp->mlock_user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
500
  	fput(file);
  no_file:
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
501
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
502
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
503
   */
03f02c765   Nadia Derbey   Storing ipcs into...
504
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
505
  {
03f02c765   Nadia Derbey   Storing ipcs into...
506
507
508
509
  	struct shmid_kernel *shp;
  
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
  	return security_shm_associate(shp, shmflg);
7748dbfaa   Nadia Derbey   ipc: unify the sy...
510
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
511
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
512
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
513
   */
03f02c765   Nadia Derbey   Storing ipcs into...
514
515
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
516
  {
03f02c765   Nadia Derbey   Storing ipcs into...
517
518
519
520
  	struct shmid_kernel *shp;
  
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
  	if (shp->shm_segsz < params->u.size)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
521
522
523
524
  		return -EINVAL;
  
  	return 0;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
525
  SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
527
  	struct ipc_namespace *ns;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
528
529
  	struct ipc_ops shm_ops;
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
530
531
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

7748dbfaa   Nadia Derbey   ipc: unify the sy...
533
534
535
  	shm_ops.getnew = newseg;
  	shm_ops.associate = shm_security;
  	shm_ops.more_checks = shm_more_checks;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
536

7748dbfaa   Nadia Derbey   ipc: unify the sy...
537
538
539
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540

7748dbfaa   Nadia Derbey   ipc: unify the sy...
541
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
548
549
550
551
  }
  
  static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
  {
  	switch(version) {
  	case IPC_64:
  		return copy_to_user(buf, in, sizeof(*in));
  	case IPC_OLD:
  	    {
  		struct shmid_ds out;
3af54c9bd   Vasiliy Kulikov   ipc: shm: fix inf...
552
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  		ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
  		out.shm_segsz	= in->shm_segsz;
  		out.shm_atime	= in->shm_atime;
  		out.shm_dtime	= in->shm_dtime;
  		out.shm_ctime	= in->shm_ctime;
  		out.shm_cpid	= in->shm_cpid;
  		out.shm_lpid	= in->shm_lpid;
  		out.shm_nattch	= in->shm_nattch;
  
  		return copy_to_user(buf, &out, sizeof(out));
  	    }
  	default:
  		return -EINVAL;
  	}
  }
016d7132f   Pierre Peiffer   IPC: get rid of t...
568
569
  static inline unsigned long
  copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
  {
  	switch(version) {
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
573
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
578
579
580
581
  	case IPC_OLD:
  	    {
  		struct shmid_ds tbuf_old;
  
  		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
  			return -EFAULT;
016d7132f   Pierre Peiffer   IPC: get rid of t...
582
583
584
  		out->shm_perm.uid	= tbuf_old.shm_perm.uid;
  		out->shm_perm.gid	= tbuf_old.shm_perm.gid;
  		out->shm_perm.mode	= tbuf_old.shm_perm.mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  
  		return 0;
  	    }
  	default:
  		return -EINVAL;
  	}
  }
  
  static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
  {
  	switch(version) {
  	case IPC_64:
  		return copy_to_user(buf, in, sizeof(*in));
  	case IPC_OLD:
  	    {
  		struct shminfo out;
  
  		if(in->shmmax > INT_MAX)
  			out.shmmax = INT_MAX;
  		else
  			out.shmmax = (int)in->shmmax;
  
  		out.shmmin	= in->shmmin;
  		out.shmmni	= in->shmmni;
  		out.shmseg	= in->shmseg;
  		out.shmall	= in->shmall; 
  
  		return copy_to_user(buf, &out, sizeof(out));
  	    }
  	default:
  		return -EINVAL;
  	}
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
618
  /*
b79521807   Helge Deller   ipc/shm.c: add RS...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
   * Calculate and add used RSS and swap pages of a shm.
   * Called with shm_ids.rw_mutex held as a reader
   */
  static void shm_add_rss_swap(struct shmid_kernel *shp,
  	unsigned long *rss_add, unsigned long *swp_add)
  {
  	struct inode *inode;
  
  	inode = shp->shm_file->f_path.dentry->d_inode;
  
  	if (is_file_hugepages(shp->shm_file)) {
  		struct address_space *mapping = inode->i_mapping;
  		struct hstate *h = hstate_file(shp->shm_file);
  		*rss_add += pages_per_huge_page(h) * mapping->nrpages;
  	} else {
  #ifdef CONFIG_SHMEM
  		struct shmem_inode_info *info = SHMEM_I(inode);
  		spin_lock(&info->lock);
  		*rss_add += inode->i_mapping->nrpages;
  		*swp_add += info->swapped;
  		spin_unlock(&info->lock);
  #else
  		*rss_add += inode->i_mapping->nrpages;
  #endif
  	}
  }
  
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
647
   * Called with shm_ids.rw_mutex held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
648
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
649
650
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
652
653
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
657
658
659
  	in_use = shm_ids(ns).in_use;
  
  	for (total = 0, next_id = 0; total < in_use; next_id++) {
e562aebc6   Tony Battersby   ipc: make shm_get...
660
  		struct kern_ipc_perm *ipc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  		struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662

e562aebc6   Tony Battersby   ipc: make shm_get...
663
664
  		ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
  		if (ipc == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  			continue;
e562aebc6   Tony Battersby   ipc: make shm_get...
666
  		shp = container_of(ipc, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667

b79521807   Helge Deller   ipc/shm.c: add RS...
668
  		shm_add_rss_swap(shp, rss, swp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
669
670
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
673
674
675
676
677
678
679
  /*
   * This function handles some shmctl commands which require the rw_mutex
   * to be held in write mode.
   * NOTE: no locks must be held, the rw_mutex is taken inside this function.
   */
  static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
  		       struct shmid_ds __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
681
  	struct kern_ipc_perm *ipcp;
016d7132f   Pierre Peiffer   IPC: get rid of t...
682
  	struct shmid64_ds shmid64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
684
685
686
  	int err;
  
  	if (cmd == IPC_SET) {
016d7132f   Pierre Peiffer   IPC: get rid of t...
687
  		if (copy_shmid_from_user(&shmid64, buf, version))
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
688
689
  			return -EFAULT;
  	}
b0e77598f   Serge E. Hallyn   userns: user name...
690
691
  	ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
  			       &shmid64.shm_perm, 0);
a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
692
693
  	if (IS_ERR(ipcp))
  		return PTR_ERR(ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
694

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
695
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
696
697
698
699
700
701
702
703
704
  
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
  		goto out_unlock;
  	switch (cmd) {
  	case IPC_RMID:
  		do_shm_rmid(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
8f4a3809c   Pierre Peiffer   IPC: introduce ip...
705
  		ipc_update_perm(&shmid64.shm_perm, ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
706
707
708
709
710
711
712
713
714
715
716
  		shp->shm_ctim = get_seconds();
  		break;
  	default:
  		err = -EINVAL;
  	}
  out_unlock:
  	shm_unlock(shp);
  out_up:
  	up_write(&shm_ids(ns).rw_mutex);
  	return err;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
717
  SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
718
719
  {
  	struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  	int err, version;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
721
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
727
728
  
  	if (cmd < 0 || shmid < 0) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	version = ipc_parse_version(&cmd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
729
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
732
733
734
735
736
737
738
  
  	switch (cmd) { /* replace with proc interface ? */
  	case IPC_INFO:
  	{
  		struct shminfo64 shminfo;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
e8148f758   WANG Cong   ipc: clean up ipc...
739
  		memset(&shminfo, 0, sizeof(shminfo));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
740
741
742
  		shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
  		shminfo.shmmax = ns->shm_ctlmax;
  		shminfo.shmall = ns->shm_ctlall;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
f4566f048   Nadia Derbey   ipc: fix wrong co...
747

3e148c799   Nadia Derbey   fix idr_find() lo...
748
  		down_read(&shm_ids(ns).rw_mutex);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
749
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
750
  		up_read(&shm_ids(ns).rw_mutex);
f4566f048   Nadia Derbey   ipc: fix wrong co...
751

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
757
758
759
760
761
762
  		if(err<0)
  			err = 0;
  		goto out;
  	}
  	case SHM_INFO:
  	{
  		struct shm_info shm_info;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
e8148f758   WANG Cong   ipc: clean up ipc...
763
  		memset(&shm_info, 0, sizeof(shm_info));
3e148c799   Nadia Derbey   fix idr_find() lo...
764
  		down_read(&shm_ids(ns).rw_mutex);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
765
766
767
  		shm_info.used_ids = shm_ids(ns).in_use;
  		shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
  		shm_info.shm_tot = ns->shm_tot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
770
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
771
  		up_read(&shm_ids(ns).rw_mutex);
e8148f758   WANG Cong   ipc: clean up ipc...
772
  		if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
776
777
778
779
780
781
782
783
784
  			err = -EFAULT;
  			goto out;
  		}
  
  		err = err < 0 ? 0 : err;
  		goto out;
  	}
  	case SHM_STAT:
  	case IPC_STAT:
  	{
  		struct shmid64_ds tbuf;
  		int result;
023a53557   Nadia Derbey   ipc: integrate ip...
785

023a53557   Nadia Derbey   ipc: integrate ip...
786
787
788
789
790
791
  		if (cmd == SHM_STAT) {
  			shp = shm_lock(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
792
  			result = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  		} else {
023a53557   Nadia Derbey   ipc: integrate ip...
794
795
796
797
798
  			shp = shm_lock_check(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  			result = 0;
  		}
e8148f758   WANG Cong   ipc: clean up ipc...
801
  		err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
802
  		if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
  			goto out_unlock;
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
807
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
  		kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
  		tbuf.shm_segsz	= shp->shm_segsz;
  		tbuf.shm_atime	= shp->shm_atim;
  		tbuf.shm_dtime	= shp->shm_dtim;
  		tbuf.shm_ctime	= shp->shm_ctim;
  		tbuf.shm_cpid	= shp->shm_cprid;
  		tbuf.shm_lpid	= shp->shm_lprid;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
815
  		tbuf.shm_nattch	= shp->shm_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
821
822
823
824
825
  		shm_unlock(shp);
  		if(copy_shmid_to_user (buf, &tbuf, version))
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
826
827
828
  		struct file *uninitialized_var(shm_file);
  
  		lru_add_drain_all();  /* drain pagevecs to lru lists */
023a53557   Nadia Derbey   ipc: integrate ip...
829
830
831
  		shp = shm_lock_check(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834

a33e67510   Al Viro   sanitize audit_ip...
835
  		audit_ipc_obj(&(shp->shm_perm));
073115d6b   Steve Grubb   [PATCH] Rework of...
836

b0e77598f   Serge E. Hallyn   userns: user name...
837
  		if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
414c0708d   David Howells   CRED: Wrap task c...
838
  			uid_t euid = current_euid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  			err = -EPERM;
414c0708d   David Howells   CRED: Wrap task c...
840
841
  			if (euid != shp->shm_perm.uid &&
  			    euid != shp->shm_perm.cuid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
  				goto out_unlock;
f1eb1332b   Jiri Slaby   ipc: use rlimit h...
843
  			if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
846
847
848
849
850
851
  				goto out_unlock;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
  		
  		if(cmd==SHM_LOCK) {
86a264abe   David Howells   CRED: Wrap curren...
852
  			struct user_struct *user = current_user();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
  			if (!is_file_hugepages(shp->shm_file)) {
  				err = shmem_lock(shp->shm_file, 1, user);
7be77e20d   Pavel Emelianov   Fix user struct l...
855
  				if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
856
  					shp->shm_perm.mode |= SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
860
861
  					shp->mlock_user = user;
  				}
  			}
  		} else if (!is_file_hugepages(shp->shm_file)) {
  			shmem_lock(shp->shm_file, 0, shp->mlock_user);
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
862
  			shp->shm_perm.mode &= ~SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
866
867
868
  			shp->mlock_user = NULL;
  		}
  		shm_unlock(shp);
  		goto out;
  	}
  	case IPC_RMID:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  	case IPC_SET:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
870
871
  		err = shmctl_down(ns, shmid, cmd, buf, version);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
873
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  out_unlock:
  	shm_unlock(shp);
  out:
  	return err;
  }
  
  /*
   * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
   *
   * NOTE! Despite the name, this is NOT a direct system call entrypoint. The
   * "raddr" thing points to kernel space, and there has to be a wrapper around
   * this.
   */
  long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
  {
  	struct shmid_kernel *shp;
  	unsigned long addr;
  	unsigned long size;
  	struct file * file;
  	int    err;
  	unsigned long flags;
  	unsigned long prot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  	int acc_mode;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
898
  	unsigned long user_addr;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
899
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
900
901
  	struct shm_file_data *sfd;
  	struct path path;
aeb5d7270   Al Viro   [PATCH] introduce...
902
  	fmode_t f_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
904
905
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
907
  	else if ((addr = (ulong)shmaddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
913
914
  		if (addr & (SHMLBA-1)) {
  			if (shmflg & SHM_RND)
  				addr &= ~(SHMLBA-1);	   /* round down */
  			else
  #ifndef __ARCH_FORCE_SHMLBA
  				if (addr & ~PAGE_MASK)
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
915
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
920
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
923
924
925
926
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
928
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
932
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
936
937
938
939
940
941
942
  	}
  	if (shmflg & SHM_EXEC) {
  		prot |= PROT_EXEC;
  		acc_mode |= S_IXUGO;
  	}
  
  	/*
  	 * We cannot rely on the fs check since SYSV IPC does have an
  	 * additional creator id...
  	 */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
943
  	ns = current->nsproxy->ipc_ns;
023a53557   Nadia Derbey   ipc: integrate ip...
944
945
946
  	shp = shm_lock_check(ns, shmid);
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  		goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
948
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
949
950
  
  	err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
951
  	if (ipcperms(ns, &shp->shm_perm, acc_mode))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
952
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
955
956
  	if (err)
  		goto out_unlock;
2c48b9c45   Al Viro   switch alloc_file...
957
958
  	path = shp->shm_file->f_path;
  	path_get(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
960
  	size = i_size_read(path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
  	shm_unlock(shp);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
962
963
964
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  	if (!sfd)
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
965
  		goto out_put_dentry;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
966

2c48b9c45   Al Viro   switch alloc_file...
967
968
  	file = alloc_file(&path, f_mode,
  			  is_file_hugepages(shp->shm_file) ?
c4caa7781   Al Viro   file ->get_unmapp...
969
970
  				&shm_file_operations_huge :
  				&shm_file_operations);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
971
972
  	if (!file)
  		goto out_free;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
973
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
974
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
975
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
976
977
978
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
981
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
985
986
987
988
989
990
991
992
  		if (find_vma_intersection(current->mm, addr, addr + size))
  			goto invalid;
  		/*
  		 * If shm segment goes below stack, make sure there is some
  		 * space left for the stack to grow (at least 4 pages).
  		 */
  		if (addr < current->mm->start_stack &&
  		    addr > current->mm->start_stack - size - PAGE_SIZE * 5)
  			goto invalid;
  	}
  		
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
993
994
995
996
997
  	user_addr = do_mmap (file, addr, size, prot, flags, 0);
  	*raddr = user_addr;
  	err = 0;
  	if (IS_ERR_VALUE(user_addr))
  		err = (long)user_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
  invalid:
  	up_write(&current->mm->mmap_sem);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1000
1001
1002
  	fput(file);
  
  out_nattch:
3e148c799   Nadia Derbey   fix idr_find() lo...
1003
  	down_write(&shm_ids(ns).rw_mutex);
00c2bf85d   Nadia Derbey   ipc: get rid of i...
1004
  	shp = shm_lock(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
1005
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
1007
  	if (shm_may_destroy(ns, shp))
4e9823111   Kirill Korotaev   [PATCH] IPC names...
1008
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
1011
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
  out:
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1015
1016
1017
1018
1019
1020
1021
  
  out_unlock:
  	shm_unlock(shp);
  	goto out;
  
  out_free:
  	kfree(sfd);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
1022
  out_put_dentry:
2c48b9c45   Al Viro   switch alloc_file...
1023
  	path_put(&path);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1024
  	goto out_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1026
  SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  {
  	unsigned long ret;
  	long err;
  
  	err = do_shmat(shmid, shmaddr, shmflg, &ret);
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1041
  SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
  {
  	struct mm_struct *mm = current->mm;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1044
  	struct vm_area_struct *vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
  	unsigned long addr = (unsigned long)shmaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
  	int retval = -EINVAL;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1047
1048
1049
1050
  #ifdef CONFIG_MMU
  	loff_t size = 0;
  	struct vm_area_struct *next;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051

df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
1052
1053
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  	down_write(&mm->mmap_sem);
  
  	/*
  	 * This function tries to be smart and unmap shm segments that
  	 * were modified by partial mlock or munmap calls:
  	 * - It first determines the size of the shm segment that should be
  	 *   unmapped: It searches for a vma that is backed by shm and that
  	 *   started at address shmaddr. It records it's size and then unmaps
  	 *   it.
  	 * - Then it unmaps all shm vmas that started at shmaddr and that
  	 *   are within the initially determined size.
  	 * Errors from do_munmap are ignored: the function only fails if
  	 * it's called with invalid parameters or if it's called to unmap
  	 * a part of a vma. Both calls in this function are for full vmas,
  	 * the parameters are directly copied from the vma itself and always
  	 * valid - therefore do_munmap cannot fail. (famous last words?)
  	 */
  	/*
  	 * If it had been mremap()'d, the starting address would not
  	 * match the usual checks anyway. So assume all vma's are
  	 * above the starting address given.
  	 */
  	vma = find_vma(mm, addr);
8feae1311   David Howells   NOMMU: Make VMAs ...
1077
  #ifdef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
1081
1082
1083
1084
1085
  	while (vma) {
  		next = vma->vm_next;
  
  		/*
  		 * Check if the starting address would match, i.e. it's
  		 * a fragment created by mprotect() and/or munmap(), or it
  		 * otherwise it starts at this address with no hassles.
  		 */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1086
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
6d63079ad   Josef Sipek   [PATCH] struct pa...
1088
  			size = vma->vm_file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  			/*
  			 * We discovered the size of the shm segment, so
  			 * break out of here and fall through to the next
  			 * loop that uses the size information to stop
  			 * searching for matching vma's.
  			 */
  			retval = 0;
  			vma = next;
  			break;
  		}
  		vma = next;
  	}
  
  	/*
  	 * We need look no further than the maximum address a fragment
  	 * could possibly have landed at. Also cast things to loff_t to
25985edce   Lucas De Marchi   Fix common misspe...
1106
  	 * prevent overflows and make comparisons vs. equal-width types.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
1108
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
1110
1111
1112
  	while (vma && (loff_t)(vma->vm_end - addr) <= size) {
  		next = vma->vm_next;
  
  		/* finding a matching vma now does not alter retval */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1113
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
1116
1117
1118
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
  
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		vma = next;
  	}
8feae1311   David Howells   NOMMU: Make VMAs ...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  #else /* CONFIG_MMU */
  	/* under NOMMU conditions, the exact address to be destroyed must be
  	 * given */
  	retval = -EINVAL;
  	if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
  		do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		retval = 0;
  	}
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
1132
1133
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1134
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1136
  	struct shmid_kernel *shp = it;
b79521807   Helge Deller   ipc/shm.c: add RS...
1137
1138
1139
  	unsigned long rss = 0, swp = 0;
  
  	shm_add_rss_swap(shp, &rss, &swp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140

6c826818f   Paul Menage   /proc/sysvipc/shm...
1141
1142
1143
1144
1145
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146

6c826818f   Paul Menage   /proc/sysvipc/shm...
1147
1148
  	return seq_printf(s,
  			  "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
b79521807   Helge Deller   ipc/shm.c: add RS...
1149
1150
1151
  			  "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
  			  SIZE_SPEC " " SIZE_SPEC "
  ",
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1152
  			  shp->shm_perm.key,
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1153
  			  shp->shm_perm.id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1154
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1155
1156
1157
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1158
  			  shp->shm_nattch,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1159
1160
1161
1162
1163
1164
  			  shp->shm_perm.uid,
  			  shp->shm_perm.gid,
  			  shp->shm_perm.cuid,
  			  shp->shm_perm.cgid,
  			  shp->shm_atim,
  			  shp->shm_dtim,
b79521807   Helge Deller   ipc/shm.c: add RS...
1165
1166
1167
  			  shp->shm_ctim,
  			  rss * PAGE_SIZE,
  			  swp * PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
  }
  #endif