aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-01-30 17:12:06 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-30 17:13:49 -0500
commit905db44087855e3c1709f538ecdc22fd149cadd8 (patch)
tree645708af472fd26bb73b5cd6abe10640322a3b93
parent1974cc205e63cec4a17a6b3fca31fa4240ded77e (diff)
packet: Avoid lock_sock in mmap handler
As the mmap handler gets called under mmap_sem, and we may grab mmap_sem elsewhere under the socket lock to access user data, we should avoid grabbing the socket lock in the mmap handler. Since the only thing we care about in the mmap handler is for pg_vec* to be invariant, i.e., to exclude packet_set_ring, we can achieve this by simply using a new mutex. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Tested-by: Martin MOKREJŠ <mmokrejs@ribosome.natur.cuni.cz> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/packet/af_packet.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 5f94db2f3e9e..9454d4ae46df 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -77,6 +77,7 @@
77#include <linux/poll.h> 77#include <linux/poll.h>
78#include <linux/module.h> 78#include <linux/module.h>
79#include <linux/init.h> 79#include <linux/init.h>
80#include <linux/mutex.h>
80 81
81#ifdef CONFIG_INET 82#ifdef CONFIG_INET
82#include <net/inet_common.h> 83#include <net/inet_common.h>
@@ -175,6 +176,7 @@ struct packet_sock {
175#endif 176#endif
176 struct packet_type prot_hook; 177 struct packet_type prot_hook;
177 spinlock_t bind_lock; 178 spinlock_t bind_lock;
179 struct mutex pg_vec_lock;
178 unsigned int running:1, /* prot_hook is attached*/ 180 unsigned int running:1, /* prot_hook is attached*/
179 auxdata:1, 181 auxdata:1,
180 origdev:1; 182 origdev:1;
@@ -1069,6 +1071,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol)
1069 */ 1071 */
1070 1072
1071 spin_lock_init(&po->bind_lock); 1073 spin_lock_init(&po->bind_lock);
1074 mutex_init(&po->pg_vec_lock);
1072 po->prot_hook.func = packet_rcv; 1075 po->prot_hook.func = packet_rcv;
1073 1076
1074 if (sock->type == SOCK_PACKET) 1077 if (sock->type == SOCK_PACKET)
@@ -1865,6 +1868,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
1865 synchronize_net(); 1868 synchronize_net();
1866 1869
1867 err = -EBUSY; 1870 err = -EBUSY;
1871 mutex_lock(&po->pg_vec_lock);
1868 if (closing || atomic_read(&po->mapped) == 0) { 1872 if (closing || atomic_read(&po->mapped) == 0) {
1869 err = 0; 1873 err = 0;
1870#define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) 1874#define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; })
@@ -1886,6 +1890,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
1886 if (atomic_read(&po->mapped)) 1890 if (atomic_read(&po->mapped))
1887 printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped)); 1891 printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped));
1888 } 1892 }
1893 mutex_unlock(&po->pg_vec_lock);
1889 1894
1890 spin_lock(&po->bind_lock); 1895 spin_lock(&po->bind_lock);
1891 if (was_running && !po->running) { 1896 if (was_running && !po->running) {
@@ -1918,7 +1923,7 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st
1918 1923
1919 size = vma->vm_end - vma->vm_start; 1924 size = vma->vm_end - vma->vm_start;
1920 1925
1921 lock_sock(sk); 1926 mutex_lock(&po->pg_vec_lock);
1922 if (po->pg_vec == NULL) 1927 if (po->pg_vec == NULL)
1923 goto out; 1928 goto out;
1924 if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE) 1929 if (size != po->pg_vec_len*po->pg_vec_pages*PAGE_SIZE)
@@ -1941,7 +1946,7 @@ static int packet_mmap(struct file *file, struct socket *sock, struct vm_area_st
1941 err = 0; 1946 err = 0;
1942 1947
1943out: 1948out:
1944 release_sock(sk); 1949 mutex_unlock(&po->pg_vec_lock);
1945 return err; 1950 return err;
1946} 1951}
1947#endif 1952#endif