aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-03-08 15:21:04 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-03-08 15:21:04 -0500
commit988addf82e4c03739375279de73929580a2d4a6a (patch)
tree989ae1cd4e264bbad80c65f04480486246e7b9f3 /ipc/mqueue.c
parent004c1c7096659d352b83047a7593e91d8a30e3c5 (diff)
parent25cf84cf377c0aae5dbcf937ea89bc7893db5176 (diff)
Merge branch 'origin' into devel-stable
Conflicts: arch/arm/mach-mx2/devices.c arch/arm/mach-mx2/devices.h sound/soc/pxa/pxa-ssp.c
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c120
1 files changed, 72 insertions, 48 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c79bd57353e7..b6cb06451f4b 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -134,7 +134,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
134 init_waitqueue_head(&info->wait_q); 134 init_waitqueue_head(&info->wait_q);
135 INIT_LIST_HEAD(&info->e_wait_q[0].list); 135 INIT_LIST_HEAD(&info->e_wait_q[0].list);
136 INIT_LIST_HEAD(&info->e_wait_q[1].list); 136 INIT_LIST_HEAD(&info->e_wait_q[1].list);
137 info->messages = NULL;
138 info->notify_owner = NULL; 137 info->notify_owner = NULL;
139 info->qsize = 0; 138 info->qsize = 0;
140 info->user = NULL; /* set when all is ok */ 139 info->user = NULL; /* set when all is ok */
@@ -146,6 +145,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
146 info->attr.mq_msgsize = attr->mq_msgsize; 145 info->attr.mq_msgsize = attr->mq_msgsize;
147 } 146 }
148 mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); 147 mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
148 info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
149 if (!info->messages)
150 goto out_inode;
151
149 mq_bytes = (mq_msg_tblsz + 152 mq_bytes = (mq_msg_tblsz +
150 (info->attr.mq_maxmsg * info->attr.mq_msgsize)); 153 (info->attr.mq_maxmsg * info->attr.mq_msgsize));
151 154
@@ -154,18 +157,12 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
154 u->mq_bytes + mq_bytes > 157 u->mq_bytes + mq_bytes >
155 p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) { 158 p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
156 spin_unlock(&mq_lock); 159 spin_unlock(&mq_lock);
160 kfree(info->messages);
157 goto out_inode; 161 goto out_inode;
158 } 162 }
159 u->mq_bytes += mq_bytes; 163 u->mq_bytes += mq_bytes;
160 spin_unlock(&mq_lock); 164 spin_unlock(&mq_lock);
161 165
162 info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
163 if (!info->messages) {
164 spin_lock(&mq_lock);
165 u->mq_bytes -= mq_bytes;
166 spin_unlock(&mq_lock);
167 goto out_inode;
168 }
169 /* all is ok */ 166 /* all is ok */
170 info->user = get_uid(u); 167 info->user = get_uid(u);
171 } else if (S_ISDIR(mode)) { 168 } else if (S_ISDIR(mode)) {
@@ -187,7 +184,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
187{ 184{
188 struct inode *inode; 185 struct inode *inode;
189 struct ipc_namespace *ns = data; 186 struct ipc_namespace *ns = data;
190 int error = 0; 187 int error;
191 188
192 sb->s_blocksize = PAGE_CACHE_SIZE; 189 sb->s_blocksize = PAGE_CACHE_SIZE;
193 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 190 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -205,7 +202,9 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
205 if (!sb->s_root) { 202 if (!sb->s_root) {
206 iput(inode); 203 iput(inode);
207 error = -ENOMEM; 204 error = -ENOMEM;
205 goto out;
208 } 206 }
207 error = 0;
209 208
210out: 209out:
211 return error; 210 return error;
@@ -264,8 +263,9 @@ static void mqueue_delete_inode(struct inode *inode)
264 263
265 clear_inode(inode); 264 clear_inode(inode);
266 265
267 mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) + 266 /* Total amount of bytes accounted for the mqueue */
268 (info->attr.mq_maxmsg * info->attr.mq_msgsize)); 267 mq_bytes = info->attr.mq_maxmsg * (sizeof(struct msg_msg *)
268 + info->attr.mq_msgsize);
269 user = info->user; 269 user = info->user;
270 if (user) { 270 if (user) {
271 spin_lock(&mq_lock); 271 spin_lock(&mq_lock);
@@ -604,8 +604,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
604 /* check for overflow */ 604 /* check for overflow */
605 if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg) 605 if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
606 return 0; 606 return 0;
607 if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) + 607 if ((unsigned long)(attr->mq_maxmsg * (attr->mq_msgsize
608 (attr->mq_maxmsg * sizeof (struct msg_msg *)) < 608 + sizeof (struct msg_msg *))) <
609 (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize)) 609 (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
610 return 0; 610 return 0;
611 return 1; 611 return 1;
@@ -623,9 +623,10 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
623 int ret; 623 int ret;
624 624
625 if (attr) { 625 if (attr) {
626 ret = -EINVAL; 626 if (!mq_attr_ok(ipc_ns, attr)) {
627 if (!mq_attr_ok(ipc_ns, attr)) 627 ret = -EINVAL;
628 goto out; 628 goto out;
629 }
629 /* store for use during create */ 630 /* store for use during create */
630 dentry->d_fsdata = attr; 631 dentry->d_fsdata = attr;
631 } 632 }
@@ -659,24 +660,28 @@ out:
659static struct file *do_open(struct ipc_namespace *ipc_ns, 660static struct file *do_open(struct ipc_namespace *ipc_ns,
660 struct dentry *dentry, int oflag) 661 struct dentry *dentry, int oflag)
661{ 662{
663 int ret;
662 const struct cred *cred = current_cred(); 664 const struct cred *cred = current_cred();
663 665
664 static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, 666 static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
665 MAY_READ | MAY_WRITE }; 667 MAY_READ | MAY_WRITE };
666 668
667 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { 669 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
668 dput(dentry); 670 ret = -EINVAL;
669 mntput(ipc_ns->mq_mnt); 671 goto err;
670 return ERR_PTR(-EINVAL);
671 } 672 }
672 673
673 if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { 674 if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
674 dput(dentry); 675 ret = -EACCES;
675 mntput(ipc_ns->mq_mnt); 676 goto err;
676 return ERR_PTR(-EACCES);
677 } 677 }
678 678
679 return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); 679 return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
680
681err:
682 dput(dentry);
683 mntput(ipc_ns->mq_mnt);
684 return ERR_PTR(ret);
680} 685}
681 686
682SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, 687SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
@@ -705,16 +710,17 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
705 dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); 710 dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
706 if (IS_ERR(dentry)) { 711 if (IS_ERR(dentry)) {
707 error = PTR_ERR(dentry); 712 error = PTR_ERR(dentry);
708 goto out_err; 713 goto out_putfd;
709 } 714 }
710 mntget(ipc_ns->mq_mnt); 715 mntget(ipc_ns->mq_mnt);
711 716
712 if (oflag & O_CREAT) { 717 if (oflag & O_CREAT) {
713 if (dentry->d_inode) { /* entry already exists */ 718 if (dentry->d_inode) { /* entry already exists */
714 audit_inode(name, dentry); 719 audit_inode(name, dentry);
715 error = -EEXIST; 720 if (oflag & O_EXCL) {
716 if (oflag & O_EXCL) 721 error = -EEXIST;
717 goto out; 722 goto out;
723 }
718 filp = do_open(ipc_ns, dentry, oflag); 724 filp = do_open(ipc_ns, dentry, oflag);
719 } else { 725 } else {
720 filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, 726 filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root,
@@ -722,9 +728,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
722 u_attr ? &attr : NULL); 728 u_attr ? &attr : NULL);
723 } 729 }
724 } else { 730 } else {
725 error = -ENOENT; 731 if (!dentry->d_inode) {
726 if (!dentry->d_inode) 732 error = -ENOENT;
727 goto out; 733 goto out;
734 }
728 audit_inode(name, dentry); 735 audit_inode(name, dentry);
729 filp = do_open(ipc_ns, dentry, oflag); 736 filp = do_open(ipc_ns, dentry, oflag);
730 } 737 }
@@ -742,7 +749,6 @@ out:
742 mntput(ipc_ns->mq_mnt); 749 mntput(ipc_ns->mq_mnt);
743out_putfd: 750out_putfd:
744 put_unused_fd(fd); 751 put_unused_fd(fd);
745out_err:
746 fd = error; 752 fd = error;
747out_upsem: 753out_upsem:
748 mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); 754 mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
@@ -872,19 +878,24 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
872 audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); 878 audit_mq_sendrecv(mqdes, msg_len, msg_prio, p);
873 timeout = prepare_timeout(p); 879 timeout = prepare_timeout(p);
874 880
875 ret = -EBADF;
876 filp = fget(mqdes); 881 filp = fget(mqdes);
877 if (unlikely(!filp)) 882 if (unlikely(!filp)) {
883 ret = -EBADF;
878 goto out; 884 goto out;
885 }
879 886
880 inode = filp->f_path.dentry->d_inode; 887 inode = filp->f_path.dentry->d_inode;
881 if (unlikely(filp->f_op != &mqueue_file_operations)) 888 if (unlikely(filp->f_op != &mqueue_file_operations)) {
889 ret = -EBADF;
882 goto out_fput; 890 goto out_fput;
891 }
883 info = MQUEUE_I(inode); 892 info = MQUEUE_I(inode);
884 audit_inode(NULL, filp->f_path.dentry); 893 audit_inode(NULL, filp->f_path.dentry);
885 894
886 if (unlikely(!(filp->f_mode & FMODE_WRITE))) 895 if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
896 ret = -EBADF;
887 goto out_fput; 897 goto out_fput;
898 }
888 899
889 if (unlikely(msg_len > info->attr.mq_msgsize)) { 900 if (unlikely(msg_len > info->attr.mq_msgsize)) {
890 ret = -EMSGSIZE; 901 ret = -EMSGSIZE;
@@ -961,19 +972,24 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
961 audit_mq_sendrecv(mqdes, msg_len, 0, p); 972 audit_mq_sendrecv(mqdes, msg_len, 0, p);
962 timeout = prepare_timeout(p); 973 timeout = prepare_timeout(p);
963 974
964 ret = -EBADF;
965 filp = fget(mqdes); 975 filp = fget(mqdes);
966 if (unlikely(!filp)) 976 if (unlikely(!filp)) {
977 ret = -EBADF;
967 goto out; 978 goto out;
979 }
968 980
969 inode = filp->f_path.dentry->d_inode; 981 inode = filp->f_path.dentry->d_inode;
970 if (unlikely(filp->f_op != &mqueue_file_operations)) 982 if (unlikely(filp->f_op != &mqueue_file_operations)) {
983 ret = -EBADF;
971 goto out_fput; 984 goto out_fput;
985 }
972 info = MQUEUE_I(inode); 986 info = MQUEUE_I(inode);
973 audit_inode(NULL, filp->f_path.dentry); 987 audit_inode(NULL, filp->f_path.dentry);
974 988
975 if (unlikely(!(filp->f_mode & FMODE_READ))) 989 if (unlikely(!(filp->f_mode & FMODE_READ))) {
990 ret = -EBADF;
976 goto out_fput; 991 goto out_fput;
992 }
977 993
978 /* checks if buffer is big enough */ 994 /* checks if buffer is big enough */
979 if (unlikely(msg_len < info->attr.mq_msgsize)) { 995 if (unlikely(msg_len < info->attr.mq_msgsize)) {
@@ -1063,13 +1079,14 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1063 1079
1064 /* create the notify skb */ 1080 /* create the notify skb */
1065 nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL); 1081 nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL);
1066 ret = -ENOMEM; 1082 if (!nc) {
1067 if (!nc) 1083 ret = -ENOMEM;
1068 goto out; 1084 goto out;
1069 ret = -EFAULT; 1085 }
1070 if (copy_from_user(nc->data, 1086 if (copy_from_user(nc->data,
1071 notification.sigev_value.sival_ptr, 1087 notification.sigev_value.sival_ptr,
1072 NOTIFY_COOKIE_LEN)) { 1088 NOTIFY_COOKIE_LEN)) {
1089 ret = -EFAULT;
1073 goto out; 1090 goto out;
1074 } 1091 }
1075 1092
@@ -1078,9 +1095,10 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
1078 /* and attach it to the socket */ 1095 /* and attach it to the socket */
1079retry: 1096retry:
1080 filp = fget(notification.sigev_signo); 1097 filp = fget(notification.sigev_signo);
1081 ret = -EBADF; 1098 if (!filp) {
1082 if (!filp) 1099 ret = -EBADF;
1083 goto out; 1100 goto out;
1101 }
1084 sock = netlink_getsockbyfilp(filp); 1102 sock = netlink_getsockbyfilp(filp);
1085 fput(filp); 1103 fput(filp);
1086 if (IS_ERR(sock)) { 1104 if (IS_ERR(sock)) {
@@ -1092,7 +1110,7 @@ retry:
1092 timeo = MAX_SCHEDULE_TIMEOUT; 1110 timeo = MAX_SCHEDULE_TIMEOUT;
1093 ret = netlink_attachskb(sock, nc, &timeo, NULL); 1111 ret = netlink_attachskb(sock, nc, &timeo, NULL);
1094 if (ret == 1) 1112 if (ret == 1)
1095 goto retry; 1113 goto retry;
1096 if (ret) { 1114 if (ret) {
1097 sock = NULL; 1115 sock = NULL;
1098 nc = NULL; 1116 nc = NULL;
@@ -1101,14 +1119,17 @@ retry:
1101 } 1119 }
1102 } 1120 }
1103 1121
1104 ret = -EBADF;
1105 filp = fget(mqdes); 1122 filp = fget(mqdes);
1106 if (!filp) 1123 if (!filp) {
1124 ret = -EBADF;
1107 goto out; 1125 goto out;
1126 }
1108 1127
1109 inode = filp->f_path.dentry->d_inode; 1128 inode = filp->f_path.dentry->d_inode;
1110 if (unlikely(filp->f_op != &mqueue_file_operations)) 1129 if (unlikely(filp->f_op != &mqueue_file_operations)) {
1130 ret = -EBADF;
1111 goto out_fput; 1131 goto out_fput;
1132 }
1112 info = MQUEUE_I(inode); 1133 info = MQUEUE_I(inode);
1113 1134
1114 ret = 0; 1135 ret = 0;
@@ -1171,14 +1192,17 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
1171 return -EINVAL; 1192 return -EINVAL;
1172 } 1193 }
1173 1194
1174 ret = -EBADF;
1175 filp = fget(mqdes); 1195 filp = fget(mqdes);
1176 if (!filp) 1196 if (!filp) {
1197 ret = -EBADF;
1177 goto out; 1198 goto out;
1199 }
1178 1200
1179 inode = filp->f_path.dentry->d_inode; 1201 inode = filp->f_path.dentry->d_inode;
1180 if (unlikely(filp->f_op != &mqueue_file_operations)) 1202 if (unlikely(filp->f_op != &mqueue_file_operations)) {
1203 ret = -EBADF;
1181 goto out_fput; 1204 goto out_fput;
1205 }
1182 info = MQUEUE_I(inode); 1206 info = MQUEUE_I(inode);
1183 1207
1184 spin_lock(&info->lock); 1208 spin_lock(&info->lock);
@@ -1272,7 +1296,7 @@ static int __init init_mqueue_fs(void)
1272 if (mqueue_inode_cachep == NULL) 1296 if (mqueue_inode_cachep == NULL)
1273 return -ENOMEM; 1297 return -ENOMEM;
1274 1298
1275 /* ignore failues - they are not fatal */ 1299 /* ignore failures - they are not fatal */
1276 mq_sysctl_table = mq_register_sysctl_table(); 1300 mq_sysctl_table = mq_register_sysctl_table();
1277 1301
1278 error = register_filesystem(&mqueue_fs_type); 1302 error = register_filesystem(&mqueue_fs_type);