aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2012-09-03 02:26:33 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-09-03 02:26:33 -0400
commitc50e86ce7c2961a41f2f7aa6e4fd6c99229ba205 (patch)
tree4ea36009719bd8fc523239fe1bdccb90f0dce3ae /net/unix/af_unix.c
parent14d33d384693eb6083396199de516fdef320f7af (diff)
parent4cbe5a555fa58a79b6ecbb6c531b8bab0650778d (diff)
Merge tag 'v3.6-rc4'
Merge 3.6-rc4 to get latest OMAP and device tree fixes.
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c207
1 files changed, 107 insertions, 100 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 641f2e47f165..c5ee4ff61364 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
118struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; 118struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
119EXPORT_SYMBOL_GPL(unix_socket_table); 119EXPORT_SYMBOL_GPL(unix_socket_table);
120DEFINE_SPINLOCK(unix_table_lock); 120DEFINE_SPINLOCK(unix_table_lock);
121EXPORT_SYMBOL_GPL(unix_table_lock); 121EXPORT_SYMBOL_GPL(unix_table_lock);
122static atomic_long_t unix_nr_socks; 122static 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) 125static 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
129static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) 138static 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);
649out: 658out:
650 if (sk == NULL) 659 if (sk == NULL)
651 atomic_long_dec(&unix_nr_socks); 660 atomic_long_dec(&unix_nr_socks);
@@ -814,6 +823,34 @@ fail:
814 return NULL; 823 return NULL;
815} 824}
816 825
826static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
827{
828 struct dentry *dentry;
829 struct path path;
830 int err = 0;
831 /*
832 * Get the parent directory, calculate the hash for last
833 * component.
834 */
835 dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
836 err = PTR_ERR(dentry);
837 if (IS_ERR(dentry))
838 return err;
839
840 /*
841 * All right, let's create it.
842 */
843 err = security_path_mknod(&path, dentry, mode, 0);
844 if (!err) {
845 err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
846 if (!err) {
847 res->mnt = mntget(path.mnt);
848 res->dentry = dget(dentry);
849 }
850 }
851 done_path_create(&path, dentry);
852 return err;
853}
817 854
818static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 855static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
819{ 856{
@@ -822,8 +859,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
822 struct unix_sock *u = unix_sk(sk); 859 struct unix_sock *u = unix_sk(sk);
823 struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; 860 struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
824 char *sun_path = sunaddr->sun_path; 861 char *sun_path = sunaddr->sun_path;
825 struct dentry *dentry = NULL;
826 struct path path;
827 int err; 862 int err;
828 unsigned int hash; 863 unsigned int hash;
829 struct unix_address *addr; 864 struct unix_address *addr;
@@ -860,43 +895,23 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
860 atomic_set(&addr->refcnt, 1); 895 atomic_set(&addr->refcnt, 1);
861 896
862 if (sun_path[0]) { 897 if (sun_path[0]) {
863 umode_t mode; 898 struct path path;
864 err = 0; 899 umode_t mode = S_IFSOCK |
865 /*
866 * Get the parent directory, calculate the hash for last
867 * component.
868 */
869 dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
870 err = PTR_ERR(dentry);
871 if (IS_ERR(dentry))
872 goto out_mknod_parent;
873
874 /*
875 * All right, let's create it.
876 */
877 mode = S_IFSOCK |
878 (SOCK_INODE(sock)->i_mode & ~current_umask()); 900 (SOCK_INODE(sock)->i_mode & ~current_umask());
879 err = mnt_want_write(path.mnt); 901 err = unix_mknod(sun_path, mode, &path);
880 if (err) 902 if (err) {
881 goto out_mknod_dput; 903 if (err == -EEXIST)
882 err = security_path_mknod(&path, dentry, mode, 0); 904 err = -EADDRINUSE;
883 if (err) 905 unix_release_addr(addr);
884 goto out_mknod_drop_write; 906 goto out_up;
885 err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); 907 }
886out_mknod_drop_write:
887 mnt_drop_write(path.mnt);
888 if (err)
889 goto out_mknod_dput;
890 mutex_unlock(&path.dentry->d_inode->i_mutex);
891 dput(path.dentry);
892 path.dentry = dentry;
893
894 addr->hash = UNIX_HASH_SIZE; 908 addr->hash = UNIX_HASH_SIZE;
895 } 909 hash = path.dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1);
896 910 spin_lock(&unix_table_lock);
897 spin_lock(&unix_table_lock); 911 u->path = path;
898 912 list = &unix_socket_table[hash];
899 if (!sun_path[0]) { 913 } else {
914 spin_lock(&unix_table_lock);
900 err = -EADDRINUSE; 915 err = -EADDRINUSE;
901 if (__unix_find_socket_byname(net, sunaddr, addr_len, 916 if (__unix_find_socket_byname(net, sunaddr, addr_len,
902 sk->sk_type, hash)) { 917 sk->sk_type, hash)) {
@@ -905,9 +920,6 @@ out_mknod_drop_write:
905 } 920 }
906 921
907 list = &unix_socket_table[addr->hash]; 922 list = &unix_socket_table[addr->hash];
908 } else {
909 list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)];
910 u->path = path;
911 } 923 }
912 924
913 err = 0; 925 err = 0;
@@ -921,16 +933,6 @@ out_up:
921 mutex_unlock(&u->readlock); 933 mutex_unlock(&u->readlock);
922out: 934out:
923 return err; 935 return err;
924
925out_mknod_dput:
926 dput(dentry);
927 mutex_unlock(&path.dentry->d_inode->i_mutex);
928 path_put(&path);
929out_mknod_parent:
930 if (err == -EEXIST)
931 err = -EADDRINUSE;
932 unix_release_addr(addr);
933 goto out_up;
934} 936}
935 937
936static void unix_state_double_lock(struct sock *sk1, struct sock *sk2) 938static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
@@ -1448,7 +1450,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
1448 if (NULL == siocb->scm) 1450 if (NULL == siocb->scm)
1449 siocb->scm = &tmp_scm; 1451 siocb->scm = &tmp_scm;
1450 wait_for_unix_gc(); 1452 wait_for_unix_gc();
1451 err = scm_send(sock, msg, siocb->scm); 1453 err = scm_send(sock, msg, siocb->scm, false);
1452 if (err < 0) 1454 if (err < 0)
1453 return err; 1455 return err;
1454 1456
@@ -1617,7 +1619,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1617 if (NULL == siocb->scm) 1619 if (NULL == siocb->scm)
1618 siocb->scm = &tmp_scm; 1620 siocb->scm = &tmp_scm;
1619 wait_for_unix_gc(); 1621 wait_for_unix_gc();
1620 err = scm_send(sock, msg, siocb->scm); 1622 err = scm_send(sock, msg, siocb->scm, false);
1621 if (err < 0) 1623 if (err < 0)
1622 return err; 1624 return err;
1623 1625
@@ -2239,47 +2241,54 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
2239} 2241}
2240 2242
2241#ifdef CONFIG_PROC_FS 2243#ifdef CONFIG_PROC_FS
2242static struct sock *first_unix_socket(int *i) 2244
2245#define BUCKET_SPACE (BITS_PER_LONG - (UNIX_HASH_BITS + 1) - 1)
2246
2247#define get_bucket(x) ((x) >> BUCKET_SPACE)
2248#define get_offset(x) ((x) & ((1L << BUCKET_SPACE) - 1))
2249#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
2250
2251static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos)
2243{ 2252{
2244 for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) { 2253 unsigned long offset = get_offset(*pos);
2245 if (!hlist_empty(&unix_socket_table[*i])) 2254 unsigned long bucket = get_bucket(*pos);
2246 return __sk_head(&unix_socket_table[*i]); 2255 struct sock *sk;
2256 unsigned long count = 0;
2257
2258 for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) {
2259 if (sock_net(sk) != seq_file_net(seq))
2260 continue;
2261 if (++count == offset)
2262 break;
2247 } 2263 }
2248 return NULL; 2264
2265 return sk;
2249} 2266}
2250 2267
2251static struct sock *next_unix_socket(int *i, struct sock *s) 2268static struct sock *unix_next_socket(struct seq_file *seq,
2269 struct sock *sk,
2270 loff_t *pos)
2252{ 2271{
2253 struct sock *next = sk_next(s); 2272 unsigned long bucket;
2254 /* More in this chain? */ 2273
2255 if (next) 2274 while (sk > (struct sock *)SEQ_START_TOKEN) {
2256 return next; 2275 sk = sk_next(sk);
2257 /* Look for next non-empty chain. */ 2276 if (!sk)
2258 for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { 2277 goto next_bucket;
2259 if (!hlist_empty(&unix_socket_table[*i])) 2278 if (sock_net(sk) == seq_file_net(seq))
2260 return __sk_head(&unix_socket_table[*i]); 2279 return sk;
2261 } 2280 }
2262 return NULL;
2263}
2264 2281
2265struct unix_iter_state { 2282 do {
2266 struct seq_net_private p; 2283 sk = unix_from_bucket(seq, pos);
2267 int i; 2284 if (sk)
2268}; 2285 return sk;
2269 2286
2270static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos) 2287next_bucket:
2271{ 2288 bucket = get_bucket(*pos) + 1;
2272 struct unix_iter_state *iter = seq->private; 2289 *pos = set_bucket_offset(bucket, 1);
2273 loff_t off = 0; 2290 } while (bucket < ARRAY_SIZE(unix_socket_table));
2274 struct sock *s;
2275 2291
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; 2292 return NULL;
2284} 2293}
2285 2294
@@ -2287,22 +2296,20 @@ static void *unix_seq_start(struct seq_file *seq, loff_t *pos)
2287 __acquires(unix_table_lock) 2296 __acquires(unix_table_lock)
2288{ 2297{
2289 spin_lock(&unix_table_lock); 2298 spin_lock(&unix_table_lock);
2290 return *pos ? unix_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN; 2299
2300 if (!*pos)
2301 return SEQ_START_TOKEN;
2302
2303 if (get_bucket(*pos) >= ARRAY_SIZE(unix_socket_table))
2304 return NULL;
2305
2306 return unix_next_socket(seq, NULL, pos);
2291} 2307}
2292 2308
2293static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2309static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2294{ 2310{
2295 struct unix_iter_state *iter = seq->private;
2296 struct sock *sk = v;
2297 ++*pos; 2311 ++*pos;
2298 2312 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} 2313}
2307 2314
2308static void unix_seq_stop(struct seq_file *seq, void *v) 2315static void unix_seq_stop(struct seq_file *seq, void *v)
@@ -2365,7 +2372,7 @@ static const struct seq_operations unix_seq_ops = {
2365static int unix_seq_open(struct inode *inode, struct file *file) 2372static int unix_seq_open(struct inode *inode, struct file *file)
2366{ 2373{
2367 return seq_open_net(inode, file, &unix_seq_ops, 2374 return seq_open_net(inode, file, &unix_seq_ops,
2368 sizeof(struct unix_iter_state)); 2375 sizeof(struct seq_net_private));
2369} 2376}
2370 2377
2371static const struct file_operations unix_seq_fops = { 2378static const struct file_operations unix_seq_fops = {