Commit 3253b669 authored by Stefan Richter's avatar Stefan Richter

ieee1394: raw1394: arm functions slept in atomic context

Sleeping functions like copy_to_user were accessed inside spinlocks in
raw1394's arm_register, arm_unregister, arm_get_buf, arm_set_buf.
http://bugzilla.kernel.org/show_bug.cgi?id=7120Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
Tested-by: default avatarDavid Trent <DTrent@piacton.com>
(cherry picked from e575953ec17c3f5c1e738847d2d16c241bb99783 commit)
parent 91925175
...@@ -1774,6 +1774,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req) ...@@ -1774,6 +1774,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
addr->notification_options |= addr->client_transactions; addr->notification_options |= addr->client_transactions;
addr->recvb = req->req.recvb; addr->recvb = req->req.recvb;
addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF); addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
spin_lock_irqsave(&host_info_lock, flags); spin_lock_irqsave(&host_info_lock, flags);
hi = find_host_info(fi->host); hi = find_host_info(fi->host);
same_host = 0; same_host = 0;
...@@ -1799,9 +1800,9 @@ static int arm_register(struct file_info *fi, struct pending_request *req) ...@@ -1799,9 +1800,9 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
} }
if (same_host) { if (same_host) {
/* addressrange occupied by same host */ /* addressrange occupied by same host */
spin_unlock_irqrestore(&host_info_lock, flags);
vfree(addr->addr_space_buffer); vfree(addr->addr_space_buffer);
kfree(addr); kfree(addr);
spin_unlock_irqrestore(&host_info_lock, flags);
return (-EALREADY); return (-EALREADY);
} }
/* another host with valid address-entry containing same addressrange */ /* another host with valid address-entry containing same addressrange */
...@@ -1829,6 +1830,8 @@ static int arm_register(struct file_info *fi, struct pending_request *req) ...@@ -1829,6 +1830,8 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
} }
} }
} }
spin_unlock_irqrestore(&host_info_lock, flags);
if (another_host) { if (another_host) {
DBGMSG("another hosts entry is valid -> SUCCESS"); DBGMSG("another hosts entry is valid -> SUCCESS");
if (copy_to_user(int2ptr(req->req.recvb), if (copy_to_user(int2ptr(req->req.recvb),
...@@ -1837,11 +1840,11 @@ static int arm_register(struct file_info *fi, struct pending_request *req) ...@@ -1837,11 +1840,11 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
" address-range-entry is invalid -> EFAULT !!!\n"); " address-range-entry is invalid -> EFAULT !!!\n");
vfree(addr->addr_space_buffer); vfree(addr->addr_space_buffer);
kfree(addr); kfree(addr);
spin_unlock_irqrestore(&host_info_lock, flags);
return (-EFAULT); return (-EFAULT);
} }
free_pending_request(req); /* immediate success or fail */ free_pending_request(req); /* immediate success or fail */
/* INSERT ENTRY */ /* INSERT ENTRY */
spin_lock_irqsave(&host_info_lock, flags);
list_add_tail(&addr->addr_list, &fi->addr_list); list_add_tail(&addr->addr_list, &fi->addr_list);
spin_unlock_irqrestore(&host_info_lock, flags); spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request); return sizeof(struct raw1394_request);
...@@ -1852,15 +1855,15 @@ static int arm_register(struct file_info *fi, struct pending_request *req) ...@@ -1852,15 +1855,15 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
req->req.address + req->req.length); req->req.address + req->req.length);
if (retval) { if (retval) {
/* INSERT ENTRY */ /* INSERT ENTRY */
spin_lock_irqsave(&host_info_lock, flags);
list_add_tail(&addr->addr_list, &fi->addr_list); list_add_tail(&addr->addr_list, &fi->addr_list);
spin_unlock_irqrestore(&host_info_lock, flags);
} else { } else {
DBGMSG("arm_register failed errno: %d \n", retval); DBGMSG("arm_register failed errno: %d \n", retval);
vfree(addr->addr_space_buffer); vfree(addr->addr_space_buffer);
kfree(addr); kfree(addr);
spin_unlock_irqrestore(&host_info_lock, flags);
return (-EALREADY); return (-EALREADY);
} }
spin_unlock_irqrestore(&host_info_lock, flags);
free_pending_request(req); /* immediate success or fail */ free_pending_request(req); /* immediate success or fail */
return sizeof(struct raw1394_request); return sizeof(struct raw1394_request);
} }
...@@ -1926,10 +1929,10 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req) ...@@ -1926,10 +1929,10 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
if (another_host) { if (another_host) {
DBGMSG("delete entry from list -> success"); DBGMSG("delete entry from list -> success");
list_del(&addr->addr_list); list_del(&addr->addr_list);
spin_unlock_irqrestore(&host_info_lock, flags);
vfree(addr->addr_space_buffer); vfree(addr->addr_space_buffer);
kfree(addr); kfree(addr);
free_pending_request(req); /* immediate success or fail */ free_pending_request(req); /* immediate success or fail */
spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request); return sizeof(struct raw1394_request);
} }
retval = retval =
...@@ -1971,23 +1974,19 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req) ...@@ -1971,23 +1974,19 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req)
(arm_addr->end > req->req.address)) { (arm_addr->end > req->req.address)) {
if (req->req.address + req->req.length <= arm_addr->end) { if (req->req.address + req->req.length <= arm_addr->end) {
offset = req->req.address - arm_addr->start; offset = req->req.address - arm_addr->start;
spin_unlock_irqrestore(&host_info_lock, flags);
DBGMSG DBGMSG
("arm_get_buf copy_to_user( %08X, %p, %u )", ("arm_get_buf copy_to_user( %08X, %p, %u )",
(u32) req->req.recvb, (u32) req->req.recvb,
arm_addr->addr_space_buffer + offset, arm_addr->addr_space_buffer + offset,
(u32) req->req.length); (u32) req->req.length);
if (copy_to_user if (copy_to_user
(int2ptr(req->req.recvb), (int2ptr(req->req.recvb),
arm_addr->addr_space_buffer + offset, arm_addr->addr_space_buffer + offset,
req->req.length)) { req->req.length))
spin_unlock_irqrestore(&host_info_lock,
flags);
return (-EFAULT); return (-EFAULT);
}
spin_unlock_irqrestore(&host_info_lock, flags);
/* We have to free the request, because we /* We have to free the request, because we
* queue no response, and therefore nobody * queue no response, and therefore nobody
* will free it. */ * will free it. */
...@@ -2027,24 +2026,23 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req) ...@@ -2027,24 +2026,23 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req)
(arm_addr->end > req->req.address)) { (arm_addr->end > req->req.address)) {
if (req->req.address + req->req.length <= arm_addr->end) { if (req->req.address + req->req.length <= arm_addr->end) {
offset = req->req.address - arm_addr->start; offset = req->req.address - arm_addr->start;
spin_unlock_irqrestore(&host_info_lock, flags);
DBGMSG DBGMSG
("arm_set_buf copy_from_user( %p, %08X, %u )", ("arm_set_buf copy_from_user( %p, %08X, %u )",
arm_addr->addr_space_buffer + offset, arm_addr->addr_space_buffer + offset,
(u32) req->req.sendb, (u32) req->req.sendb,
(u32) req->req.length); (u32) req->req.length);
if (copy_from_user if (copy_from_user
(arm_addr->addr_space_buffer + offset, (arm_addr->addr_space_buffer + offset,
int2ptr(req->req.sendb), int2ptr(req->req.sendb),
req->req.length)) { req->req.length))
spin_unlock_irqrestore(&host_info_lock,
flags);
return (-EFAULT); return (-EFAULT);
}
spin_unlock_irqrestore(&host_info_lock, flags); /* We have to free the request, because we
free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ * queue no response, and therefore nobody
* will free it. */
free_pending_request(req);
return sizeof(struct raw1394_request); return sizeof(struct raw1394_request);
} else { } else {
DBGMSG("arm_set_buf request exceeded mapping"); DBGMSG("arm_set_buf request exceeded mapping");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment