Blame view

ipc/shm.c 25.5 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  static struct vm_operations_struct shm_vm_ops;
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
55
  #define shm_ids(ns)	((ns)->ids[IPC_SHM_IDS])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

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

7748dbfaa   Nadia Derbey   ipc: unify the sy...
60
  static int newseg(struct ipc_namespace *, struct ipc_params *);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
61
62
  static void shm_open(struct vm_area_struct *vma);
  static void shm_close(struct vm_area_struct *vma);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
63
  static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
65
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  #endif
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
67
  void shm_init_ns(struct ipc_namespace *ns)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
68
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
69
70
71
72
  	ns->shm_ctlmax = SHMMAX;
  	ns->shm_ctlall = SHMALL;
  	ns->shm_ctlmni = SHMMNI;
  	ns->shm_tot = 0;
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
73
  	ipc_init_ids(&ns->ids[IPC_SHM_IDS]);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
74
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
75
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
76
77
   * 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...
78
   */
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
79
  static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
80
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
81
82
  	struct shmid_kernel *shp;
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
83
84
85
86
87
88
89
90
  	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 ...
91
  #ifdef CONFIG_IPC_NS
4e9823111   Kirill Korotaev   [PATCH] IPC names...
92
93
  void shm_exit_ns(struct ipc_namespace *ns)
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
94
  	free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
95
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
96
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  
  void __init shm_init (void)
  {
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
100
  	shm_init_ns(&init_ipc_ns);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
101
102
103
  	ipc_init_proc_interface("sysvipc/shm",
  				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime
  ",
4e9823111   Kirill Korotaev   [PATCH] IPC names...
104
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  }
3e148c799   Nadia Derbey   fix idr_find() lo...
106
107
108
109
110
111
112
113
  /*
   * shm_lock_(check_)down routines are called in the paths where the rw_mutex
   * is held to protect access to the idr tree.
   */
  static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
  						int id)
  {
  	struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
114
115
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
3e148c799   Nadia Derbey   fix idr_find() lo...
116
117
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
  }
3e148c799   Nadia Derbey   fix idr_find() lo...
118
119
120
121
  /*
   * shm_lock_(check_) routines are called in the paths where the rw_mutex
   * is not held.
   */
023a53557   Nadia Derbey   ipc: integrate ip...
122
  static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  {
03f02c765   Nadia Derbey   Storing ipcs into...
124
  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
125
126
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
127
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
023a53557   Nadia Derbey   ipc: integrate ip...
128
129
130
131
132
  }
  
  static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
  						int id)
  {
03f02c765   Nadia Derbey   Storing ipcs into...
133
  	struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
134
135
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
136
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  }
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
138
  static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
