aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c68
1 files changed, 38 insertions, 30 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c8943b53d8e6..59302fc3643b 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -11,6 +11,7 @@
11 * This file is released under the GPL. 11 * This file is released under the GPL.
12 */ 12 */
13 13
14#include <linux/capability.h>
14#include <linux/init.h> 15#include <linux/init.h>
15#include <linux/pagemap.h> 16#include <linux/pagemap.h>
16#include <linux/file.h> 17#include <linux/file.h>
@@ -598,15 +599,16 @@ static int mq_attr_ok(struct mq_attr *attr)
598static struct file *do_create(struct dentry *dir, struct dentry *dentry, 599static struct file *do_create(struct dentry *dir, struct dentry *dentry,
599 int oflag, mode_t mode, struct mq_attr __user *u_attr) 600 int oflag, mode_t mode, struct mq_attr __user *u_attr)
600{ 601{
601 struct file *filp;
602 struct mq_attr attr; 602 struct mq_attr attr;
603 int ret; 603 int ret;
604 604
605 if (u_attr != NULL) { 605 if (u_attr) {
606 ret = -EFAULT;
606 if (copy_from_user(&attr, u_attr, sizeof(attr))) 607 if (copy_from_user(&attr, u_attr, sizeof(attr)))
607 return ERR_PTR(-EFAULT); 608 goto out;
609 ret = -EINVAL;
608 if (!mq_attr_ok(&attr)) 610 if (!mq_attr_ok(&attr))
609 return ERR_PTR(-EINVAL); 611 goto out;
610 /* store for use during create */ 612 /* store for use during create */
611 dentry->d_fsdata = &attr; 613 dentry->d_fsdata = &attr;
612 } 614 }
@@ -615,13 +617,14 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
615 ret = vfs_create(dir->d_inode, dentry, mode, NULL); 617 ret = vfs_create(dir->d_inode, dentry, mode, NULL);
616 dentry->d_fsdata = NULL; 618 dentry->d_fsdata = NULL;
617 if (ret) 619 if (ret)
618 return ERR_PTR(ret); 620 goto out;
619 621
620 filp = dentry_open(dentry, mqueue_mnt, oflag); 622 return dentry_open(dentry, mqueue_mnt, oflag);
621 if (!IS_ERR(filp))
622 dget(dentry);
623 623
624 return filp; 624out:
625 dput(dentry);
626 mntput(mqueue_mnt);
627 return ERR_PTR(ret);
625} 628}
626 629
627/* Opens existing queue */ 630/* Opens existing queue */
@@ -629,20 +632,20 @@ static struct file *do_open(struct dentry *dentry, int oflag)
629{ 632{
630static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, 633static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
631 MAY_READ | MAY_WRITE }; 634 MAY_READ | MAY_WRITE };
632 struct file *filp;
633 635
634 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) 636 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
637 dput(dentry);
638 mntput(mqueue_mnt);
635 return ERR_PTR(-EINVAL); 639 return ERR_PTR(-EINVAL);
640 }
636 641
637 if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) 642 if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
643 dput(dentry);
644 mntput(mqueue_mnt);
638 return ERR_PTR(-EACCES); 645 return ERR_PTR(-EACCES);
646 }
639 647
640 filp = dentry_open(dentry, mqueue_mnt, oflag); 648 return dentry_open(dentry, mqueue_mnt, oflag);
641
642 if (!IS_ERR(filp))
643 dget(dentry);
644
645 return filp;
646} 649}
647 650
648asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, 651asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
@@ -660,7 +663,7 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
660 if (fd < 0) 663 if (fd < 0)
661 goto out_putname; 664 goto out_putname;
662 665
663 down(&mqueue_mnt->mnt_root->d_inode->i_sem); 666 mutex_lock(&mqueue_mnt->mnt_root->d_inode->i_mutex);
664 dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); 667 dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name));
665 if (IS_ERR(dentry)) { 668 if (IS_ERR(dentry)) {
666 error = PTR_ERR(dentry); 669 error = PTR_ERR(dentry);
@@ -670,17 +673,20 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
670 673
671 if (oflag & O_CREAT) { 674 if (oflag & O_CREAT) {
672 if (dentry->d_inode) { /* entry already exists */ 675 if (dentry->d_inode) { /* entry already exists */
673 filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) : 676 error = -EEXIST;
674 do_open(dentry, oflag); 677 if (oflag & O_EXCL)
678 goto out;
679 filp = do_open(dentry, oflag);
675 } else { 680 } else {
676 filp = do_create(mqueue_mnt->mnt_root, dentry, 681 filp = do_create(mqueue_mnt->mnt_root, dentry,
677 oflag, mode, u_attr); 682 oflag, mode, u_attr);
678 } 683 }
679 } else 684 } else {
680 filp = (dentry->d_inode) ? do_open(dentry, oflag) : 685 error = -ENOENT;
681 ERR_PTR(-ENOENT); 686 if (!dentry->d_inode)
682 687 goto out;
683 dput(dentry); 688 filp = do_open(dentry, oflag);
689 }
684 690
685 if (IS_ERR(filp)) { 691 if (IS_ERR(filp)) {
686 error = PTR_ERR(filp); 692 error = PTR_ERR(filp);
@@ -691,13 +697,15 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
691 fd_install(fd, filp); 697 fd_install(fd, filp);
692 goto out_upsem; 698 goto out_upsem;
693 699
694out_putfd: 700out:
701 dput(dentry);
695 mntput(mqueue_mnt); 702 mntput(mqueue_mnt);
703out_putfd:
696 put_unused_fd(fd); 704 put_unused_fd(fd);
697out_err: 705out_err:
698 fd = error; 706 fd = error;
699out_upsem: 707out_upsem:
700 up(&mqueue_mnt->mnt_root->d_inode->i_sem); 708 mutex_unlock(&mqueue_mnt->mnt_root->d_inode->i_mutex);
701out_putname: 709out_putname:
702 putname(name); 710 putname(name);
703 return fd; 711 return fd;
@@ -714,7 +722,7 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
714 if (IS_ERR(name)) 722 if (IS_ERR(name))
715 return PTR_ERR(name); 723 return PTR_ERR(name);
716 724
717 down(&mqueue_mnt->mnt_root->d_inode->i_sem); 725 mutex_lock(&mqueue_mnt->mnt_root->d_inode->i_mutex);
718 dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); 726 dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name));
719 if (IS_ERR(dentry)) { 727 if (IS_ERR(dentry)) {
720 err = PTR_ERR(dentry); 728 err = PTR_ERR(dentry);
@@ -735,7 +743,7 @@ out_err:
735 dput(dentry); 743 dput(dentry);
736 744
737out_unlock: 745out_unlock:
738 up(&mqueue_mnt->mnt_root->d_inode->i_sem); 746 mutex_unlock(&mqueue_mnt->mnt_root->d_inode->i_mutex);
739 putname(name); 747 putname(name);
740 if (inode) 748 if (inode)
741 iput(inode); 749 iput(inode);