aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2011-09-15 09:08:05 -0400
committerJiri Kosina <jkosina@suse.cz>2011-09-15 09:08:18 -0400
commite060c38434b2caa78efe7cedaff4191040b65a15 (patch)
tree407361230bf6733f63d8e788e4b5e6566ee04818 /ipc
parent10e4ac572eeffe5317019bd7330b6058a400dfc2 (diff)
parentcc39c6a9bbdebfcf1a7dee64d83bf302bc38d941 (diff)
Merge branch 'master' into for-next
Fast-forward merge with Linus to be able to merge patches based on more recent version of the tree.
Diffstat (limited to 'ipc')
-rw-r--r--ipc/ipc_sysctl.c36
-rw-r--r--ipc/mqueue.c125
-rw-r--r--ipc/shm.c117
3 files changed, 212 insertions, 66 deletions
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index 56410faa455..00fba2bab87 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -31,12 +31,37 @@ static int proc_ipc_dointvec(ctl_table *table, int write,
31 void __user *buffer, size_t *lenp, loff_t *ppos) 31 void __user *buffer, size_t *lenp, loff_t *ppos)
32{ 32{
33 struct ctl_table ipc_table; 33 struct ctl_table ipc_table;
34
34 memcpy(&ipc_table, table, sizeof(ipc_table)); 35 memcpy(&ipc_table, table, sizeof(ipc_table));
35 ipc_table.data = get_ipc(table); 36 ipc_table.data = get_ipc(table);
36 37
37 return proc_dointvec(&ipc_table, write, buffer, lenp, ppos); 38 return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
38} 39}
39 40
41static int proc_ipc_dointvec_minmax(ctl_table *table, int write,
42 void __user *buffer, size_t *lenp, loff_t *ppos)
43{
44 struct ctl_table ipc_table;
45
46 memcpy(&ipc_table, table, sizeof(ipc_table));
47 ipc_table.data = get_ipc(table);
48
49 return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
50}
51
52static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
53 void __user *buffer, size_t *lenp, loff_t *ppos)
54{
55 struct ipc_namespace *ns = current->nsproxy->ipc_ns;
56 int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
57
58 if (err < 0)
59 return err;
60 if (ns->shm_rmid_forced)
61 shm_destroy_orphaned(ns);
62 return err;
63}
64
40static int proc_ipc_callback_dointvec(ctl_table *table, int write, 65static int proc_ipc_callback_dointvec(ctl_table *table, int write,
41 void __user *buffer, size_t *lenp, loff_t *ppos) 66 void __user *buffer, size_t *lenp, loff_t *ppos)
42{ 67{
@@ -125,6 +150,8 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
125#else 150#else
126#define proc_ipc_doulongvec_minmax NULL 151#define proc_ipc_doulongvec_minmax NULL
127#define proc_ipc_dointvec NULL 152#define proc_ipc_dointvec NULL
153#define proc_ipc_dointvec_minmax NULL
154#define proc_ipc_dointvec_minmax_orphans NULL
128#define proc_ipc_callback_dointvec NULL 155#define proc_ipc_callback_dointvec NULL
129#define proc_ipcauto_dointvec_minmax NULL 156#define proc_ipcauto_dointvec_minmax NULL
130#endif 157#endif
@@ -155,6 +182,15 @@ static struct ctl_table ipc_kern_table[] = {
155 .proc_handler = proc_ipc_dointvec, 182 .proc_handler = proc_ipc_dointvec,
156 }, 183 },
157 { 184 {
185 .procname = "shm_rmid_forced",
186 .data = &init_ipc_ns.shm_rmid_forced,
187 .maxlen = sizeof(init_ipc_ns.shm_rmid_forced),
188 .mode = 0644,
189 .proc_handler = proc_ipc_dointvec_minmax_orphans,
190 .extra1 = &zero,
191 .extra2 = &one,
192 },
193 {
158 .procname = "msgmax", 194 .procname = "msgmax",
159 .data = &init_ipc_ns.msg_ctlmax, 195 .data = &init_ipc_ns.msg_ctlmax,
160 .maxlen = sizeof (init_ipc_ns.msg_ctlmax), 196 .maxlen = sizeof (init_ipc_ns.msg_ctlmax),
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 14fb6d67e6a..ed049ea568f 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -113,72 +113,75 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
113{ 113{
114 struct user_struct *u = current_user(); 114 struct user_struct *u = current_user();
115 struct inode *inode; 115 struct inode *inode;
116 int ret = -ENOMEM;
116 117
117 inode = new_inode(sb); 118 inode = new_inode(sb);
118 if (inode) { 119 if (!inode)
119 inode->i_ino = get_next_ino(); 120 goto err;
120 inode->i_mode = mode;
121 inode->i_uid = current_fsuid();
122 inode->i_gid = current_fsgid();
123 inode->i_mtime = inode->i_ctime = inode->i_atime =
124 CURRENT_TIME;
125 121
126 if (S_ISREG(mode)) { 122 inode->i_ino = get_next_ino();
127 struct mqueue_inode_info *info; 123 inode->i_mode = mode;
128 struct task_struct *p = current; 124 inode->i_uid = current_fsuid();
129 unsigned long mq_bytes, mq_msg_tblsz; 125 inode->i_gid = current_fsgid();
130 126 inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
131 inode->i_fop = &mqueue_file_operations; 127
132 inode->i_size = FILENT_SIZE; 128 if (S_ISREG(mode)) {
133 /* mqueue specific info */ 129 struct mqueue_inode_info *info;
134 info = MQUEUE_I(inode); 130 struct task_struct *p = current;
135 spin_lock_init(&info->lock); 131 unsigned long mq_bytes, mq_msg_tblsz;
136 init_waitqueue_head(&info->wait_q); 132
137 INIT_LIST_HEAD(&info->e_wait_q[0].list); 133 inode->i_fop = &mqueue_file_operations;
138 INIT_LIST_HEAD(&info->e_wait_q[1].list); 134 inode->i_size = FILENT_SIZE;
139 info->notify_owner = NULL; 135 /* mqueue specific info */
140 info->qsize = 0; 136 info = MQUEUE_I(inode);
141 info->user = NULL; /* set when all is ok */ 137 spin_lock_init(&info->lock);
142 memset(&info->attr, 0, sizeof(info->attr)); 138 init_waitqueue_head(&info->wait_q);
143 info->attr.mq_maxmsg = ipc_ns->mq_msg_max; 139 INIT_LIST_HEAD(&info->e_wait_q[0].list);
144 info->attr.mq_msgsize = ipc_ns->mq_msgsize_max; 140 INIT_LIST_HEAD(&info->e_wait_q[1].list);
145 if (attr) { 141 info->notify_owner = NULL;
146 info->attr.mq_maxmsg = attr->mq_maxmsg; 142 info->qsize = 0;
147 info->attr.mq_msgsize = attr->mq_msgsize; 143 info->user = NULL; /* set when all is ok */
148 } 144 memset(&info->attr, 0, sizeof(info->attr));
149 mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); 145 info->attr.mq_maxmsg = ipc_ns->mq_msg_max;
150 info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); 146 info->attr.mq_msgsize = ipc_ns->mq_msgsize_max;
151 if (!info->messages) 147 if (attr) {
152 goto out_inode; 148 info->attr.mq_maxmsg = attr->mq_maxmsg;
153 149 info->attr.mq_msgsize = attr->mq_msgsize;
154 mq_bytes = (mq_msg_tblsz + 150 }
155 (info->attr.mq_maxmsg * info->attr.mq_msgsize)); 151 mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
156 152 info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
157 spin_lock(&mq_lock); 153 if (!info->messages)
158 if (u->mq_bytes + mq_bytes < u->mq_bytes || 154 goto out_inode;
159 u->mq_bytes + mq_bytes >
160 task_rlimit(p, RLIMIT_MSGQUEUE)) {
161 spin_unlock(&mq_lock);
162 /* mqueue_evict_inode() releases info->messages */
163 goto out_inode;
164 }
165 u->mq_bytes += mq_bytes;
166 spin_unlock(&mq_lock);
167 155
168 /* all is ok */ 156 mq_bytes = (mq_msg_tblsz +
169 info->user = get_uid(u); 157 (info->attr.mq_maxmsg * info->attr.mq_msgsize));
170 } else if (S_ISDIR(mode)) { 158
171 inc_nlink(inode); 159 spin_lock(&mq_lock);
172 /* Some things misbehave if size == 0 on a directory */ 160 if (u->mq_bytes + mq_bytes < u->mq_bytes ||
173 inode->i_size = 2 * DIRENT_SIZE; 161 u->mq_bytes + mq_bytes > task_rlimit(p, RLIMIT_MSGQUEUE)) {
174 inode->i_op = &mqueue_dir_inode_operations; 162 spin_unlock(&mq_lock);
175 inode->i_fop = &simple_dir_operations; 163 /* mqueue_evict_inode() releases info->messages */
164 ret = -EMFILE;
165 goto out_inode;
176 } 166 }
167 u->mq_bytes += mq_bytes;
168 spin_unlock(&mq_lock);
169
170 /* all is ok */
171 info->user = get_uid(u);
172 } else if (S_ISDIR(mode)) {
173 inc_nlink(inode);
174 /* Some things misbehave if size == 0 on a directory */
175 inode->i_size = 2 * DIRENT_SIZE;
176 inode->i_op = &mqueue_dir_inode_operations;
177 inode->i_fop = &simple_dir_operations;
177 } 178 }
179
178 return inode; 180 return inode;
179out_inode: 181out_inode:
180 iput(inode); 182 iput(inode);
181 return NULL; 183err:
184 return ERR_PTR(ret);
182} 185}
183 186
184static int mqueue_fill_super(struct super_block *sb, void *data, int silent) 187static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
@@ -194,8 +197,8 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
194 197
195 inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, 198 inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO,
196 NULL); 199 NULL);
197 if (!inode) { 200 if (IS_ERR(inode)) {
198 error = -ENOMEM; 201 error = PTR_ERR(inode);
199 goto out; 202 goto out;
200 } 203 }
201 204
@@ -315,8 +318,8 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
315 spin_unlock(&mq_lock); 318 spin_unlock(&mq_lock);
316 319
317 inode = mqueue_get_inode(dir->i_sb, ipc_ns, mode, attr); 320 inode = mqueue_get_inode(dir->i_sb, ipc_ns, mode, attr);
318 if (!inode) { 321 if (IS_ERR(inode)) {
319 error = -ENOMEM; 322 error = PTR_ERR(inode);
320 spin_lock(&mq_lock); 323 spin_lock(&mq_lock);
321 ipc_ns->mq_queues_count--; 324 ipc_ns->mq_queues_count--;
322 goto out_unlock; 325 goto out_unlock;
diff --git a/ipc/shm.c b/ipc/shm.c
index 27884adb1a9..02ecf2c078f 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -74,6 +74,7 @@ void shm_init_ns(struct ipc_namespace *ns)
74 ns->shm_ctlmax = SHMMAX; 74 ns->shm_ctlmax = SHMMAX;
75 ns->shm_ctlall = SHMALL; 75 ns->shm_ctlall = SHMALL;
76 ns->shm_ctlmni = SHMMNI; 76 ns->shm_ctlmni = SHMMNI;
77 ns->shm_rmid_forced = 0;
77 ns->shm_tot = 0; 78 ns->shm_tot = 0;
78 ipc_init_ids(&shm_ids(ns)); 79 ipc_init_ids(&shm_ids(ns));
79} 80}
@@ -104,9 +105,16 @@ void shm_exit_ns(struct ipc_namespace *ns)
104} 105}
105#endif 106#endif
106 107
107void __init shm_init (void) 108static int __init ipc_ns_init(void)
108{ 109{
109 shm_init_ns(&init_ipc_ns); 110 shm_init_ns(&init_ipc_ns);
111 return 0;
112}
113
114pure_initcall(ipc_ns_init);
115
116void __init shm_init (void)
117{
110 ipc_init_proc_interface("sysvipc/shm", 118 ipc_init_proc_interface("sysvipc/shm",
111#if BITS_PER_LONG <= 32 119#if BITS_PER_LONG <= 32
112 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", 120 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
@@ -130,6 +138,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
130 return container_of(ipcp, struct shmid_kernel, shm_perm); 138 return container_of(ipcp, struct shmid_kernel, shm_perm);
131} 139}
132 140
141static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
142{
143 rcu_read_lock();
144 spin_lock(&ipcp->shm_perm.lock);
145}
146
133static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, 147static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
134 int id) 148 int id)
135{ 149{
@@ -187,6 +201,23 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
187} 201}
188 202
189/* 203/*
204 * shm_may_destroy - identifies whether shm segment should be destroyed now
205 *
206 * Returns true if and only if there are no active users of the segment and
207 * one of the following is true:
208 *
209 * 1) shmctl(id, IPC_RMID, NULL) was called for this shp
210 *
211 * 2) sysctl kernel.shm_rmid_forced is set to 1.
212 */
213static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
214{
215 return (shp->shm_nattch == 0) &&
216 (ns->shm_rmid_forced ||
217 (shp->shm_perm.mode & SHM_DEST));
218}
219
220/*
190 * remove the attach descriptor vma. 221 * remove the attach descriptor vma.
191 * free memory for segment if it is marked destroyed. 222 * free memory for segment if it is marked destroyed.
192 * The descriptor has already been removed from the current->mm->mmap list 223 * The descriptor has already been removed from the current->mm->mmap list
@@ -206,14 +237,90 @@ static void shm_close(struct vm_area_struct *vma)
206 shp->shm_lprid = task_tgid_vnr(current); 237 shp->shm_lprid = task_tgid_vnr(current);
207 shp->shm_dtim = get_seconds(); 238 shp->shm_dtim = get_seconds();
208 shp->shm_nattch--; 239 shp->shm_nattch--;
209 if(shp->shm_nattch == 0 && 240 if (shm_may_destroy(ns, shp))
210 shp->shm_perm.mode & SHM_DEST)
211 shm_destroy(ns, shp); 241 shm_destroy(ns, shp);
212 else 242 else
213 shm_unlock(shp); 243 shm_unlock(shp);
214 up_write(&shm_ids(ns).rw_mutex); 244 up_write(&shm_ids(ns).rw_mutex);
215} 245}
216 246
247/* Called with ns->shm_ids(ns).rw_mutex locked */
248static int shm_try_destroy_current(int id, void *p, void *data)
249{
250 struct ipc_namespace *ns = data;
251 struct kern_ipc_perm *ipcp = p;
252 struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
253
254 if (shp->shm_creator != current)
255 return 0;
256
257 /*
258 * Mark it as orphaned to destroy the segment when
259 * kernel.shm_rmid_forced is changed.
260 * It is noop if the following shm_may_destroy() returns true.
261 */
262 shp->shm_creator = NULL;
263
264 /*
265 * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID
266 * is not set, it shouldn't be deleted here.
267 */
268 if (!ns->shm_rmid_forced)
269 return 0;
270
271 if (shm_may_destroy(ns, shp)) {
272 shm_lock_by_ptr(shp);
273 shm_destroy(ns, shp);
274 }
275 return 0;
276}
277
278/* Called with ns->shm_ids(ns).rw_mutex locked */
279static int shm_try_destroy_orphaned(int id, void *p, void *data)
280{
281 struct ipc_namespace *ns = data;
282 struct kern_ipc_perm *ipcp = p;
283 struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
284
285 /*
286 * We want to destroy segments without users and with already
287 * exit'ed originating process.
288 *
289 * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
290 */
291 if (shp->shm_creator != NULL)
292 return 0;
293
294 if (shm_may_destroy(ns, shp)) {
295 shm_lock_by_ptr(shp);
296 shm_destroy(ns, shp);
297 }
298 return 0;
299}
300
301void shm_destroy_orphaned(struct ipc_namespace *ns)
302{
303 down_write(&shm_ids(ns).rw_mutex);
304 if (shm_ids(ns).in_use)
305 idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
306 up_write(&shm_ids(ns).rw_mutex);
307}
308
309
310void exit_shm(struct task_struct *task)
311{
312 struct ipc_namespace *ns = task->nsproxy->ipc_ns;
313
314 if (shm_ids(ns).in_use == 0)
315 return;
316
317 /* Destroy all already created segments, but not mapped yet */
318 down_write(&shm_ids(ns).rw_mutex);
319 if (shm_ids(ns).in_use)
320 idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
321 up_write(&shm_ids(ns).rw_mutex);
322}
323
217static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 324static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
218{ 325{
219 struct file *file = vma->vm_file; 326 struct file *file = vma->vm_file;
@@ -404,6 +511,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
404 shp->shm_segsz = size; 511 shp->shm_segsz = size;
405 shp->shm_nattch = 0; 512 shp->shm_nattch = 0;
406 shp->shm_file = file; 513 shp->shm_file = file;
514 shp->shm_creator = current;
407 /* 515 /*
408 * shmid gets reported as "inode#" in /proc/pid/maps. 516 * shmid gets reported as "inode#" in /proc/pid/maps.
409 * proc-ps tools use this. Changing this will break them. 517 * proc-ps tools use this. Changing this will break them.
@@ -950,8 +1058,7 @@ out_nattch:
950 shp = shm_lock(ns, shmid); 1058 shp = shm_lock(ns, shmid);
951 BUG_ON(IS_ERR(shp)); 1059 BUG_ON(IS_ERR(shp));
952 shp->shm_nattch--; 1060 shp->shm_nattch--;
953 if(shp->shm_nattch == 0 && 1061 if (shm_may_destroy(ns, shp))
954 shp->shm_perm.mode & SHM_DEST)
955 shm_destroy(ns, shp); 1062 shm_destroy(ns, shp);
956 else 1063 else
957 shm_unlock(shp); 1064 shm_unlock(shp);