140
  	ipc_rmid(&shm_ids(ns), &s->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
143
144
  /* 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...
145
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
146
147
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
149
  	shp = shm_lock(sfd->ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
150
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  	shp->shm_atim = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
152
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
159
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
   * @shp: struct to free
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
162
   * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
165
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
167
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
168
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
  	shm_unlock(shp);
  	if (!is_file_hugepages(shp->shm_file))
  		shmem_lock(shp->shm_file, 0, shp->mlock_user);
  	else
6d63079ad   Josef Sipek   [PATCH] struct pa...
173
  		user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
  						shp->mlock_user);
  	fput (shp->shm_file);
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  }
  
  /*
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
181
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
   * 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...
186
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
188
189
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
191
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
192

3e148c799   Nadia Derbey   fix idr_find() lo...
193
  	down_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  	/* remove from the list of attaches of the shm segment */
3e148c799   Nadia Derbey   fix idr_find() lo...
195
  	shp = shm_lock_down(ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
196
  	BUG_ON(IS_ERR(shp));
b488893a3   Pavel Emelyanov   pid namespaces: c...
197
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
  	shp->shm_dtim = get_seconds();
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
201
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
202
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
205
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
207
  static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
208
209
210
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
d0217ac04   Nick Piggin   mm: fault feedbac...
211
  	return sfd->vm_ops->fault(vma, vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
212
213
214
  }
  
  #ifdef CONFIG_NUMA
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
215
  static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
216
217
218
219
220
221
222
223
  {
  	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...
224
225
  static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
226
227
228
229
230
231
232
  {
  	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...
233
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
234
  		pol = vma->vm_policy;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
235

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
236
237
238
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
241
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
242
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
243
244
245
246
  	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...
247
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
248
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
249
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
250
251
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
252
253
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
255
256
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
257
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
258

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
259
260
261
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
262
263
  	return 0;
  }
516dffdcd   Adam Litke   [PATCH] Fix get_u...
264
265
266
267
268
269
270
271
272
273
274
  static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
  {
  	int (*fsync) (struct file *, struct dentry *, int datasync);
  	struct shm_file_data *sfd = shm_file_data(file);
  	int ret = -EINVAL;
  
  	fsync = sfd->file->f_op->fsync;
  	if (fsync)
  		ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
  	return ret;
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
275
276
277
278
279
  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);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
280
281
282
283
284
285
286
287
288
289
290
291
292
  	return get_unmapped_area(sfd->file, addr, len, pgoff, flags);
  }
  
  int is_file_shm_hugepages(struct file *file)
  {
  	int ret = 0;
  
  	if (file->f_op == &shm_file_operations) {
  		struct shm_file_data *sfd;
  		sfd = shm_file_data(file);
  		ret = is_file_hugepages(sfd->file);
  	}
  	return ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
293
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
294

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
295
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
296
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
297
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
298
  	.release	= shm_release,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
299
  	.get_unmapped_area	= shm_get_unmapped_area,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
  };
  
  static struct vm_operations_struct shm_vm_ops = {
  	.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...
305
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
306
307
308
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
311
312
313
314
315
  /**
   * 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...
316
   * Called with shm_ids.rw_mutex held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
317
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
318
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
320
321
322
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
328
  	int error;
  	struct shmid_kernel *shp;
  	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
  	struct file * file;
  	char name[13];
  	int id;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
329
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
331
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
339
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
  	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...
348
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  	if (shmflg & SHM_HUGETLB) {
9d66586f7   Eric W. Biederman   shm: fix the file...
350
351
  		/* hugetlb_file_setup takes care of mlock user accounting */
  		file = hugetlb_file_setup(name, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  		shp->mlock_user = current->user;
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
354
355
356
357
358
359
360
361
  		int acctflag = VM_ACCOUNT;
  		/*
  		 * Do not allow no accounting for OVERCOMMIT_NEVER, even
  	 	 * if it's asked for.
  		 */
  		if  ((shmflg & SHM_NORESERVE) &&
  				sysctl_overcommit_memory != OVERCOMMIT_NEVER)
  			acctflag = 0;
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
362
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
48dea404e   Pierre Peiffer   IPC: use ipc_buil...
367
  	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
283bb7fad   Pierre Peiffer   IPC: fix error ca...
368
369
  	if (id < 0) {
  		error = id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  		goto no_id;
283bb7fad   Pierre Peiffer   IPC: fix error ca...
371
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

b488893a3   Pavel Emelyanov   pid namespaces: c...
373
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
  	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
379
  	shp->shm_file = file;
30475cc12   Badari Pulavarty   Restore shmid as ...
380
381
382
383
  	/*
  	 * 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...
384
  	file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
385

4e9823111   Kirill Korotaev   [PATCH] IPC names...
386
  	ns->shm_tot += numpages;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
387
  	error = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  	shm_unlock(shp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
389
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
394
395
396
397
  
  no_id:
  	fput(file);
  no_file:
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
398
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
399
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
400
   */
03f02c765   Nadia Derbey   Storing ipcs into...
401
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
402
  {
03f02c765   Nadia Derbey   Storing ipcs into...
403
404
405
406
  	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...
407
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
408
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
409
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
410
   */
03f02c765   Nadia Derbey   Storing ipcs into...
411
412
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
413
  {
03f02c765   Nadia Derbey   Storing ipcs into...
414
415
416
417
  	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...
418
419
420
421
  		return -EINVAL;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
424
  	struct ipc_namespace *ns;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
425
426
  	struct ipc_ops shm_ops;
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
427
428
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

7748dbfaa   Nadia Derbey   ipc: unify the sy...
430
431
432
  	shm_ops.getnew = newseg;
  	shm_ops.associate = shm_security;
  	shm_ops.more_checks = shm_more_checks;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
433

7748dbfaa   Nadia Derbey   ipc: unify the sy...
434
435
436
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

7748dbfaa   Nadia Derbey   ipc: unify the sy...
438
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  }
  
  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;
  
  		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...
465
466
  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
467
468
469
  {
  	switch(version) {
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
470
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
478
  	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...
479
480
481
  		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
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  
  		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...
515
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
516
   * Called with shm_ids.rw_mutex held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
517
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
518
519
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
521
522
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
526
527
528
  	in_use = shm_ids(ns).in_use;
  
  	for (total = 0, next_id = 0; total < in_use; next_id++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
  		struct shmid_kernel *shp;
  		struct inode *inode;
637c36634   Nadia Derbey   ipc: remove the i...
531
  		shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
532
  		if (shp == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  			continue;
6d63079ad   Josef Sipek   [PATCH] struct pa...
534
  		inode = shp->shm_file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
  
  		if (is_file_hugepages(shp->shm_file)) {
  			struct address_space *mapping = inode->i_mapping;
a55164389   Andi Kleen   hugetlb: modular ...
538
539
  			struct hstate *h = hstate_file(shp->shm_file);
  			*rss += pages_per_huge_page(h) * mapping->nrpages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
  		} else {
  			struct shmem_inode_info *info = SHMEM_I(inode);
  			spin_lock(&info->lock);
  			*rss += inode->i_mapping->nrpages;
  			*swp += info->swapped;
  			spin_unlock(&info->lock);
  		}
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
547
548
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
551
552
553
554
555
556
557
  /*
   * 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
558
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
559
  	struct kern_ipc_perm *ipcp;
016d7132f   Pierre Peiffer   IPC: get rid of t...
560
  	struct shmid64_ds shmid64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
562
563
564
  	int err;
  
  	if (cmd == IPC_SET) {
016d7132f   Pierre Peiffer   IPC: get rid of t...
565
  		if (copy_shmid_from_user(&shmid64, buf, version))
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
566
567
  			return -EFAULT;
  	}
a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
568
569
570
  	ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0);
  	if (IS_ERR(ipcp))
  		return PTR_ERR(ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
571

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
572
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
573
574
575
576
577
578
579
580
581
  
  	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...
582
  		ipc_update_perm(&shmid64.shm_perm, ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
  		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;
  }
  
  asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
  {
  	struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  	int err, version;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
599
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
606
  
  	if (cmd < 0 || shmid < 0) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	version = ipc_parse_version(&cmd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
607
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
612
613
614
615
616
617
618
  
  	switch (cmd) { /* replace with proc interface ? */
  	case IPC_INFO:
  	{
  		struct shminfo64 shminfo;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
  
  		memset(&shminfo,0,sizeof(shminfo));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
619
620
621
  		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
622
623
624
625
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
f4566f048   Nadia Derbey   ipc: fix wrong co...
626

3e148c799   Nadia Derbey   fix idr_find() lo...
627
  		down_read(&shm_ids(ns).rw_mutex);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
628
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
629
  		up_read(&shm_ids(ns).rw_mutex);
f4566f048   Nadia Derbey   ipc: fix wrong co...
630

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
636
637
638
639
640
641
642
643
  		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;
  
  		memset(&shm_info,0,sizeof(shm_info));
3e148c799   Nadia Derbey   fix idr_find() lo...
644
  		down_read(&shm_ids(ns).rw_mutex);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
645
646
647
  		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
648
649
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
650
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
651
  		up_read(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
655
656
657
658
659
660
661
662
663
664
  		if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
  			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...
665
666
667
  
  		if (!buf) {
  			err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  			goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
669
670
671
672
673
674
675
676
  		}
  
  		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...
677
  			result = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  		} else {
023a53557   Nadia Derbey   ipc: integrate ip...
679
680
681
682
683
  			shp = shm_lock_check(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
689
690
691
  			result = 0;
  		}
  		err=-EACCES;
  		if (ipcperms (&shp->shm_perm, S_IRUGO))
  			goto out_unlock;
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
692
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
697
698
699
  		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...
700
  		tbuf.shm_nattch	= shp->shm_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
706
707
708
709
710
  		shm_unlock(shp);
  		if(copy_shmid_to_user (buf, &tbuf, version))
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
023a53557   Nadia Derbey   ipc: integrate ip...
711
712
713
  		shp = shm_lock_check(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716

073115d6b   Steve Grubb   [PATCH] Rework of...
717
718
719
  		err = audit_ipc_obj(&(shp->shm_perm));
  		if (err)
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  		if (!capable(CAP_IPC_LOCK)) {
  			err = -EPERM;
  			if (current->euid != shp->shm_perm.uid &&
  			    current->euid != shp->shm_perm.cuid)
  				goto out_unlock;
  			if (cmd == SHM_LOCK &&
  			    !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
  				goto out_unlock;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
  		
  		if(cmd==SHM_LOCK) {
  			struct user_struct * user = current->user;
  			if (!is_file_hugepages(shp->shm_file)) {
  				err = shmem_lock(shp->shm_file, 1, user);
7be77e20d   Pavel Emelianov   Fix user struct l...
738
  				if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
739
  					shp->shm_perm.mode |= SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
  					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...
745
  			shp->shm_perm.mode &= ~SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
751
  			shp->mlock_user = NULL;
  		}
  		shm_unlock(shp);
  		goto out;
  	}
  	case IPC_RMID:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  	case IPC_SET:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
753
754
  		err = shmctl_down(ns, shmid, cmd, buf, version);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
756
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
  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
780
  	int acc_mode;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
781
  	unsigned long user_addr;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
782
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
783
784
785
  	struct shm_file_data *sfd;
  	struct path path;
  	mode_t f_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
787
788
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
790
  	else if ((addr = (ulong)shmaddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
794
795
796
797
  		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...
798
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
802
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
803
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
809
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
811
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
815
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
819
820
821
822
823
824
825
  	}
  	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...
826
  	ns = current->nsproxy->ipc_ns;
023a53557   Nadia Derbey   ipc: integrate ip...
827
828
829
  	shp = shm_lock_check(ns, shmid);
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
  		goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
831
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
832
833
834
835
  
  	err = -EACCES;
  	if (ipcperms(&shp->shm_perm, acc_mode))
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
838
839
840
841
  	if (err)
  		goto out_unlock;
  
  	path.dentry = dget(shp->shm_file->f_path.dentry);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
842
  	path.mnt    = shp->shm_file->f_path.mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
844
  	size = i_size_read(path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  	shm_unlock(shp);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
846
847
848
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  	if (!sfd)
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
849
  		goto out_put_dentry;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
850

ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
851
  	file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
852
853
  	if (!file)
  		goto out_free;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
854
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
855
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
856
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
857
858
859
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
862
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
866
867
868
869
870
871
872
873
  		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...
874
875
876
877
878
  	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
879
880
  invalid:
  	up_write(&current->mm->mmap_sem);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
881
882
883
  	fput(file);
  
  out_nattch:
3e148c799   Nadia Derbey   fix idr_find() lo...
884
885
  	down_write(&shm_ids(ns).rw_mutex);
  	shp = shm_lock_down(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
886
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
888
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
889
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
890
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
893
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
  out:
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
897
898
899
900
901
902
903
  
  out_unlock:
  	shm_unlock(shp);
  	goto out;
  
  out_free:
  	kfree(sfd);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
904
  out_put_dentry:
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
905
  	dput(path.dentry);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
906
  	goto out_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
  }
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
908
909
910
911
912
913
914
915
916
917
918
  asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
  {
  	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
919
920
921
922
923
924
925
926
927
928
929
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
  asmlinkage long sys_shmdt(char __user *shmaddr)
  {
  	struct mm_struct *mm = current->mm;
  	struct vm_area_struct *vma, *next;
  	unsigned long addr = (unsigned long)shmaddr;
  	loff_t size = 0;
  	int retval = -EINVAL;
df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
930
931
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
  	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);
  
  	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...
964
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
6d63079ad   Josef Sipek   [PATCH] struct pa...
966
  			size = vma->vm_file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  			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
  	 * prevent overflows and make comparisions vs. equal-width types.
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
986
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
988
989
990
  	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...
991
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
993
994
995
996
997
998
999
1000
1001
1002
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
  
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		vma = next;
  	}
  
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1003
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1005
  	struct shmid_kernel *shp = it;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006

6c826818f   Paul Menage   /proc/sysvipc/shm...
1007
1008
1009
1010
1011
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012

6c826818f   Paul Menage   /proc/sysvipc/shm...
1013
1014
1015
1016
  	return seq_printf(s,
  			  "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
  			  "%5lu %5u %5u %5u %5u %10lu %10lu %10lu
  ",
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1017
  			  shp->shm_perm.key,
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1018
  			  shp->shm_perm.id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1019
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1020
1021
1022
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1023
  			  shp->shm_nattch,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1024
1025
1026
1027
1028
1029
1030
  			  shp->shm_perm.uid,
  			  shp->shm_perm.gid,
  			  shp->shm_perm.cuid,
  			  shp->shm_perm.cgid,
  			  shp->shm_atim,
  			  shp->shm_dtim,
  			  shp->shm_ctim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
  }
  #endif