diff options
author | NeilBrown <neilb@suse.de> | 2012-08-01 06:40:02 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2012-08-01 06:40:02 -0400 |
commit | bb181e2e48f8c85db08c9cb015cbba9618dbf05c (patch) | |
tree | 191bc24dd97bcb174535cc217af082f16da3b43d /net/unix/af_unix.c | |
parent | d57368afe63b3b7b45ce6c2b8c5276417935be2f (diff) | |
parent | c039c332f23e794deb6d6f37b9f07ff3b27fb2cf (diff) |
Merge commit 'c039c332f23e794deb6d6f37b9f07ff3b27fb2cf' into md
Pull in pre-requisites for adding raid10 support to dm-raid.
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 110 |
1 files changed, 62 insertions, 48 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 641f2e47f165..79981d97bc9c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -115,15 +115,24 @@ | |||
115 | #include <net/checksum.h> | 115 | #include <net/checksum.h> |
116 | #include <linux/security.h> | 116 | #include <linux/security.h> |
117 | 117 | ||
118 | struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; | 118 | struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; |
119 | EXPORT_SYMBOL_GPL(unix_socket_table); | 119 | EXPORT_SYMBOL_GPL(unix_socket_table); |
120 | DEFINE_SPINLOCK(unix_table_lock); | 120 | DEFINE_SPINLOCK(unix_table_lock); |
121 | EXPORT_SYMBOL_GPL(unix_table_lock); | 121 | EXPORT_SYMBOL_GPL(unix_table_lock); |
122 | static atomic_long_t unix_nr_socks; | 122 | static atomic_long_t unix_nr_socks; |
123 | 123 | ||
124 | #define unix_sockets_unbound (&unix_socket_table[UNIX_HASH_SIZE]) | ||
125 | 124 | ||
126 | #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE) | 125 | static struct hlist_head *unix_sockets_unbound(void *addr) |
126 | { | ||
127 | unsigned long hash = (unsigned long)addr; | ||
128 | |||
129 | hash ^= hash >> 16; | ||
130 | hash ^= hash >> 8; | ||
131 | hash %= UNIX_HASH_SIZE; | ||
132 | return &unix_socket_table[UNIX_HASH_SIZE + hash]; | ||
133 | } | ||
134 | |||
135 | #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash < UNIX_HASH_SIZE) | ||
127 | 136 | ||
128 | #ifdef CONFIG_SECURITY_NETWORK | 137 | #ifdef CONFIG_SECURITY_NETWORK |
129 | static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) | 138 | static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) |
@@ -645,7 +654,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) | |||
645 | INIT_LIST_HEAD(&u->link); | 654 | INIT_LIST_HEAD(&u->link); |
646 | mutex_init(&u->readlock); /* single task reading lock */ | 655 | mutex_init(&u->readlock); /* single task reading lock */ |
647 | init_waitqueue_head(&u->peer_wait); | 656 | init_waitqueue_head(&u->peer_wait); |
648 | unix_insert_socket(unix_sockets_unbound, sk); | 657 | unix_insert_socket(unix_sockets_unbound(sk), sk); |
649 | out: | 658 | out: |
650 | if (sk == NULL) | 659 | if (sk == NULL) |
651 | atomic_long_dec(&unix_nr_socks); | 660 | atomic_long_dec(&unix_nr_socks); |
@@ -2239,47 +2248,54 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, | |||
2239 | } | 2248 | } |
2240 | 2249 | ||
2241 | #ifdef CONFIG_PROC_FS | 2250 | #ifdef CONFIG_PROC_FS |
2242 | static struct sock *first_unix_socket(int *i) | 2251 | |
2252 | #define BUCKET_SPACE (BITS_PER_LONG - (UNIX_HASH_BITS + 1) - 1) | ||
2253 | |||
2254 | #define get_bucket(x) ((x) >> BUCKET_SPACE) | ||
2255 | #define get_offset(x) ((x) & ((1L << BUCKET_SPACE) - 1)) | ||
2256 | #define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o)) | ||
2257 | |||
2258 | static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos) | ||
2243 | { | 2259 | { |
2244 | for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) { | 2260 | unsigned long offset = get_offset(*pos); |
2245 | if (!hlist_empty(&unix_socket_table[*i])) | 2261 | unsigned long bucket = get_bucket(*pos); |
2246 | return __sk_head(&unix_socket_table[*i]); | 2262 | struct sock *sk; |
2263 | unsigned long count = 0; | ||
2264 | |||
2265 | for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) { | ||
2266 | if (sock_net(sk) != seq_file_net(seq)) | ||
2267 | continue; | ||
2268 | if (++count == offset) | ||
2269 | break; | ||
2247 | } | 2270 | } |
2248 | return NULL; | 2271 | |
2272 | return sk; | ||
2249 | } | 2273 | } |
2250 | 2274 | ||
2251 | static struct sock *next_unix_socket(int *i, struct sock *s) | 2275 | static struct sock *unix_next_socket(struct seq_file *seq, |
2276 | struct sock *sk, | ||
2277 | loff_t *pos) | ||
2252 | { | 2278 | { |
2253 | struct sock *next = sk_next(s); | 2279 | unsigned long bucket; |
2254 | /* More in this chain? */ | 2280 | |
2255 | if (next) | 2281 | while (sk > (struct sock *)SEQ_START_TOKEN) { |
2256 | return next; | 2282 | sk = sk_next(sk); |
2257 | /* Look for next non-empty chain. */ | 2283 | if (!sk) |
2258 | for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { | 2284 | goto next_bucket; |
2259 | if (!hlist_empty(&unix_socket_table[*i])) | 2285 | if (sock_net(sk) == seq_file_net(seq)) |
2260 | return __sk_head(&unix_socket_table[*i]); | 2286 | return sk; |
2261 | } | 2287 | } |
2262 | return NULL; | ||
2263 | } | ||
2264 | 2288 | ||
2265 | struct unix_iter_state { | 2289 | do { |
2266 | struct seq_net_private p; | 2290 | sk = unix_from_bucket(seq, pos); |
2267 | int i; | 2291 | if (sk) |
2268 | }; | 2292 | return sk; |
2269 | 2293 | ||
2270 | static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos) | 2294 | next_bucket: |
2271 | { | 2295 | bucket = get_bucket(*pos) + 1; |
2272 | struct unix_iter_state *iter = seq->private; | 2296 | *pos = set_bucket_offset(bucket, 1); |
2273 | loff_t off = 0; | 2297 | } while (bucket < ARRAY_SIZE(unix_socket_table)); |
2274 | struct sock *s; | ||
2275 | 2298 | ||
2276 | for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { | ||
2277 | if (sock_net(s) != seq_file_net(seq)) | ||
2278 | continue; | ||
2279 | if (off == pos) | ||
2280 | return s; | ||
2281 | ++off; | ||
2282 | } | ||
2283 | return NULL; | 2299 | return NULL; |
2284 | } | 2300 | } |
2285 | 2301 | ||
@@ -2287,22 +2303,20 @@ static void *unix_seq_start(struct seq_file *seq, loff_t *pos) | |||
2287 | __acquires(unix_table_lock) | 2303 | __acquires(unix_table_lock) |
2288 | { | 2304 | { |
2289 | spin_lock(&unix_table_lock); | 2305 | spin_lock(&unix_table_lock); |
2290 | return *pos ? unix_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 2306 | |
2307 | if (!*pos) | ||
2308 | return SEQ_START_TOKEN; | ||
2309 | |||
2310 | if (get_bucket(*pos) >= ARRAY_SIZE(unix_socket_table)) | ||
2311 | return NULL; | ||
2312 | |||
2313 | return unix_next_socket(seq, NULL, pos); | ||
2291 | } | 2314 | } |
2292 | 2315 | ||
2293 | static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2316 | static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2294 | { | 2317 | { |
2295 | struct unix_iter_state *iter = seq->private; | ||
2296 | struct sock *sk = v; | ||
2297 | ++*pos; | 2318 | ++*pos; |
2298 | 2319 | return unix_next_socket(seq, v, pos); | |
2299 | if (v == SEQ_START_TOKEN) | ||
2300 | sk = first_unix_socket(&iter->i); | ||
2301 | else | ||
2302 | sk = next_unix_socket(&iter->i, sk); | ||
2303 | while (sk && (sock_net(sk) != seq_file_net(seq))) | ||
2304 | sk = next_unix_socket(&iter->i, sk); | ||
2305 | return sk; | ||
2306 | } | 2320 | } |
2307 | 2321 | ||
2308 | static void unix_seq_stop(struct seq_file *seq, void *v) | 2322 | static void unix_seq_stop(struct seq_file *seq, void *v) |
@@ -2365,7 +2379,7 @@ static const struct seq_operations unix_seq_ops = { | |||
2365 | static int unix_seq_open(struct inode *inode, struct file *file) | 2379 | static int unix_seq_open(struct inode *inode, struct file *file) |
2366 | { | 2380 | { |
2367 | return seq_open_net(inode, file, &unix_seq_ops, | 2381 | return seq_open_net(inode, file, &unix_seq_ops, |
2368 | sizeof(struct unix_iter_state)); | 2382 | sizeof(struct seq_net_private)); |
2369 | } | 2383 | } |
2370 | 2384 | ||
2371 | static const struct file_operations unix_seq_fops = { | 2385 | static const struct file_operations unix_seq_fops = { |