root/ipc/msg.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msg_init
  2. real_msgsnd
  3. real_msgrcv
  4. sys_msgsnd
  5. sys_msgrcv
  6. findkey
  7. newque
  8. sys_msgget
  9. freeque
  10. sys_msgctl
  11. kerneld_exit
  12. kerneld_send

   1 /*
   2  * linux/ipc/msg.c
   3  * Copyright (C) 1992 Krishna Balasubramanian 
   4  *
   5  * Kerneld extensions by Bjorn Ekwall <bj0rn@blox.se> in May 1995
   6  *
   7  */
   8 
   9 #include <linux/config.h>
  10 #include <linux/errno.h>
  11 #include <linux/sched.h>
  12 #include <linux/msg.h>
  13 #include <linux/stat.h>
  14 #include <linux/malloc.h>
  15 #include <linux/kerneld.h>
  16 
  17 #include <asm/segment.h>
  18 
  19 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
  20 
  21 static void freeque (int id);
  22 static int newque (key_t key, int msgflg);
  23 static int findkey (key_t key);
  24 
  25 static struct msqid_ds *msgque[MSGMNI];
  26 static int msgbytes = 0;
  27 static int msghdrs = 0;
  28 static unsigned short msg_seq = 0;
  29 static int used_queues = 0;
  30 static int max_msqid = 0;
  31 static struct wait_queue *msg_lock = NULL;
  32 static int kerneld_msqid = -1;
  33 static int kerneld_pid;
  34 
  35 void msg_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         int id;
  38         
  39         for (id = 0; id < MSGMNI; id++) 
  40                 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
  41         msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
  42         msg_lock = NULL;
  43         return;
  44 }
  45 
  46 static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48         int id, err;
  49         struct msqid_ds *msq;
  50         struct ipc_perm *ipcp;
  51         struct msg *msgh;
  52         long mtype;
  53         
  54         if (msgsz > MSGMAX || (long) msgsz < 0 || msqid < 0)
  55                 return -EINVAL;
  56         if (!msgp) 
  57                 return -EFAULT;
  58         /*
  59          * Calls from kernel level (IPC_KERNELD set)
  60          * have the message somewhere in kernel space already!
  61          */
  62         if ((msgflg & IPC_KERNELD))
  63                 mtype = msgp->mtype;
  64         else {
  65                 err = verify_area (VERIFY_READ, msgp->mtext, msgsz);
  66                 if (err) 
  67                         return err;
  68                 if ((mtype = get_user (&msgp->mtype)) < 1)
  69                         return -EINVAL;
  70         }
  71         id = (unsigned int) msqid % MSGMNI;
  72         msq = msgque [id];
  73         if (msq == IPC_UNUSED || msq == IPC_NOID)
  74                 return -EINVAL;
  75         ipcp = &msq->msg_perm; 
  76 
  77  slept:
  78         if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) 
  79                 return -EIDRM;
  80         /*
  81          * Non-root processes may send to kerneld! 
  82          * i.e. no permission check if called from the kernel
  83          * otoh we don't want user level non-root snoopers...
  84          */
  85         if ((msgflg & IPC_KERNELD) == 0)
  86                 if (ipcperms(ipcp, S_IWUGO)) 
  87                         return -EACCES;
  88         
  89         if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { 
  90                 /* no space in queue */
  91                 if (msgflg & IPC_NOWAIT)
  92                         return -EAGAIN;
  93                 if (current->signal & ~current->blocked)
  94                         return -EINTR;
  95                 if (intr_count) {
  96                         /* Very unlikely, but better safe than sorry... */
  97                         printk("Ouch, kerneld:msgsnd wants to sleep at interrupt!\n");
  98                         return -EINTR;
  99                 }
 100                 interruptible_sleep_on (&msq->wwait);
 101                 goto slept;
 102         }
 103         
 104         /* allocate message header and text space*/ 
 105         msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_USER);
 106         if (!msgh)
 107                 return -ENOMEM;
 108         msgh->msg_spot = (char *) (msgh + 1);
 109 
 110         /*
 111          * Calls from kernel level (IPC_KERNELD set)
 112          * have the message somewhere in kernel space already!
 113          */
 114         if (msgflg & IPC_KERNELD) {
 115                 struct kerneld_msg *kdmp = (struct kerneld_msg *)msgp;
 116 
 117                 /*
 118                  * Note that the kernel supplies a pointer
 119                  * but the user-level kerneld uses a char array...
 120                  */
 121                 memcpy(msgh->msg_spot, (char *)(&(kdmp->id)), sizeof(long)); 
 122                 memcpy(msgh->msg_spot + sizeof(long), kdmp->text,
 123                         msgsz - sizeof(long)); 
 124         }
 125         else
 126                 memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
 127         
 128         if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
 129                 || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
 130                 kfree(msgh);
 131                 return -EIDRM;
 132         }
 133 
 134         msgh->msg_next = NULL;
 135         if (!msq->msg_first)
 136                 msq->msg_first = msq->msg_last = msgh;
 137         else {
 138                 msq->msg_last->msg_next = msgh;
 139                 msq->msg_last = msgh;
 140         }
 141         msgh->msg_ts = msgsz;
 142         msgh->msg_type = mtype;
 143         msq->msg_cbytes += msgsz;
 144         msgbytes  += msgsz;
 145         msghdrs++;
 146         msq->msg_qnum++;
 147         msq->msg_lspid = current->pid;
 148         msq->msg_stime = CURRENT_TIME;
 149         if (msq->rwait)
 150                 wake_up (&msq->rwait);
 151         return 0;
 152 }
 153 
 154 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156         struct msqid_ds *msq;
 157         struct ipc_perm *ipcp;
 158         struct msg *tmsg, *leastp = NULL;
 159         struct msg *nmsg = NULL;
 160         int id, err;
 161 
 162         if (msqid < 0 || (long) msgsz < 0)
 163                 return -EINVAL;
 164         if (!msgp || !msgp->mtext)
 165             return -EFAULT;
 166         /*
 167          * Calls from kernel level (IPC_KERNELD set)
 168          * wants the message put in kernel space!
 169          */
 170         if ((msgflg & IPC_KERNELD) == 0) {
 171                 err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz);
 172                 if (err)
 173                         return err;
 174         }
 175 
 176         id = (unsigned int) msqid % MSGMNI;
 177         msq = msgque [id];
 178         if (msq == IPC_NOID || msq == IPC_UNUSED)
 179                 return -EINVAL;
 180         ipcp = &msq->msg_perm; 
 181 
 182         /* 
 183          *  find message of correct type.
 184          *  msgtyp = 0 => get first.
 185          *  msgtyp > 0 => get first message of matching type.
 186          *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
 187          */
 188         while (!nmsg) {
 189                 if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
 190                         return -EIDRM;
 191                 if ((msgflg & IPC_KERNELD) == 0)
 192                         /*
 193                          * Non-root processes may receive from kerneld! 
 194                          * i.e. no permission check if called from the kernel
 195                          * otoh we don't want user level non-root snoopers...
 196                          */
 197                 if (ipcperms (ipcp, S_IRUGO))
 198                         return -EACCES;
 199                 if (msgtyp == 0) 
 200                         nmsg = msq->msg_first;
 201                 else if (msgtyp > 0) {
 202                         if (msgflg & MSG_EXCEPT) { 
 203                                 for (tmsg = msq->msg_first; tmsg; 
 204                                      tmsg = tmsg->msg_next)
 205                                         if (tmsg->msg_type != msgtyp)
 206                                                 break;
 207                                 nmsg = tmsg;
 208                         } else {
 209                                 for (tmsg = msq->msg_first; tmsg; 
 210                                      tmsg = tmsg->msg_next)
 211                                         if (tmsg->msg_type == msgtyp)
 212                                                 break;
 213                                 nmsg = tmsg;
 214                         }
 215                 } else {
 216                         for (leastp = tmsg = msq->msg_first; tmsg; 
 217                              tmsg = tmsg->msg_next) 
 218                                 if (tmsg->msg_type < leastp->msg_type) 
 219                                         leastp = tmsg;
 220                         if (leastp && leastp->msg_type <= - msgtyp)
 221                                 nmsg = leastp;
 222                 }
 223                 
 224                 if (nmsg) { /* done finding a message */
 225                         if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
 226                                 return -E2BIG;
 227                         msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
 228                         if (nmsg ==  msq->msg_first)
 229                                 msq->msg_first = nmsg->msg_next;
 230                         else {
 231                                 for (tmsg = msq->msg_first; tmsg; 
 232                                      tmsg = tmsg->msg_next)
 233                                         if (tmsg->msg_next == nmsg) 
 234                                                 break;
 235                                 tmsg->msg_next = nmsg->msg_next;
 236                                 if (nmsg == msq->msg_last)
 237                                         msq->msg_last = tmsg;
 238                         }
 239                         if (!(--msq->msg_qnum))
 240                                 msq->msg_last = msq->msg_first = NULL;
 241                         
 242                         msq->msg_rtime = CURRENT_TIME;
 243                         msq->msg_lrpid = current->pid;
 244                         msgbytes -= nmsg->msg_ts; 
 245                         msghdrs--; 
 246                         msq->msg_cbytes -= nmsg->msg_ts;
 247                         if (msq->wwait)
 248                                 wake_up (&msq->wwait);
 249                         /*
 250                          * Calls from kernel level (IPC_KERNELD set)
 251                          * wants the message copied to kernel space!
 252                          */
 253                         if (msgflg & IPC_KERNELD) {
 254                                 struct kerneld_msg *kdmp = (struct kerneld_msg *) msgp;
 255 
 256                                 memcpy((char *)(&(kdmp->id)),
 257                                         nmsg->msg_spot,
 258                                         sizeof(long)); 
 259                                 /*
 260                                  * Note that kdmp->text is a pointer
 261                                  * when called from kernel space!
 262                                  */
 263                                 if ((msgsz > sizeof(long)) && kdmp->text)
 264                                         memcpy(kdmp->text,
 265                                                 nmsg->msg_spot + sizeof(long),
 266                                                 msgsz - sizeof(long)); 
 267                         }
 268                         else {
 269                                 put_user (nmsg->msg_type, &msgp->mtype);
 270                                 memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
 271                         }
 272                         kfree(nmsg);
 273                         return msgsz;
 274                 } else {  /* did not find a message */
 275                         if (msgflg & IPC_NOWAIT)
 276                                 return -ENOMSG;
 277                         if (current->signal & ~current->blocked)
 278                                 return -EINTR; 
 279                         if (intr_count) {
 280                                 /* Won't happen... */
 281                                 printk("Ouch, kerneld:msgrcv wants to sleep at interrupt!\n");
 282                                 return -EINTR;
 283                         }
 284                         interruptible_sleep_on (&msq->rwait);
 285                 }
 286         } /* end while */
 287         return -1;
 288 }
 289 
 290 asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         /* IPC_KERNELD is used as a marker for kernel calls */
 293         return real_msgsnd(msqid, msgp, msgsz, msgflg & ~IPC_KERNELD);
 294 }
 295 
 296 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
     /* [previous][next][first][last][top][bottom][index][help] */
 297         long msgtyp, int msgflg)
 298 {
 299         /* IPC_KERNELD is used as a marker for kernel calls */
 300         return real_msgrcv (msqid, msgp, msgsz, msgtyp, msgflg & ~IPC_KERNELD);
 301 }
 302 
 303 static int findkey (key_t key)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         int id;
 306         struct msqid_ds *msq;
 307         
 308         for (id = 0; id <= max_msqid; id++) {
 309                 while ((msq = msgque[id]) == IPC_NOID) 
 310                         interruptible_sleep_on (&msg_lock);
 311                 if (msq == IPC_UNUSED)
 312                         continue;
 313                 if (key == msq->msg_perm.key)
 314                         return id;
 315         }
 316         return -1;
 317 }
 318 
 319 static int newque (key_t key, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321         int id;
 322         struct msqid_ds *msq;
 323         struct ipc_perm *ipcp;
 324 
 325         for (id = 0; id < MSGMNI; id++) 
 326                 if (msgque[id] == IPC_UNUSED) {
 327                         msgque[id] = (struct msqid_ds *) IPC_NOID;
 328                         goto found;
 329                 }
 330         return -ENOSPC;
 331 
 332 found:
 333         msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL);
 334         if (!msq) {
 335                 msgque[id] = (struct msqid_ds *) IPC_UNUSED;
 336                 if (msg_lock)
 337                         wake_up (&msg_lock);
 338                 return -ENOMEM;
 339         }
 340         ipcp = &msq->msg_perm;
 341         ipcp->mode = (msgflg & S_IRWXUGO);
 342         ipcp->key = key;
 343         ipcp->cuid = ipcp->uid = current->euid;
 344         ipcp->gid = ipcp->cgid = current->egid;
 345         msq->msg_perm.seq = msg_seq;
 346         msq->msg_first = msq->msg_last = NULL;
 347         msq->rwait = msq->wwait = NULL;
 348         msq->msg_cbytes = msq->msg_qnum = 0;
 349         msq->msg_lspid = msq->msg_lrpid = 0;
 350         msq->msg_stime = msq->msg_rtime = 0;
 351         msq->msg_qbytes = MSGMNB;
 352         msq->msg_ctime = CURRENT_TIME;
 353         if (id > max_msqid)
 354                 max_msqid = id;
 355         msgque[id] = msq;
 356         used_queues++;
 357         if (msg_lock)
 358                 wake_up (&msg_lock);
 359         return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 360 }
 361 
 362 asmlinkage int sys_msgget (key_t key, int msgflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364         int id;
 365         struct msqid_ds *msq;
 366         
 367         /*
 368          * If the IPC_KERNELD flag is set, the key is forced to IPC_PRIVATE,
 369          * and a designated kerneld message queue is created/refered to
 370          */
 371         if ((msgflg & IPC_KERNELD)) {
 372                 if (!suser())
 373                         return -EPERM;
 374                 if ((kerneld_msqid == -1) && (kerneld_msqid =
 375                                 newque(IPC_PRIVATE, msgflg & S_IRWXU)) >= 0)
 376                         kerneld_pid = current->pid;
 377                 return kerneld_msqid;
 378         }
 379         /* else it is a "normal" request */
 380         if (key == IPC_PRIVATE) 
 381                 return newque(key, msgflg);
 382         if ((id = findkey (key)) == -1) { /* key not used */
 383                 if (!(msgflg & IPC_CREAT))
 384                         return -ENOENT;
 385                 return newque(key, msgflg);
 386         }
 387         if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
 388                 return -EEXIST;
 389         msq = msgque[id];
 390         if (msq == IPC_UNUSED || msq == IPC_NOID)
 391                 return -EIDRM;
 392         if (ipcperms(&msq->msg_perm, msgflg))
 393                 return -EACCES;
 394         return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 395 } 
 396 
 397 static void freeque (int id)
     /* [previous][next][first][last][top][bottom][index][help] */
 398 {
 399         struct msqid_ds *msq = msgque[id];
 400         struct msg *msgp, *msgh;
 401 
 402         msq->msg_perm.seq++;
 403         msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
 404         msgbytes -= msq->msg_cbytes;
 405         if (id == max_msqid)
 406                 while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
 407         msgque[id] = (struct msqid_ds *) IPC_UNUSED;
 408         used_queues--;
 409         while (msq->rwait || msq->wwait) {
 410                 if (msq->rwait)
 411                         wake_up (&msq->rwait); 
 412                 if (msq->wwait)
 413                         wake_up (&msq->wwait);
 414                 schedule(); 
 415         }
 416         for (msgp = msq->msg_first; msgp; msgp = msgh ) {
 417                 msgh = msgp->msg_next;
 418                 msghdrs--;
 419                 kfree(msgp);
 420         }
 421         kfree(msq);
 422 }
 423 
 424 asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426         int id, err;
 427         struct msqid_ds *msq;
 428         struct msqid_ds tbuf;
 429         struct ipc_perm *ipcp;
 430         
 431         if (msqid < 0 || cmd < 0)
 432                 return -EINVAL;
 433         switch (cmd) {
 434         case IPC_INFO: 
 435         case MSG_INFO: 
 436                 if (!buf)
 437                         return -EFAULT;
 438         { 
 439                 struct msginfo msginfo;
 440                 msginfo.msgmni = MSGMNI;
 441                 msginfo.msgmax = MSGMAX;
 442                 msginfo.msgmnb = MSGMNB;
 443                 msginfo.msgmap = MSGMAP;
 444                 msginfo.msgpool = MSGPOOL;
 445                 msginfo.msgtql = MSGTQL;
 446                 msginfo.msgssz = MSGSSZ;
 447                 msginfo.msgseg = MSGSEG;
 448                 if (cmd == MSG_INFO) {
 449                         msginfo.msgpool = used_queues;
 450                         msginfo.msgmap = msghdrs;
 451                         msginfo.msgtql = msgbytes;
 452                 }
 453                 err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo));
 454                 if (err)
 455                         return err;
 456                 memcpy_tofs (buf, &msginfo, sizeof(struct msginfo));
 457                 return max_msqid;
 458         }
 459         case MSG_STAT:
 460                 if (!buf)
 461                         return -EFAULT;
 462                 err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 463                 if (err)
 464                         return err;
 465                 if (msqid > max_msqid)
 466                         return -EINVAL;
 467                 msq = msgque[msqid];
 468                 if (msq == IPC_UNUSED || msq == IPC_NOID)
 469                         return -EINVAL;
 470                 if (ipcperms (&msq->msg_perm, S_IRUGO))
 471                         return -EACCES;
 472                 id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
 473                 tbuf.msg_perm   = msq->msg_perm;
 474                 tbuf.msg_stime  = msq->msg_stime;
 475                 tbuf.msg_rtime  = msq->msg_rtime;
 476                 tbuf.msg_ctime  = msq->msg_ctime;
 477                 tbuf.msg_cbytes = msq->msg_cbytes;
 478                 tbuf.msg_qnum   = msq->msg_qnum;
 479                 tbuf.msg_qbytes = msq->msg_qbytes;
 480                 tbuf.msg_lspid  = msq->msg_lspid;
 481                 tbuf.msg_lrpid  = msq->msg_lrpid;
 482                 memcpy_tofs (buf, &tbuf, sizeof(*buf));
 483                 return id;
 484         case IPC_SET:
 485                 if (!buf)
 486                         return -EFAULT;
 487                 err = verify_area (VERIFY_READ, buf, sizeof (*buf));
 488                 if (err)
 489                         return err;
 490                 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
 491                 break;
 492         case IPC_STAT:
 493                 if (!buf)
 494                         return -EFAULT;
 495                 err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
 496                 if (err)
 497                         return err;
 498                 break;
 499         }
 500 
 501         id = (unsigned int) msqid % MSGMNI;
 502         msq = msgque [id];
 503         if (msq == IPC_UNUSED || msq == IPC_NOID)
 504                 return -EINVAL;
 505         if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
 506                 return -EIDRM;
 507         ipcp = &msq->msg_perm;
 508 
 509         switch (cmd) {
 510         case IPC_STAT:
 511                 if (ipcperms (ipcp, S_IRUGO))
 512                         return -EACCES;
 513                 tbuf.msg_perm   = msq->msg_perm;
 514                 tbuf.msg_stime  = msq->msg_stime;
 515                 tbuf.msg_rtime  = msq->msg_rtime;
 516                 tbuf.msg_ctime  = msq->msg_ctime;
 517                 tbuf.msg_cbytes = msq->msg_cbytes;
 518                 tbuf.msg_qnum   = msq->msg_qnum;
 519                 tbuf.msg_qbytes = msq->msg_qbytes;
 520                 tbuf.msg_lspid  = msq->msg_lspid;
 521                 tbuf.msg_lrpid  = msq->msg_lrpid;
 522                 memcpy_tofs (buf, &tbuf, sizeof (*buf));
 523                 return 0;
 524         case IPC_SET:
 525                 if (!suser() && current->euid != ipcp->cuid && 
 526                     current->euid != ipcp->uid)
 527                         return -EPERM;
 528                 if (tbuf.msg_qbytes > MSGMNB && !suser())
 529                         return -EPERM;
 530                 msq->msg_qbytes = tbuf.msg_qbytes;
 531                 ipcp->uid = tbuf.msg_perm.uid;
 532                 ipcp->gid =  tbuf.msg_perm.gid;
 533                 ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
 534                         (S_IRWXUGO & tbuf.msg_perm.mode);
 535                 msq->msg_ctime = CURRENT_TIME;
 536                 return 0;
 537         case IPC_RMID:
 538                 if (!suser() && current->euid != ipcp->cuid && 
 539                     current->euid != ipcp->uid)
 540                         return -EPERM;
 541                 /*
 542                  * There is only one kerneld message queue,
 543                  * mark it as non-existant
 544                  */
 545                 if ((kerneld_msqid >= 0) && (msqid == kerneld_msqid))
 546                         kerneld_pid = kerneld_msqid = -1;
 547                 freeque (id); 
 548                 return 0;
 549         default:
 550                 return -EINVAL;
 551         }
 552 }
 553 
 554 /*
 555  * We do perhaps need a "flush" for waiting processes,
 556  * so that if they are terminated, a call from do_exit
 557  * will minimize the possibility of orphaned received
 558  * messages in the queue.  For now we just make sure
 559  * that the queue is shut down whenever kerneld dies.
 560  */
 561 void kerneld_exit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 562 {
 563         if ((current->pid == kerneld_pid) && (kerneld_msqid != -1))
 564                 sys_msgctl(kerneld_msqid, IPC_RMID, NULL);
 565 }
 566 
 567 /*
 568  * Kerneld internal message format/syntax:
 569  *
 570  * The message type from the kernel to kerneld is used to specify _what_
 571  * function we want kerneld to perform. 
 572  *
 573  * The "normal" message area is divided into a long, followed by a char array.
 574  * The long is used to hold the sequence number of the request, which will
 575  * be used as the return message type from kerneld back to the kernel.
 576  * In the return message, the long will be used to store the exit status
 577  * of the kerneld "job", or task.
 578  * The character array is used to pass parameters to kerneld and (optional)
 579  * return information from kerneld back to the kernel.
 580  * It is the responsibility of kerneld and the kernel level caller
 581  * to set usable sizes on the parameter/return value array, since
 582  * that information is _not_ included in the message format
 583  */
 584 
 585 /*
 586  * The basic kernel level entry point to kerneld.
 587  *      msgtype should correspond to a task type for (a) kerneld
 588  *      ret_size is the size of the (optional) return _value,
 589  *              OR-ed with KERNELD_WAIT if we want an answer
 590  *      msgsize is the size (in bytes) of the message, not including
 591  *              the long that is always sent first in a kerneld message
 592  *      text is the parameter for the kerneld specific task
 593  *      ret_val is NULL or the kernel address where an expected answer
 594  *              from kerneld should be placed.
 595  *
 596  * See <linux/kerneld.h> for usage (inline convenience functions)
 597  *
 598  */
 599 int kerneld_send(int msgtype, int ret_size, int msgsz,
     /* [previous][next][first][last][top][bottom][index][help] */
 600                 const char *text, const char *ret_val)
 601 {
 602         int status = -ENOSYS;
 603 #ifdef CONFIG_KERNELD
 604         static int id = KERNELD_MINSEQ;
 605         struct kerneld_msg kmsp = { msgtype, 0, (char *)text };
 606         int msgflg = S_IRUSR | S_IWUSR | IPC_KERNELD | MSG_NOERROR;
 607 
 608         msgsz += sizeof(long);
 609         if (ret_size & KERNELD_WAIT) {
 610                 if (++id <= 0)
 611                         id = KERNELD_MINSEQ;
 612                 kmsp.id = id;
 613         }
 614 
 615         if (kerneld_msqid == -1)
 616                 return -ENODEV;
 617 
 618         status = real_msgsnd(kerneld_msqid, (struct msgbuf *)&kmsp, msgsz, msgflg);
 619         if ((status >= 0) && (ret_size & KERNELD_WAIT)) {
 620                 ret_size &= ~KERNELD_WAIT;
 621                 if (intr_count) {
 622                         /*
 623                          * Do not wait for an answer at interrupt-time!
 624                          * OK, so fake it...
 625                          * If the kerneld request failed in user-space
 626                          * we will find out eventually, and retry again!
 627                          */
 628                         return 0; /* i.e. say that it worked... */
 629                 }
 630                 /* else */
 631                 kmsp.text = (char *)ret_val;
 632                 status = real_msgrcv(kerneld_msqid, (struct msgbuf *)&kmsp,
 633                                 sizeof(long) + ((ret_val)?ret_size:0),
 634                                 kmsp.id, msgflg);
 635                 if (status > 0) /* a valid answer contains at least a long */
 636                         status = kmsp.id;
 637         }
 638 
 639 #endif /* CONFIG_KERNELD */
 640         return status;
 641 }

/* [previous][next][first][last][top][bottom][index][help] */