aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
authorAlexander Viro <aviro@redhat.com>2006-01-14 15:29:55 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-14 15:38:17 -0500
commit7c7dce9209161eb260cdf9e9172f72c3a02379e6 (patch)
tree81135190b6aadfc9126dcbff63710cd97fe5b6a1 /ipc/mqueue.c
parent12dbf3fc4d06d2c0c4c44dc0612df04248b3cfd3 (diff)
[PATCH] Fix double decrement of mqueue_mnt->mnt_count in sys_mq_open
Fixed the refcounting on failure exits in sys_mq_open() and cleaned the logics up. Rules are actually pretty simple - dentry_open() expects vfsmount and dentry to be pinned down and it either transfers them into created struct file or drops them. Old code had been very confused in that area - if dentry_open() had failed either in do_open() or do_create(), we ended up dentry and mqueue_mnt dropped twice, once by dentry_open() cleanup and then by sys_mq_open(). Fix consists of making the rules for do_create() and do_open() same as for dentry_open() and updating the sys_mq_open() accordingly; that actually leads to more straightforward code and less work on normal path. Signed-off-by: Al Viro <aviro@redhat.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c59
1 files changed, 33 insertions, 26 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4e776f9c80e7..59302fc3643b 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -599,15 +599,16 @@ static int mq_attr_ok(struct mq_attr *attr)
599static struct file *do_create(struct dentry *dir, struct dentry *dentry, 599static struct file *do_create(struct dentry *dir, struct dentry *dentry,
600 int oflag, mode_t mode, struct mq_attr __user *u_attr) 600 int oflag, mode_t mode, struct mq_attr __user *u_attr)
601{ 601{
602 struct file *filp;
603 struct mq_attr attr; 602 struct mq_attr attr;
604 int ret; 603 int ret;
605 604
606 if (u_attr != NULL) { 605 if (u_attr) {
606 ret = -EFAULT;
607 if (copy_from_user(&attr, u_attr, sizeof(attr))) 607 if (copy_from_user(&attr, u_attr, sizeof(attr)))
608 return ERR_PTR(-EFAULT); 608 goto out;
609 ret = -EINVAL;
609 if (!mq_attr_ok(&attr)) 610 if (!mq_attr_ok(&attr))
610 return ERR_PTR(-EINVAL); 611 goto out;
611 /* store for use during create */ 612 /* store for use during create */
612 dentry->d_fsdata = &attr; 613 dentry->d_fsdata = &attr;
613 } 614 }
@@ -616,13 +617,14 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
616 ret = vfs_create(dir->d_inode, dentry, mode, NULL); 617 ret = vfs_create(dir->d_inode, dentry, mode, NULL);
617 dentry->d_fsdata = NULL; 618 dentry->d_fsdata = NULL;
618 if (ret) 619 if (ret)
619 return ERR_PTR(ret); 620 goto out;
620 621
621 filp = dentry_open(dentry, mqueue_mnt, oflag); 622 return dentry_open(dentry, mqueue_mnt, oflag);
622 if (!IS_ERR(filp))
623 dget(dentry);
624 623
625 return filp; 624out:
625 dput(dentry);
626 mntput(mqueue_mnt);
627 return ERR_PTR(ret);
626} 628}
627 629
628/* Opens existing queue */ 630/* Opens existing queue */
@@ -630,20 +632,20 @@ static struct file *do_open(struct dentry *dentry, int oflag)
630{ 632{
631static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, 633static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
632 MAY_READ | MAY_WRITE }; 634 MAY_READ | MAY_WRITE };
633 struct file *filp;
634 635
635 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) 636 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
637 dput(dentry);
638 mntput(mqueue_mnt);
636 return ERR_PTR(-EINVAL); 639 return ERR_PTR(-EINVAL);
640 }
637 641
638 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);
639 return ERR_PTR(-EACCES); 645 return ERR_PTR(-EACCES);
646 }
640 647
641 filp = dentry_open(dentry, mqueue_mnt, oflag); 648 return dentry_open(dentry, mqueue_mnt, oflag);
642
643 if (!IS_ERR(filp))
644 dget(dentry);
645
646 return filp;
647} 649}
648 650
649asmlinkage 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,
@@ -671,17 +673,20 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
671 673
672 if (oflag & O_CREAT) { 674 if (oflag & O_CREAT) {
673 if (dentry->d_inode) { /* entry already exists */ 675 if (dentry->d_inode) { /* entry already exists */
674 filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) : 676 error = -EEXIST;
675 do_open(dentry, oflag); 677 if (oflag & O_EXCL)
678 goto out;
679 filp = do_open(dentry, oflag);
676 } else { 680 } else {
677 filp = do_create(mqueue_mnt->mnt_root, dentry, 681 filp = do_create(mqueue_mnt->mnt_root, dentry,
678 oflag, mode, u_attr); 682 oflag, mode, u_attr);
679 } 683 }
680 } else 684 } else {
681 filp = (dentry->d_inode) ? do_open(dentry, oflag) : 685 error = -ENOENT;
682 ERR_PTR(-ENOENT); 686 if (!dentry->d_inode)
683 687 goto out;
684 dput(dentry); 688 filp = do_open(dentry, oflag);
689 }
685 690
686 if (IS_ERR(filp)) { 691 if (IS_ERR(filp)) {
687 error = PTR_ERR(filp); 692 error = PTR_ERR(filp);
@@ -692,8 +697,10 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
692 fd_install(fd, filp); 697 fd_install(fd, filp);
693 goto out_upsem; 698 goto out_upsem;
694 699
695out_putfd: 700out:
701 dput(dentry);
696 mntput(mqueue_mnt); 702 mntput(mqueue_mnt);
703out_putfd:
697 put_unused_fd(fd); 704 put_unused_fd(fd);
698out_err: 705out_err:
699 fd = error; 706 fd = error;