aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c111
1 files changed, 82 insertions, 29 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index a3673a09069a..c82d7b51ef68 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -88,7 +88,6 @@ static const struct file_operations mqueue_file_operations;
88static struct super_operations mqueue_super_ops; 88static struct super_operations mqueue_super_ops;
89static void remove_notification(struct mqueue_inode_info *info); 89static void remove_notification(struct mqueue_inode_info *info);
90 90
91static spinlock_t mq_lock;
92static struct kmem_cache *mqueue_inode_cachep; 91static struct kmem_cache *mqueue_inode_cachep;
93 92
94static struct ctl_table_header * mq_sysctl_table; 93static struct ctl_table_header * mq_sysctl_table;
@@ -98,27 +97,30 @@ static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
98 return container_of(inode, struct mqueue_inode_info, vfs_inode); 97 return container_of(inode, struct mqueue_inode_info, vfs_inode);
99} 98}
100 99
101void mq_init_ns(struct ipc_namespace *ns) 100/*
101 * This routine should be called with the mq_lock held.
102 */
103static inline struct ipc_namespace *__get_ns_from_inode(struct inode *inode)
102{ 104{
103 ns->mq_queues_count = 0; 105 return get_ipc_ns(inode->i_sb->s_fs_info);
104 ns->mq_queues_max = DFLT_QUEUESMAX;
105 ns->mq_msg_max = DFLT_MSGMAX;
106 ns->mq_msgsize_max = DFLT_MSGSIZEMAX;
107 ns->mq_mnt = mntget(init_ipc_ns.mq_mnt);
108} 106}
109 107
110void mq_exit_ns(struct ipc_namespace *ns) 108static struct ipc_namespace *get_ns_from_inode(struct inode *inode)
111{ 109{
112 /* will need to clear out ns->mq_mnt->mnt_sb->s_fs_info here */ 110 struct ipc_namespace *ns;
113 mntput(ns->mq_mnt); 111
112 spin_lock(&mq_lock);
113 ns = __get_ns_from_inode(inode);
114 spin_unlock(&mq_lock);
115 return ns;
114} 116}
115 117
116static struct inode *mqueue_get_inode(struct super_block *sb, int mode, 118static struct inode *mqueue_get_inode(struct super_block *sb,
117 struct mq_attr *attr) 119 struct ipc_namespace *ipc_ns, int mode,
120 struct mq_attr *attr)
118{ 121{
119 struct user_struct *u = current_user(); 122 struct user_struct *u = current_user();
120 struct inode *inode; 123 struct inode *inode;
121 struct ipc_namespace *ipc_ns = &init_ipc_ns;
122 124
123 inode = new_inode(sb); 125 inode = new_inode(sb);
124 if (inode) { 126 if (inode) {
@@ -193,30 +195,38 @@ out_inode:
193static int mqueue_fill_super(struct super_block *sb, void *data, int silent) 195static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
194{ 196{
195 struct inode *inode; 197 struct inode *inode;
198 struct ipc_namespace *ns = data;
199 int error = 0;
196 200
197 sb->s_blocksize = PAGE_CACHE_SIZE; 201 sb->s_blocksize = PAGE_CACHE_SIZE;
198 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 202 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
199 sb->s_magic = MQUEUE_MAGIC; 203 sb->s_magic = MQUEUE_MAGIC;
200 sb->s_op = &mqueue_super_ops; 204 sb->s_op = &mqueue_super_ops;
201 205
202 inode = mqueue_get_inode(sb, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL); 206 inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO,
203 if (!inode) 207 NULL);
204 return -ENOMEM; 208 if (!inode) {
209 error = -ENOMEM;
210 goto out;
211 }
205 212
206 sb->s_root = d_alloc_root(inode); 213 sb->s_root = d_alloc_root(inode);
207 if (!sb->s_root) { 214 if (!sb->s_root) {
208 iput(inode); 215 iput(inode);
209 return -ENOMEM; 216 error = -ENOMEM;
210 } 217 }
211 218
212 return 0; 219out:
220 return error;
213} 221}
214 222
215static int mqueue_get_sb(struct file_system_type *fs_type, 223static int mqueue_get_sb(struct file_system_type *fs_type,
216 int flags, const char *dev_name, 224 int flags, const char *dev_name,
217 void *data, struct vfsmount *mnt) 225 void *data, struct vfsmount *mnt)
218{ 226{
219 return get_sb_single(fs_type, flags, data, mqueue_fill_super, mnt); 227 if (!(flags & MS_KERNMOUNT))
228 data = current->nsproxy->ipc_ns;
229 return get_sb_ns(fs_type, flags, data, mqueue_fill_super, mnt);
220} 230}
221 231
222static void init_once(void *foo) 232static void init_once(void *foo)
@@ -247,12 +257,13 @@ static void mqueue_delete_inode(struct inode *inode)
247 struct user_struct *user; 257 struct user_struct *user;
248 unsigned long mq_bytes; 258 unsigned long mq_bytes;
249 int i; 259 int i;
250 struct ipc_namespace *ipc_ns = &init_ipc_ns; 260 struct ipc_namespace *ipc_ns;
251 261
252 if (S_ISDIR(inode->i_mode)) { 262 if (S_ISDIR(inode->i_mode)) {
253 clear_inode(inode); 263 clear_inode(inode);
254 return; 264 return;
255 } 265 }
266 ipc_ns = get_ns_from_inode(inode);
256 info = MQUEUE_I(inode); 267 info = MQUEUE_I(inode);
257 spin_lock(&info->lock); 268 spin_lock(&info->lock);
258 for (i = 0; i < info->attr.mq_curmsgs; i++) 269 for (i = 0; i < info->attr.mq_curmsgs; i++)
@@ -268,10 +279,19 @@ static void mqueue_delete_inode(struct inode *inode)
268 if (user) { 279 if (user) {
269 spin_lock(&mq_lock); 280 spin_lock(&mq_lock);
270 user->mq_bytes -= mq_bytes; 281 user->mq_bytes -= mq_bytes;
271 ipc_ns->mq_queues_count--; 282 /*
283 * get_ns_from_inode() ensures that the
284 * (ipc_ns = sb->s_fs_info) is either a valid ipc_ns
285 * to which we now hold a reference, or it is NULL.
286 * We can't put it here under mq_lock, though.
287 */
288 if (ipc_ns)
289 ipc_ns->mq_queues_count--;
272 spin_unlock(&mq_lock); 290 spin_unlock(&mq_lock);
273 free_uid(user); 291 free_uid(user);
274 } 292 }
293 if (ipc_ns)
294 put_ipc_ns(ipc_ns);
275} 295}
276 296
277static int mqueue_create(struct inode *dir, struct dentry *dentry, 297static int mqueue_create(struct inode *dir, struct dentry *dentry,
@@ -280,9 +300,14 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
280 struct inode *inode; 300 struct inode *inode;
281 struct mq_attr *attr = dentry->d_fsdata; 301 struct mq_attr *attr = dentry->d_fsdata;
282 int error; 302 int error;
283 struct ipc_namespace *ipc_ns = &init_ipc_ns; 303 struct ipc_namespace *ipc_ns;
284 304
285 spin_lock(&mq_lock); 305 spin_lock(&mq_lock);
306 ipc_ns = __get_ns_from_inode(dir);
307 if (!ipc_ns) {
308 error = -EACCES;
309 goto out_unlock;
310 }
286 if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && 311 if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
287 !capable(CAP_SYS_RESOURCE)) { 312 !capable(CAP_SYS_RESOURCE)) {
288 error = -ENOSPC; 313 error = -ENOSPC;
@@ -291,7 +316,7 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
291 ipc_ns->mq_queues_count++; 316 ipc_ns->mq_queues_count++;
292 spin_unlock(&mq_lock); 317 spin_unlock(&mq_lock);
293 318
294 inode = mqueue_get_inode(dir->i_sb, mode, attr); 319 inode = mqueue_get_inode(dir->i_sb, ipc_ns, mode, attr);
295 if (!inode) { 320 if (!inode) {
296 error = -ENOMEM; 321 error = -ENOMEM;
297 spin_lock(&mq_lock); 322 spin_lock(&mq_lock);
@@ -299,6 +324,7 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
299 goto out_unlock; 324 goto out_unlock;
300 } 325 }
301 326
327 put_ipc_ns(ipc_ns);
302 dir->i_size += DIRENT_SIZE; 328 dir->i_size += DIRENT_SIZE;
303 dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; 329 dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
304 330
@@ -307,6 +333,8 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
307 return 0; 333 return 0;
308out_unlock: 334out_unlock:
309 spin_unlock(&mq_lock); 335 spin_unlock(&mq_lock);
336 if (ipc_ns)
337 put_ipc_ns(ipc_ns);
310 return error; 338 return error;
311} 339}
312 340
@@ -668,7 +696,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
668 char *name; 696 char *name;
669 struct mq_attr attr; 697 struct mq_attr attr;
670 int fd, error; 698 int fd, error;
671 struct ipc_namespace *ipc_ns = &init_ipc_ns; 699 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
672 700
673 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) 701 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
674 return -EFAULT; 702 return -EFAULT;
@@ -738,7 +766,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
738 char *name; 766 char *name;
739 struct dentry *dentry; 767 struct dentry *dentry;
740 struct inode *inode = NULL; 768 struct inode *inode = NULL;
741 struct ipc_namespace *ipc_ns = &init_ipc_ns; 769 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
742 770
743 name = getname(u_name); 771 name = getname(u_name);
744 if (IS_ERR(name)) 772 if (IS_ERR(name))
@@ -1217,6 +1245,32 @@ static struct file_system_type mqueue_fs_type = {
1217 .kill_sb = kill_litter_super, 1245 .kill_sb = kill_litter_super,
1218}; 1246};
1219 1247
1248int mq_init_ns(struct ipc_namespace *ns)
1249{
1250 ns->mq_queues_count = 0;
1251 ns->mq_queues_max = DFLT_QUEUESMAX;
1252 ns->mq_msg_max = DFLT_MSGMAX;
1253 ns->mq_msgsize_max = DFLT_MSGSIZEMAX;
1254
1255 ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
1256 if (IS_ERR(ns->mq_mnt)) {
1257 int err = PTR_ERR(ns->mq_mnt);
1258 ns->mq_mnt = NULL;
1259 return err;
1260 }
1261 return 0;
1262}
1263
1264void mq_clear_sbinfo(struct ipc_namespace *ns)
1265{
1266 ns->mq_mnt->mnt_sb->s_fs_info = NULL;
1267}
1268
1269void mq_put_mnt(struct ipc_namespace *ns)
1270{
1271 mntput(ns->mq_mnt);
1272}
1273
1220static int msg_max_limit_min = MIN_MSGMAX; 1274static int msg_max_limit_min = MIN_MSGMAX;
1221static int msg_max_limit_max = MAX_MSGMAX; 1275static int msg_max_limit_max = MAX_MSGMAX;
1222 1276
@@ -1288,15 +1342,14 @@ static int __init init_mqueue_fs(void)
1288 if (error) 1342 if (error)
1289 goto out_sysctl; 1343 goto out_sysctl;
1290 1344
1291 init_ipc_ns.mq_mnt = kern_mount(&mqueue_fs_type); 1345 spin_lock_init(&mq_lock);
1346
1347 init_ipc_ns.mq_mnt = kern_mount_data(&mqueue_fs_type, &init_ipc_ns);
1292 if (IS_ERR(init_ipc_ns.mq_mnt)) { 1348 if (IS_ERR(init_ipc_ns.mq_mnt)) {
1293 error = PTR_ERR(init_ipc_ns.mq_mnt); 1349 error = PTR_ERR(init_ipc_ns.mq_mnt);
1294 goto out_filesystem; 1350 goto out_filesystem;
1295 } 1351 }
1296 1352
1297 /* internal initialization - not common for vfs */
1298 spin_lock_init(&mq_lock);
1299
1300 return 0; 1353 return 0;
1301 1354
1302out_filesystem: 1355out_filesystem: