diff options
author | Pavel Emelyanov <xemul@parallels.com> | 2011-12-14 21:45:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-16 13:48:28 -0500 |
commit | 5d3cae8bc39dd38d1aa5fd4bbc788c7b43fcaa71 (patch) | |
tree | 8d49e08b4887296b9230dd010ab1b435a7980d44 /net/unix | |
parent | 45a96b9be6ec1b7d248642d17ceee59ff5f64451 (diff) |
unix_diag: Dumping exact socket core
The socket inode is used as a key for lookup. This is effectively
the only really unique ID of a unix socket, but using this for
search currently has one problem -- it is O(number of sockets) :(
Does it worth fixing this lookup or inventing some other ID for
unix sockets?
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix')
-rw-r--r-- | net/unix/diag.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/net/unix/diag.c b/net/unix/diag.c index 86d85abf90c6..d7bd48c49ee5 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c | |||
@@ -89,11 +89,76 @@ done: | |||
89 | return skb->len; | 89 | return skb->len; |
90 | } | 90 | } |
91 | 91 | ||
92 | static struct sock *unix_lookup_by_ino(int ino) | ||
93 | { | ||
94 | int i; | ||
95 | struct sock *sk; | ||
96 | |||
97 | spin_lock(&unix_table_lock); | ||
98 | for (i = 0; i <= UNIX_HASH_SIZE; i++) { | ||
99 | struct hlist_node *node; | ||
100 | |||
101 | sk_for_each(sk, node, &unix_socket_table[i]) | ||
102 | if (ino == sock_i_ino(sk)) { | ||
103 | sock_hold(sk); | ||
104 | spin_unlock(&unix_table_lock); | ||
105 | |||
106 | return sk; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | spin_unlock(&unix_table_lock); | ||
111 | return NULL; | ||
112 | } | ||
113 | |||
92 | static int unix_diag_get_exact(struct sk_buff *in_skb, | 114 | static int unix_diag_get_exact(struct sk_buff *in_skb, |
93 | const struct nlmsghdr *nlh, | 115 | const struct nlmsghdr *nlh, |
94 | struct unix_diag_req *req) | 116 | struct unix_diag_req *req) |
95 | { | 117 | { |
96 | return -EAFNOSUPPORT; | 118 | int err = -EINVAL; |
119 | struct sock *sk; | ||
120 | struct sk_buff *rep; | ||
121 | unsigned int extra_len; | ||
122 | |||
123 | if (req->udiag_ino == 0) | ||
124 | goto out_nosk; | ||
125 | |||
126 | sk = unix_lookup_by_ino(req->udiag_ino); | ||
127 | err = -ENOENT; | ||
128 | if (sk == NULL) | ||
129 | goto out_nosk; | ||
130 | |||
131 | err = sock_diag_check_cookie(sk, req->udiag_cookie); | ||
132 | if (err) | ||
133 | goto out; | ||
134 | |||
135 | extra_len = 256; | ||
136 | again: | ||
137 | err = -ENOMEM; | ||
138 | rep = alloc_skb(NLMSG_SPACE((sizeof(struct unix_diag_msg) + extra_len)), | ||
139 | GFP_KERNEL); | ||
140 | if (!rep) | ||
141 | goto out; | ||
142 | |||
143 | err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).pid, | ||
144 | nlh->nlmsg_seq, 0, req->udiag_ino); | ||
145 | if (err < 0) { | ||
146 | kfree_skb(rep); | ||
147 | extra_len += 256; | ||
148 | if (extra_len >= PAGE_SIZE) | ||
149 | goto out; | ||
150 | |||
151 | goto again; | ||
152 | } | ||
153 | err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid, | ||
154 | MSG_DONTWAIT); | ||
155 | if (err > 0) | ||
156 | err = 0; | ||
157 | out: | ||
158 | if (sk) | ||
159 | sock_put(sk); | ||
160 | out_nosk: | ||
161 | return err; | ||
97 | } | 162 | } |
98 | 163 | ||
99 | static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) | 164 | static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) |