1 /* 2 * linux/ipc/msg.c 3 * Copyright (C) 1992 Krishna Balasubramanian 4 * 5 * Removed all the remaining kerneld mess 6 * Catch the -EFAULT stuff properly 7 * Use GFP_KERNEL for messages as in 1.2 8 * Fixed up the unchecked user space derefs 9 * Copyright (C) 1998 Alan Cox & Andi Kleen 10 * 11 * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com> 12 * 13 * mostly rewritten, threaded and wake-one semantics added 14 * MSGMAX limit removed, sysctl's added 15 * (c) 1999 Manfred Spraul <manfred@colorfullife.com> 16 */ 17 18 #include <linux/capability.h> 19 #include <linux/config.h> 20 #include <linux/slab.h> 21 #include <linux/msg.h> 22 #include <linux/spinlock.h> 23 #include <linux/init.h> 24 #include <linux/proc_fs.h> 25 #include <linux/list.h> 26 #include <linux/security.h> 27 #include <linux/sched.h> 28 #include <linux/syscalls.h> 29 #include <linux/audit.h> 30 #include <linux/seq_file.h> 31 #include <asm/current.h> 32 #include <asm/uaccess.h> 33 #include "util.h" 34 35 /* sysctl: */ 36 int msg_ctlmax = MSGMAX; 37 int msg_ctlmnb = MSGMNB; 38 int msg_ctlmni = MSGMNI; 39 40 /* one msg_receiver structure for each sleeping receiver */ 41 struct msg_receiver { 42 struct list_head r_list; 43 struct task_struct* r_tsk; 44 45 int r_mode; 46 long r_msgtype; 47 long r_maxsize; 48 49 struct msg_msg* volatile r_msg; 50 }; 51 52 /* one msg_sender for each sleeping sender */ 53 struct msg_sender { 54 struct list_head list; 55 struct task_struct* tsk; 56 }; 57 58 #define SEARCH_ANY 1 59 #define SEARCH_EQUAL 2 60 #define SEARCH_NOTEQUAL 3 61 #define SEARCH_LESSEQUAL 4 62 63 static atomic_t msg_bytes = ATOMIC_INIT(0); 64 static atomic_t msg_hdrs = ATOMIC_INIT(0); 65 66 static struct ipc_ids msg_ids; 67 68 #define msg_lock(id) ((struct msg_queue*)ipc_lock(&msg_ids,id)) 69 #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) 70 #define msg_rmid(id) ((struct msg_queue*)ipc_rmid(&msg_ids,id)) 71 #define msg_checkid(msq, msgid) \ 72 ipc_checkid(&msg_ids,&msq->q_perm,msgid) 73 #define msg_buildid(id, seq) \ 74 ipc_buildid(&msg_ids, id, seq) 75 76 static void freeque (struct msg_queue *msq, int id); 77 static int newque (key_t key, int msgflg); 78 #ifdef CONFIG_PROC_FS 79 static int sysvipc_msg_proc_show(struct seq_file *s, void *it); 80 #endif 81 82 void __init msg_init (void) 83 { 84 ipc_init_ids(&msg_ids,msg_ctlmni); 85 ipc_init_proc_interface("sysvipc/msg", 86 " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", 87 &msg_ids, 88 sysvipc_msg_proc_show); 89 } 90 91 static int newque (key_t key, int msgflg) 92 { 93 int id; 94 int retval; 95 struct msg_queue *msq; 96 97 msq = ipc_rcu_alloc(sizeof(*msq)); 98 if (!msq) 99 return -ENOMEM; 100 101 msq->q_perm.mode = (msgflg & S_IRWXUGO); 102 msq->q_perm.key = key; 103 104 msq->q_perm.security = NULL; 105 retval = security_msg_queue_alloc(msq); 106 if (retval) { 107 ipc_rcu_putref(msq); 108 return retval; 109 } 110 111 id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); 112 if(id == -1) { 113 security_msg_queue_free(msq); 114 ipc_rcu_putref(msq); 115 return -ENOSPC; 116 } 117 118 msq->q_id = msg_buildid(id,msq->q_perm.seq); 119 msq->q_stime = msq->q_rtime = 0; 120 msq->q_ctime = get_seconds(); 121 msq->q_cbytes = msq->q_qnum = 0; 122 msq->q_qbytes = msg_ctlmnb; 123 msq->q_lspid = msq->q_lrpid = 0; 124 INIT_LIST_HEAD(&msq->q_messages); 125 INIT_LIST_HEAD(&msq->q_receivers); 126 INIT_LIST_HEAD(&msq->q_senders); 127 msg_unlock(msq); 128 129 return msq->q_id; 130 } 131 132 static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss) 133 { 134 mss->tsk=current; 135 current->state=TASK_INTERRUPTIBLE; 136 list_add_tail(&mss->list,&msq->q_senders); 137 } 138 139 static inline void ss_del(struct msg_sender* mss) 140 { 141 if(mss->list.next != NULL) 142 list_del(&mss->list); 143 } 144 145 static void ss_wakeup(struct list_head* h, int kill) 146 { 147 struct list_head *tmp; 148 149 tmp = h->next; 150 while (tmp != h) { 151 struct msg_sender* mss; 152 153 mss = list_entry(tmp,struct msg_sender,list); 154 tmp = tmp->next; 155 if(kill) 156 mss->list.next=NULL; 157 wake_up_process(mss->tsk); 158 } 159 } 160 161 static void expunge_all(struct msg_queue* msq, int res) 162 { 163 struct list_head *tmp; 164 165 tmp = msq->q_receivers.next; 166 while (tmp != &msq->q_receivers) { 167 struct msg_receiver* msr; 168 169 msr = list_entry(tmp,struct msg_receiver,r_list); 170 tmp = tmp->next; 171 msr->r_msg = NULL; 172 wake_up_process(msr->r_tsk); 173 smp_mb(); 174 msr->r_msg = ERR_PTR(res); 175 } 176 } 177 /* 178 * freeque() wakes up waiters on the sender and receiver waiting queue, 179 * removes the message queue from message queue ID 180 * array, and cleans up all the messages associated with this queue. 181 * 182 * msg_ids.sem and the spinlock for this message queue is hold 183 * before freeque() is called. msg_ids.sem remains locked on exit. 184 */ 185 static void freeque (struct msg_queue *msq, int id) 186 { 187 struct list_head *tmp; 188 189 expunge_all(msq,-EIDRM); 190 ss_wakeup(&msq->q_senders,1); 191 msq = msg_rmid(id); 192 msg_unlock(msq); 193 194 tmp = msq->q_messages.next; 195 while(tmp != &msq->q_messages) { 196 struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list); 197 tmp = tmp->next; 198 atomic_dec(&msg_hdrs); 199 free_msg(msg); 200 } 201 atomic_sub(msq->q_cbytes, &msg_bytes); 202 security_msg_queue_free(msq); 203 ipc_rcu_putref(msq); 204 } 205 206 asmlinkage long sys_msgget (key_t key, int msgflg) 207 { 208 int id, ret = -EPERM; 209 struct msg_queue *msq; 210 211 down(&msg_ids.sem); 212 if (key == IPC_PRIVATE) 213 ret = newque(key, msgflg); 214 else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */ 215 if (!(msgflg & IPC_CREAT)) 216 ret = -ENOENT; 217 else 218 ret = newque(key, msgflg); 219 } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { 220 ret = -EEXIST; 221 } else { 222 msq = msg_lock(id); 223 if(msq==NULL) 224 BUG(); 225 if (ipcperms(&msq->q_perm, msgflg)) 226 ret = -EACCES; 227 else { 228 int qid = msg_buildid(id, msq->q_perm.seq); 229 ret = security_msg_queue_associate(msq, msgflg); 230 if (!ret) 231 ret = qid; 232 } 233 msg_unlock(msq); 234 } 235 up(&msg_ids.sem); 236 return ret; 237 } 238 239 static inline unsigned long copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) 240 { 241 switch(version) { 242 case IPC_64: 243 return copy_to_user (buf, in, sizeof(*in)); 244 case IPC_OLD: 245 { 246 struct msqid_ds out; 247 248 memset(&out,0,sizeof(out)); 249 250 ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm); 251 252 out.msg_stime = in->msg_stime; 253 out.msg_rtime = in->msg_rtime; 254 out.msg_ctime = in->msg_ctime; 255 256 if(in->msg_cbytes > USHRT_MAX) 257 out.msg_cbytes = USHRT_MAX; 258 else 259 out.msg_cbytes = in->msg_cbytes; 260 out.msg_lcbytes = in->msg_cbytes; 261 262 if(in->msg_qnum > USHRT_MAX) 263 out.msg_qnum = USHRT_MAX; 264 else 265 out.msg_qnum = in->msg_qnum; 266 267 if(in->msg_qbytes > USHRT_MAX) 268 out.msg_qbytes = USHRT_MAX; 269 else 270 out.msg_qbytes = in->msg_qbytes; 271 out.msg_lqbytes = in->msg_qbytes; 272 273 out.msg_lspid = in->msg_lspid; 274 out.msg_lrpid = in->msg_lrpid; 275 276 return copy_to_user (buf, &out, sizeof(out)); 277 } 278 default: 279 return -EINVAL; 280 } 281 } 282 283 struct msq_setbuf { 284 unsigned long qbytes; 285 uid_t uid; 286 gid_t gid; 287 mode_t mode; 288 }; 289 290 static inline unsigned long copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version) 291 { 292 switch(version) { 293 case IPC_64: 294 { 295 struct msqid64_ds tbuf; 296 297 if (copy_from_user (&tbuf, buf, sizeof (tbuf))) 298 return -EFAULT; 299 300 out->qbytes = tbuf.msg_qbytes; 301 out->uid = tbuf.msg_perm.uid; 302 out->gid = tbuf.msg_perm.gid; 303 out->mode = tbuf.msg_perm.mode; 304 305 return 0; 306 } 307 case IPC_OLD: 308 { 309 struct msqid_ds tbuf_old; 310 311 if (copy_from_user (&tbuf_old, buf, sizeof (tbuf_old))) 312 return -EFAULT; 313 314 out->uid = tbuf_old.msg_perm.uid; 315 out->gid = tbuf_old.msg_perm.gid; 316 out->mode = tbuf_old.msg_perm.mode; 317 318 if(tbuf_old.msg_qbytes == 0) 319 out->qbytes = tbuf_old.msg_lqbytes; 320 else 321 out->qbytes = tbuf_old.msg_qbytes; 322 323 return 0; 324 } 325 default: 326 return -EINVAL; 327 } 328 } 329 330 asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) 331 { 332 int err, version; 333 struct msg_queue *msq; 334 struct msq_setbuf setbuf; 335 struct kern_ipc_perm *ipcp; 336 337 if (msqid < 0 || cmd < 0) 338 return -EINVAL; 339 340 version = ipc_parse_version(&cmd); 341 342 switch (cmd) { 343 case IPC_INFO: 344 case MSG_INFO: 345 { 346 struct msginfo msginfo; 347 int max_id; 348 if (!buf) 349 return -EFAULT; 350 /* We must not return kernel stack data. 351 * due to padding, it's not enough 352 * to set all member fields. 353 */ 354 355 err = security_msg_queue_msgctl(NULL, cmd); 356 if (err) 357 return err; 358 359 memset(&msginfo,0,sizeof(msginfo)); 360 msginfo.msgmni = msg_ctlmni; 361 msginfo.msgmax = msg_ctlmax; 362 msginfo.msgmnb = msg_ctlmnb; 363 msginfo.msgssz = MSGSSZ; 364 msginfo.msgseg = MSGSEG; 365 down(&msg_ids.sem); 366 if (cmd == MSG_INFO) { 367 msginfo.msgpool = msg_ids.in_use; 368 msginfo.msgmap = atomic_read(&msg_hdrs); 369 msginfo.msgtql = atomic_read(&msg_bytes); 370 } else { 371 msginfo.msgmap = MSGMAP; 372 msginfo.msgpool = MSGPOOL; 373 msginfo.msgtql = MSGTQL; 374 } 375 max_id = msg_ids.max_id; 376 up(&msg_ids.sem); 377 if (copy_to_user (buf, &msginfo, sizeof(struct msginfo))) 378 return -EFAULT; 379 return (max_id < 0) ? 0: max_id; 380 } 381 case MSG_STAT: 382 case IPC_STAT: 383 { 384 struct msqid64_ds tbuf; 385 int success_return; 386 if (!buf) 387 return -EFAULT; 388 if(cmd == MSG_STAT && msqid >= msg_ids.entries->size) 389 return -EINVAL; 390 391 memset(&tbuf,0,sizeof(tbuf)); 392 393 msq = msg_lock(msqid); 394 if (msq == NULL) 395 return -EINVAL; 396 397 if(cmd == MSG_STAT) { 398 success_return = msg_buildid(msqid, msq->q_perm.seq); 399 } else { 400 err = -EIDRM; 401 if (msg_checkid(msq,msqid)) 402 goto out_unlock; 403 success_return = 0; 404 } 405 err = -EACCES; 406 if (ipcperms (&msq->q_perm, S_IRUGO)) 407 goto out_unlock; 408 409 err = security_msg_queue_msgctl(msq, cmd); 410 if (err) 411 goto out_unlock; 412 413 kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm); 414 tbuf.msg_stime = msq->q_stime; 415 tbuf.msg_rtime = msq->q_rtime; 416 tbuf.msg_ctime = msq->q_ctime; 417 tbuf.msg_cbytes = msq->q_cbytes; 418 tbuf.msg_qnum = msq->q_qnum; 419 tbuf.msg_qbytes = msq->q_qbytes; 420 tbuf.msg_lspid = msq->q_lspid; 421 tbuf.msg_lrpid = msq->q_lrpid; 422 msg_unlock(msq); 423 if (copy_msqid_to_user(buf, &tbuf, version)) 424 return -EFAULT; 425 return success_return; 426 } 427 case IPC_SET: 428 if (!buf) 429 return -EFAULT; 430 if (copy_msqid_from_user (&setbuf, buf, version)) 431 return -EFAULT; 432 if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode))) 433 return err; 434 break; 435 case IPC_RMID: 436 break; 437 default: 438 return -EINVAL; 439 } 440 441 down(&msg_ids.sem); 442 msq = msg_lock(msqid); 443 err=-EINVAL; 444 if (msq == NULL) 445 goto out_up; 446 447 err = -EIDRM; 448 if (msg_checkid(msq,msqid)) 449 goto out_unlock_up; 450 ipcp = &msq->q_perm; 451 err = -EPERM; 452 if (current->euid != ipcp->cuid && 453 current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) 454 /* We _could_ check for CAP_CHOWN above, but we don't */ 455 goto out_unlock_up; 456 457 err = security_msg_queue_msgctl(msq, cmd); 458 if (err) 459 goto out_unlock_up; 460 461 switch (cmd) { 462 case IPC_SET: 463 { 464 err = -EPERM; 465 if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) 466 goto out_unlock_up; 467 468 msq->q_qbytes = setbuf.qbytes; 469 470 ipcp->uid = setbuf.uid; 471 ipcp->gid = setbuf.gid; 472 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 473 (S_IRWXUGO & setbuf.mode); 474 msq->q_ctime = get_seconds(); 475 /* sleeping receivers might be excluded by 476 * stricter permissions. 477 */ 478 expunge_all(msq,-EAGAIN); 479 /* sleeping senders might be able to send 480 * due to a larger queue size. 481 */ 482 ss_wakeup(&msq->q_senders,0); 483 msg_unlock(msq); 484 break; 485 } 486 case IPC_RMID: 487 freeque (msq, msqid); 488 break; 489 } 490 err = 0; 491 out_up: 492 up(&msg_ids.sem); 493 return err; 494 out_unlock_up: 495 msg_unlock(msq); 496 goto out_up; 497 out_unlock: 498 msg_unlock(msq); 499 return err; 500 } 501 502 static int testmsg(struct msg_msg* msg,long type,int mode) 503 { 504 switch(mode) 505 { 506 case SEARCH_ANY: 507 return 1; 508 case SEARCH_LESSEQUAL: 509 if(msg->m_type <=type) 510 return 1; 511 break; 512 case SEARCH_EQUAL: 513 if(msg->m_type == type) 514 return 1; 515 break; 516 case SEARCH_NOTEQUAL: 517 if(msg->m_type != type) 518 return 1; 519 break; 520 } 521 return 0; 522 } 523 524 static inline int pipelined_send(struct msg_queue* msq, struct msg_msg* msg) 525 { 526 struct list_head* tmp; 527 528 tmp = msq->q_receivers.next; 529 while (tmp != &msq->q_receivers) { 530 struct msg_receiver* msr; 531 msr = list_entry(tmp,struct msg_receiver,r_list); 532 tmp = tmp->next; 533 if(testmsg(msg,msr->r_msgtype,msr->r_mode) && 534 !security_msg_queue_msgrcv(msq, msg, msr->r_tsk, msr->r_msgtype, msr->r_mode)) { 535 list_del(&msr->r_list); 536 if(msr->r_maxsize < msg->m_ts) { 537 msr->r_msg = NULL; 538 wake_up_process(msr->r_tsk); 539 smp_mb(); 540 msr->r_msg = ERR_PTR(-E2BIG); 541 } else { 542 msr->r_msg = NULL; 543 msq->q_lrpid = msr->r_tsk->pid; 544 msq->q_rtime = get_seconds(); 545 wake_up_process(msr->r_tsk); 546 smp_mb(); 547 msr->r_msg = msg; 548 return 1; 549 } 550 } 551 } 552 return 0; 553 } 554 555 asmlinkage long sys_msgsnd (int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) 556 { 557 struct msg_queue *msq; 558 struct msg_msg *msg; 559 long mtype; 560 int err; 561 562 if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0) 563 return -EINVAL; 564 if (get_user(mtype, &msgp->mtype)) 565 return -EFAULT; 566 if (mtype < 1) 567 return -EINVAL; 568 569 msg = load_msg(msgp->mtext, msgsz); 570 if(IS_ERR(msg)) 571 return PTR_ERR(msg); 572 573 msg->m_type = mtype; 574 msg->m_ts = msgsz; 575 576 msq = msg_lock(msqid); 577 err=-EINVAL; 578 if(msq==NULL) 579 goto out_free; 580 581 err= -EIDRM; 582 if (msg_checkid(msq,msqid)) 583 goto out_unlock_free; 584 585 for (;;) { 586 struct msg_sender s; 587 588 err=-EACCES; 589 if (ipcperms(&msq->q_perm, S_IWUGO)) 590 goto out_unlock_free; 591 592 err = security_msg_queue_msgsnd(msq, msg, msgflg); 593 if (err) 594 goto out_unlock_free; 595 596 if(msgsz + msq->q_cbytes <= msq->q_qbytes && 597 1 + msq->q_qnum <= msq->q_qbytes) { 598 break; 599 } 600 601 /* queue full, wait: */ 602 if(msgflg&IPC_NOWAIT) { 603 err=-EAGAIN; 604 goto out_unlock_free; 605 } 606 ss_add(msq, &s); 607 ipc_rcu_getref(msq); 608 msg_unlock(msq); 609 schedule(); 610 611 ipc_lock_by_ptr(&msq->q_perm); 612 ipc_rcu_putref(msq); 613 if (msq->q_perm.deleted) { 614 err = -EIDRM; 615 goto out_unlock_free; 616 } 617 ss_del(&s); 618 619 if (signal_pending(current)) { 620 err=-ERESTARTNOHAND; 621 goto out_unlock_free; 622 } 623 } 624 625 msq->q_lspid = current->tgid; 626 msq->q_stime = get_seconds(); 627 628 if(!pipelined_send(msq,msg)) { 629 /* noone is waiting for this message, enqueue it */ 630 list_add_tail(&msg->m_list,&msq->q_messages); 631 msq->q_cbytes += msgsz; 632 msq->q_qnum++; 633 atomic_add(msgsz,&msg_bytes); 634 atomic_inc(&msg_hdrs); 635 } 636 637 err = 0; 638 msg = NULL; 639 640 out_unlock_free: 641 msg_unlock(msq); 642 out_free: 643 if(msg!=NULL) 644 free_msg(msg); 645 return err; 646 } 647 648 static inline int convert_mode(long* msgtyp, int msgflg) 649 { 650 /* 651 * find message of correct type. 652 * msgtyp = 0 => get first. 653 * msgtyp > 0 => get first message of matching type. 654 * msgtyp < 0 => get message with least type must be < abs(msgtype). 655 */ 656 if(*msgtyp==0) 657 return SEARCH_ANY; 658 if(*msgtyp<0) { 659 *msgtyp=-(*msgtyp); 660 return SEARCH_LESSEQUAL; 661 } 662 if(msgflg & MSG_EXCEPT) 663 return SEARCH_NOTEQUAL; 664 return SEARCH_EQUAL; 665 } 666 667 asmlinkage long sys_msgrcv (int msqid, struct msgbuf __user *msgp, size_t msgsz, 668 long msgtyp, int msgflg) 669 { 670 struct msg_queue *msq; 671 struct msg_msg *msg; 672 int mode; 673 674 if (msqid < 0 || (long) msgsz < 0) 675 return -EINVAL; 676 mode = convert_mode(&msgtyp,msgflg); 677 678 msq = msg_lock(msqid); 679 if(msq==NULL) 680 return -EINVAL; 681 682 msg = ERR_PTR(-EIDRM); 683 if (msg_checkid(msq,msqid)) 684 goto out_unlock; 685 686 for (;;) { 687 struct msg_receiver msr_d; 688 struct list_head* tmp; 689 690 msg = ERR_PTR(-EACCES); 691 if (ipcperms (&msq->q_perm, S_IRUGO)) 692 goto out_unlock; 693 694 msg = ERR_PTR(-EAGAIN); 695 tmp = msq->q_messages.next; 696 while (tmp != &msq->q_messages) { 697 struct msg_msg *walk_msg; 698 walk_msg = list_entry(tmp,struct msg_msg,m_list); 699 if(testmsg(walk_msg,msgtyp,mode) && 700 !security_msg_queue_msgrcv(msq, walk_msg, current, msgtyp, mode)) { 701 msg = walk_msg; 702 if(mode == SEARCH_LESSEQUAL && walk_msg->m_type != 1) { 703 msg=walk_msg; 704 msgtyp=walk_msg->m_type-1; 705 } else { 706 msg=walk_msg; 707 break; 708 } 709 } 710 tmp = tmp->next; 711 } 712 if(!IS_ERR(msg)) { 713 /* Found a suitable message. Unlink it from the queue. */ 714 if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { 715 msg = ERR_PTR(-E2BIG); 716 goto out_unlock; 717 } 718 list_del(&msg->m_list); 719 msq->q_qnum--; 720 msq->q_rtime = get_seconds(); 721 msq->q_lrpid = current->tgid; 722 msq->q_cbytes -= msg->m_ts; 723 atomic_sub(msg->m_ts,&msg_bytes); 724 atomic_dec(&msg_hdrs); 725 ss_wakeup(&msq->q_senders,0); 726 msg_unlock(msq); 727 break; 728 } 729 /* No message waiting. Wait for a message */ 730 if (msgflg & IPC_NOWAIT) { 731 msg = ERR_PTR(-ENOMSG); 732 goto out_unlock; 733 } 734 list_add_tail(&msr_d.r_list,&msq->q_receivers); 735 msr_d.r_tsk = current; 736 msr_d.r_msgtype = msgtyp; 737 msr_d.r_mode = mode; 738 if(msgflg & MSG_NOERROR) 739 msr_d.r_maxsize = INT_MAX; 740 else 741 msr_d.r_maxsize = msgsz; 742 msr_d.r_msg = ERR_PTR(-EAGAIN); 743 current->state = TASK_INTERRUPTIBLE; 744 msg_unlock(msq); 745 746 schedule(); 747 748 /* Lockless receive, part 1: 749 * Disable preemption. We don't hold a reference to the queue 750 * and getting a reference would defeat the idea of a lockless 751 * operation, thus the code relies on rcu to guarantee the 752 * existance of msq: 753 * Prior to destruction, expunge_all(-EIRDM) changes r_msg. 754 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed. 755 * rcu_read_lock() prevents preemption between reading r_msg 756 * and the spin_lock() inside ipc_lock_by_ptr(). 757 */ 758 rcu_read_lock(); 759 760 /* Lockless receive, part 2: 761 * Wait until pipelined_send or expunge_all are outside of 762 * wake_up_process(). There is a race with exit(), see 763 * ipc/mqueue.c for the details. 764 */ 765 msg = (struct msg_msg*) msr_d.r_msg; 766 while (msg == NULL) { 767 cpu_relax(); 768 msg = (struct msg_msg*) msr_d.r_msg; 769 } 770 771 /* Lockless receive, part 3: 772 * If there is a message or an error then accept it without 773 * locking. 774 */ 775 if(msg != ERR_PTR(-EAGAIN)) { 776 rcu_read_unlock(); 777 break; 778 } 779 780 /* Lockless receive, part 3: 781 * Acquire the queue spinlock. 782 */ 783 ipc_lock_by_ptr(&msq->q_perm); 784 rcu_read_unlock(); 785 786 /* Lockless receive, part 4: 787 * Repeat test after acquiring the spinlock. 788 */ 789 msg = (struct msg_msg*)msr_d.r_msg; 790 if(msg != ERR_PTR(-EAGAIN)) 791 goto out_unlock; 792 793 list_del(&msr_d.r_list); 794 if (signal_pending(current)) { 795 msg = ERR_PTR(-ERESTARTNOHAND); 796 out_unlock: 797 msg_unlock(msq); 798 break; 799 } 800 } 801 if (IS_ERR(msg)) 802 return PTR_ERR(msg); 803 804 msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; 805 if (put_user (msg->m_type, &msgp->mtype) || 806 store_msg(msgp->mtext, msg, msgsz)) { 807 msgsz = -EFAULT; 808 } 809 free_msg(msg); 810 return msgsz; 811 } 812 813 #ifdef CONFIG_PROC_FS 814 static int sysvipc_msg_proc_show(struct seq_file *s, void *it) 815 { 816 struct msg_queue *msq = it; 817 818 return seq_printf(s, 819 "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n", 820 msq->q_perm.key, 821 msq->q_id, 822 msq->q_perm.mode, 823 msq->q_cbytes, 824 msq->q_qnum, 825 msq->q_lspid, 826 msq->q_lrpid, 827 msq->q_perm.uid, 828 msq->q_perm.gid, 829 msq->q_perm.cuid, 830 msq->q_perm.cgid, 831 msq->q_stime, 832 msq->q_rtime, 833 msq->q_ctime); 834 } 835 #endif 836