Blame view

ipc/shm.c 25.9 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>
5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
37
  #include <linux/mutex.h>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
38
  #include <linux/nsproxy.h>
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
39
  #include <linux/mount.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
40

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  #include <asm/uaccess.h>
  
  #include "util.h"
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
44
45
46
47
48
49
50
51
  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...
52
  static const struct file_operations shm_file_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  static struct vm_operations_struct shm_vm_ops;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
54
55
56
  static struct ipc_ids init_shm_ids;
  
  #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
60
61
62
63
64
65
  #define shm_lock(ns, id)		\
  	((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id))
  #define shm_unlock(shp)			\
  	ipc_unlock(&(shp)->shm_perm)
  #define shm_get(ns, id)			\
  	((struct shmid_kernel*)ipc_get(&shm_ids(ns),id))
  #define shm_buildid(ns, id, seq)	\
  	ipc_buildid(&shm_ids(ns), id, seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

4e9823111   Kirill Korotaev   [PATCH] IPC names...
67
68
  static int newseg (struct ipc_namespace *ns, key_t key,
  		int shmflg, size_t size);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
69
70
  static void shm_open(struct vm_area_struct *vma);
  static void shm_close(struct vm_area_struct *vma);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
71
  static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
73
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  #endif
7d69a1f4a   Cedric Le Goater   remove CONFIG_UTS...
75
  static void __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  {
  	ns->ids[IPC_SHM_IDS] = ids;
  	ns->shm_ctlmax = SHMMAX;
  	ns->shm_ctlall = SHMALL;
  	ns->shm_ctlmni = SHMMNI;
  	ns->shm_tot = 0;
  	ipc_init_ids(ids, 1);
  }
  
  static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
  {
  	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);
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
95
96
97
98
99
100
101
  int shm_init_ns(struct ipc_namespace *ns)
  {
  	struct ipc_ids *ids;
  
  	ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
  	if (ids == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102

4e9823111   Kirill Korotaev   [PATCH] IPC names...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	__shm_init_ns(ns, ids);
  	return 0;
  }
  
  void shm_exit_ns(struct ipc_namespace *ns)
  {
  	int i;
  	struct shmid_kernel *shp;
  
  	mutex_lock(&shm_ids(ns).mutex);
  	for (i = 0; i <= shm_ids(ns).max_id; i++) {
  		shp = shm_lock(ns, i);
  		if (shp == NULL)
  			continue;
  
  		do_shm_rmid(ns, shp);
  	}
  	mutex_unlock(&shm_ids(ns).mutex);
c7e12b838   Pavel Emelianov   [PATCH] Fix ipc e...
121
  	ipc_fini_ids(ns->ids[IPC_SHM_IDS]);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
122
123
124
  	kfree(ns->ids[IPC_SHM_IDS]);
  	ns->ids[IPC_SHM_IDS] = NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
  
  void __init shm_init (void)
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
128
  	__shm_init_ns(&init_ipc_ns, &init_shm_ids);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
129
130
131
  	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...
132
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
134
135
  static inline int shm_checkid(struct ipc_namespace *ns,
  		struct shmid_kernel *s, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
137
  	if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
  		return -EIDRM;
  	return 0;
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
141
  static inline struct shmid_kernel *shm_rmid(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
143
  	return (struct shmid_kernel *)ipc_rmid(&shm_ids(ns), id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
145
  static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
147
  	return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
149
150
  /* 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...
151
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
152
153
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
155
  	shp = shm_lock(sfd->ns, sfd->id);
9ba025f10   Eric Sesterhenn   BUG_ON() Conversi...
156
  	BUG_ON(!shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
  	shp->shm_atim = get_seconds();
  	shp->shm_lprid = current->tgid;
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
  /*
   * shm_destroy - free the struct shmid_kernel
   *
   * @shp: struct to free
   *
5f921ae96   Ingo Molnar   [PATCH] sem2mutex...
167
   * It has to be called with shp and shm_ids.mutex locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
170
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
172
173
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
  	shm_rmid(ns, shp->id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
  	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...
178
  		user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
  						shp->mlock_user);
  	fput (shp->shm_file);
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  }
  
  /*
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
186
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
   * 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...
191
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
193
194
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
196
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
197
198
  
  	mutex_lock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  	/* remove from the list of attaches of the shm segment */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
200
  	shp = shm_lock(ns, sfd->id);
9ba025f10   Eric Sesterhenn   BUG_ON() Conversi...
201
  	BUG_ON(!shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
  	shp->shm_lprid = current->tgid;
  	shp->shm_dtim = get_seconds();
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
206
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
207
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  	else
  		shm_unlock(shp);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
210
  	mutex_unlock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
212
  static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
213
214
215
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
d0217ac04   Nick Piggin   mm: fault feedbac...
216
  	return sfd->vm_ops->fault(vma, vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  }
  
  #ifdef CONFIG_NUMA
  int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
  {
  	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;
  }
  
  struct mempolicy *shm_get_policy(struct vm_area_struct *vma, unsigned long addr)
  {
  	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);
22741925d   Adam Litke   hugetlb: fix get_...
238
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
239
  		pol = vma->vm_policy;
22741925d   Adam Litke   hugetlb: fix get_...
240
241
  	else
  		pol = current->mempolicy;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
242
243
244
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
247
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
248
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
249
250
251
252
  	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...
253
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
254
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
255
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
256
257
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
258
259
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
261
262
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
263
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
264

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
265
266
267
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
268
269
  	return 0;
  }
516dffdcd   Adam Litke   [PATCH] Fix get_u...
270
271
272
273
274
275
276
277
278
279
280
  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...
281
282
283
284
285
  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...
286
287
288
289
290
291
292
293
294
295
296
297
298
  	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...
299
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
300

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
301
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
302
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
303
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
304
  	.release	= shm_release,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
305
  	.get_unmapped_area	= shm_get_unmapped_area,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
  };
  
  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...
311
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
312
313
314
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  #endif
  };
4e9823111   Kirill Korotaev   [PATCH] IPC names...
317
  static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
  {
  	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...
325
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
327
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
335
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
  	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...
344
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  	if (shmflg & SHM_HUGETLB) {
9d66586f7   Eric W. Biederman   shm: fix the file...
346
347
  		/* hugetlb_file_setup takes care of mlock user accounting */
  		file = hugetlb_file_setup(name, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
  		shp->mlock_user = current->user;
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
350
351
352
353
354
355
356
357
  		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...
358
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
  
  	error = -ENOSPC;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
365
  	id = shm_addid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
373
374
  	if(id == -1) 
  		goto no_id;
  
  	shp->shm_cprid = current->tgid;
  	shp->shm_lprid = 0;
  	shp->shm_atim = shp->shm_dtim = 0;
  	shp->shm_ctim = get_seconds();
  	shp->shm_segsz = size;
  	shp->shm_nattch = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
375
  	shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	shp->shm_file = file;
30475cc12   Badari Pulavarty   Restore shmid as ...
377
378
379
380
381
  	/*
  	 * shmid gets reported as "inode#" in /proc/pid/maps.
  	 * proc-ps tools use this. Changing this will break them.
  	 */
  	file->f_dentry->d_inode->i_ino = shp->id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
382

4e9823111   Kirill Korotaev   [PATCH] IPC names...
383
  	ns->shm_tot += numpages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  	shm_unlock(shp);
  	return shp->id;
  
  no_id:
  	fput(file);
  no_file:
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  	return error;
  }
  
  asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
  {
  	struct shmid_kernel *shp;
  	int err, id = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
399
400
401
  	struct ipc_namespace *ns;
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

4e9823111   Kirill Korotaev   [PATCH] IPC names...
403
  	mutex_lock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  	if (key == IPC_PRIVATE) {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
405
406
  		err = newseg(ns, key, shmflg, size);
  	} else if ((id = ipc_findkey(&shm_ids(ns), key)) == -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  		if (!(shmflg & IPC_CREAT))
  			err = -ENOENT;
  		else
4e9823111   Kirill Korotaev   [PATCH] IPC names...
410
  			err = newseg(ns, key, shmflg, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  	} else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
  		err = -EEXIST;
  	} else {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
414
  		shp = shm_lock(ns, id);
9ba025f10   Eric Sesterhenn   BUG_ON() Conversi...
415
  		BUG_ON(shp==NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
420
  		if (shp->shm_segsz < size)
  			err = -EINVAL;
  		else if (ipcperms(&shp->shm_perm, shmflg))
  			err = -EACCES;
  		else {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
421
  			int shmid = shm_buildid(ns, id, shp->shm_perm.seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
427
  			err = security_shm_associate(shp, shmflg);
  			if (!err)
  				err = shmid;
  		}
  		shm_unlock(shp);
  	}
4e9823111   Kirill Korotaev   [PATCH] IPC names...
428
  	mutex_unlock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
436
437
438
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
465
466
467
468
469
470
471
472
473
474
475
  
  	return err;
  }
  
  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;
  	}
  }
  
  struct shm_setbuf {
  	uid_t	uid;
  	gid_t	gid;
  	mode_t	mode;
  };	
  
  static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version)
  {
  	switch(version) {
  	case IPC_64:
  	    {
  		struct shmid64_ds tbuf;
  
  		if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
  			return -EFAULT;
  
  		out->uid	= tbuf.shm_perm.uid;
  		out->gid	= tbuf.shm_perm.gid;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
476
  		out->mode	= tbuf.shm_perm.mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
  
  		return 0;
  	    }
  	case IPC_OLD:
  	    {
  		struct shmid_ds tbuf_old;
  
  		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
  			return -EFAULT;
  
  		out->uid	= tbuf_old.shm_perm.uid;
  		out->gid	= tbuf_old.shm_perm.gid;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
489
  		out->mode	= tbuf_old.shm_perm.mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
515
516
517
518
519
520
521
522
  
  		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;
  	}
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
523
524
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
  {
  	int i;
  
  	*rss = 0;
  	*swp = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
530
  	for (i = 0; i <= shm_ids(ns).max_id; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
  		struct shmid_kernel *shp;
  		struct inode *inode;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
533
  		shp = shm_get(ns, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
  		if(!shp)
  			continue;
6d63079ad   Josef Sipek   [PATCH] struct pa...
536
  		inode = shp->shm_file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  
  		if (is_file_hugepages(shp->shm_file)) {
  			struct address_space *mapping = inode->i_mapping;
  			*rss += (HPAGE_SIZE/PAGE_SIZE)*mapping->nrpages;
  		} 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);
  		}
  	}
  }
  
  asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
  {
  	struct shm_setbuf setbuf;
  	struct shmid_kernel *shp;
  	int err, version;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
556
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
559
560
561
562
563
  
  	if (cmd < 0 || shmid < 0) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	version = ipc_parse_version(&cmd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
564
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
572
573
574
575
  
  	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...
576
577
578
  		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
579
580
581
582
583
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
  		/* reading a integer is always atomic */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
584
  		err= shm_ids(ns).max_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
  		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));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
598
599
600
601
  		mutex_lock(&shm_ids(ns).mutex);
  		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
602
603
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
604
605
  		err = shm_ids(ns).max_id;
  		mutex_unlock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  		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;
  		memset(&tbuf, 0, sizeof(tbuf));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
620
  		shp = shm_lock(ns, shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
  		if(shp==NULL) {
  			err = -EINVAL;
  			goto out;
  		} else if(cmd==SHM_STAT) {
  			err = -EINVAL;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
626
  			if (shmid > shm_ids(ns).max_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
  				goto out_unlock;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
628
  			result = shm_buildid(ns, shmid, shp->shm_perm.seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  		} else {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
630
  			err = shm_checkid(ns, shp,shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  			if(err)
  				goto out_unlock;
  			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;
  		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...
648
  		tbuf.shm_nattch	= shp->shm_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
656
657
658
  		shm_unlock(shp);
  		if(copy_shmid_to_user (buf, &tbuf, version))
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
4e9823111   Kirill Korotaev   [PATCH] IPC names...
659
  		shp = shm_lock(ns, shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
663
  		if(shp==NULL) {
  			err = -EINVAL;
  			goto out;
  		}
4e9823111   Kirill Korotaev   [PATCH] IPC names...
664
  		err = shm_checkid(ns, shp,shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  		if(err)
  			goto out_unlock;
073115d6b   Steve Grubb   [PATCH] Rework of...
667
668
669
  		err = audit_ipc_obj(&(shp->shm_perm));
  		if (err)
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  		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...
688
  				if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
689
  					shp->shm_perm.mode |= SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
693
694
  					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...
695
  			shp->shm_perm.mode &= ~SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  			shp->mlock_user = NULL;
  		}
  		shm_unlock(shp);
  		goto out;
  	}
  	case IPC_RMID:
  	{
  		/*
  		 *	We cannot simply remove the file. The SVID states
  		 *	that the block remains until the last person
  		 *	detaches from it, then is deleted. A shmat() on
  		 *	an RMID segment is legal in older Linux and if 
  		 *	we change it apps break...
  		 *
  		 *	Instead we set a destroyed flag, and then blow
  		 *	the name away when the usage hits zero.
  		 */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
713
714
  		mutex_lock(&shm_ids(ns).mutex);
  		shp = shm_lock(ns, shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  		err = -EINVAL;
  		if (shp == NULL) 
  			goto out_up;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
718
  		err = shm_checkid(ns, shp, shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
  		if(err)
  			goto out_unlock_up;
073115d6b   Steve Grubb   [PATCH] Rework of...
721
722
723
  		err = audit_ipc_obj(&(shp->shm_perm));
  		if (err)
  			goto out_unlock_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
727
728
729
730
731
732
733
  		if (current->euid != shp->shm_perm.uid &&
  		    current->euid != shp->shm_perm.cuid && 
  		    !capable(CAP_SYS_ADMIN)) {
  			err=-EPERM;
  			goto out_unlock_up;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock_up;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
734
735
  		do_shm_rmid(ns, shp);
  		mutex_unlock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
741
742
743
744
  		goto out;
  	}
  
  	case IPC_SET:
  	{
  		if (copy_shmid_from_user (&setbuf, buf, version)) {
  			err = -EFAULT;
  			goto out;
  		}
4e9823111   Kirill Korotaev   [PATCH] IPC names...
745
746
  		mutex_lock(&shm_ids(ns).mutex);
  		shp = shm_lock(ns, shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
  		err=-EINVAL;
  		if(shp==NULL)
  			goto out_up;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
750
  		err = shm_checkid(ns, shp,shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
  		if(err)
  			goto out_unlock_up;
073115d6b   Steve Grubb   [PATCH] Rework of...
753
754
755
  		err = audit_ipc_obj(&(shp->shm_perm));
  		if (err)
  			goto out_unlock_up;
ac03221a4   Linda Knippers   [PATCH] update of...
756
  		err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
073115d6b   Steve Grubb   [PATCH] Rework of...
757
758
  		if (err)
  			goto out_unlock_up;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
763
764
765
766
767
768
769
770
771
  		err=-EPERM;
  		if (current->euid != shp->shm_perm.uid &&
  		    current->euid != shp->shm_perm.cuid && 
  		    !capable(CAP_SYS_ADMIN)) {
  			goto out_unlock_up;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock_up;
  		
  		shp->shm_perm.uid = setbuf.uid;
  		shp->shm_perm.gid = setbuf.gid;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
772
  		shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  			| (setbuf.mode & S_IRWXUGO);
  		shp->shm_ctim = get_seconds();
  		break;
  	}
  
  	default:
  		err = -EINVAL;
  		goto out;
  	}
  
  	err = 0;
  out_unlock_up:
  	shm_unlock(shp);
  out_up:
4e9823111   Kirill Korotaev   [PATCH] IPC names...
787
  	mutex_unlock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
  	goto out;
  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
811
  	int acc_mode;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
812
  	unsigned long user_addr;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
813
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
814
815
816
  	struct shm_file_data *sfd;
  	struct path path;
  	mode_t f_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
818
819
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
821
  	else if ((addr = (ulong)shmaddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
824
825
826
827
828
  		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...
829
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
831
832
833
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
834
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
839
840
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
842
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
846
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
849
850
851
852
853
854
855
856
  	}
  	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...
857
858
  	ns = current->nsproxy->ipc_ns;
  	shp = shm_lock(ns, shmid);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
859
  	if(shp == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
861

4e9823111   Kirill Korotaev   [PATCH] IPC names...
862
  	err = shm_checkid(ns, shp,shmid);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
863
864
865
866
867
868
  	if (err)
  		goto out_unlock;
  
  	err = -EACCES;
  	if (ipcperms(&shp->shm_perm, acc_mode))
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
871
872
873
874
875
  	if (err)
  		goto out_unlock;
  
  	path.dentry = dget(shp->shm_file->f_path.dentry);
  	path.mnt    = mntget(shp->shm_file->f_path.mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
877
  	size = i_size_read(path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	shm_unlock(shp);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  	if (!sfd)
  		goto out_put_path;
  
  	err = -ENOMEM;
  	file = get_empty_filp();
  	if (!file)
  		goto out_free;
  
  	file->f_op = &shm_file_operations;
  	file->private_data = sfd;
  	file->f_path = path;
  	file->f_mapping = shp->shm_file->f_mapping;
  	file->f_mode = f_mode;
  	sfd->id = shp->id;
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
900
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
902
903
904
905
906
907
908
909
910
911
  		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...
912
913
914
915
916
  	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
917
918
  invalid:
  	up_write(&current->mm->mmap_sem);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
919
920
921
  	fput(file);
  
  out_nattch:
4e9823111   Kirill Korotaev   [PATCH] IPC names...
922
923
  	mutex_lock(&shm_ids(ns).mutex);
  	shp = shm_lock(ns, shmid);
9ba025f10   Eric Sesterhenn   BUG_ON() Conversi...
924
  	BUG_ON(!shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
927
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
928
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
  	else
  		shm_unlock(shp);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
931
  	mutex_unlock(&shm_ids(ns).mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
  out:
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
935
936
937
938
939
940
941
942
943
944
945
  
  out_unlock:
  	shm_unlock(shp);
  	goto out;
  
  out_free:
  	kfree(sfd);
  out_put_path:
  	dput(path.dentry);
  	mntput(path.mnt);
  	goto out_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  }
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
947
948
949
950
951
952
953
954
955
956
957
  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
958
959
960
961
962
963
964
965
966
967
968
  /*
   * 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...
969
970
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
  	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...
1003
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
6d63079ad   Josef Sipek   [PATCH] struct pa...
1005
  			size = vma->vm_file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
  			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...
1025
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
1028
1029
  	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...
1030
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  			(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...
1042
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1044
1045
  	struct shmid_kernel *shp = it;
  	char *format;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
1049
1050
  #define SMALL_STRING "%10d %10d  %4o %10u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu
  "
  #define BIG_STRING   "%10d %10d  %4o %21u %5u %5u  %5d %5u %5u %5u %5u %10lu %10lu %10lu
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051

19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1052
1053
1054
1055
1056
1057
1058
  	if (sizeof(size_t) <= sizeof(int))
  		format = SMALL_STRING;
  	else
  		format = BIG_STRING;
  	return seq_printf(s, format,
  			  shp->shm_perm.key,
  			  shp->id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1059
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1060
1061
1062
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1063
  			  shp->shm_nattch,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1064
1065
1066
1067
1068
1069
1070
  			  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
1071
1072
  }
  #endif