diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/net/socket.c b/net/socket.c index 3ca2fd9e3720..ccc576a6a508 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -156,7 +156,7 @@ static const struct file_operations socket_file_ops = { | |||
156 | */ | 156 | */ |
157 | 157 | ||
158 | static DEFINE_SPINLOCK(net_family_lock); | 158 | static DEFINE_SPINLOCK(net_family_lock); |
159 | static const struct net_proto_family *net_families[NPROTO] __read_mostly; | 159 | static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly; |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Statistics counters of the socket lists | 162 | * Statistics counters of the socket lists |
@@ -262,6 +262,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb) | |||
262 | } | 262 | } |
263 | 263 | ||
264 | 264 | ||
265 | |||
265 | static void wq_free_rcu(struct rcu_head *head) | 266 | static void wq_free_rcu(struct rcu_head *head) |
266 | { | 267 | { |
267 | struct socket_wq *wq = container_of(head, struct socket_wq, rcu); | 268 | struct socket_wq *wq = container_of(head, struct socket_wq, rcu); |
@@ -360,14 +361,14 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags) | |||
360 | if (unlikely(fd < 0)) | 361 | if (unlikely(fd < 0)) |
361 | return fd; | 362 | return fd; |
362 | 363 | ||
363 | path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); | 364 | path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); |
364 | if (unlikely(!path.dentry)) { | 365 | if (unlikely(!path.dentry)) { |
365 | put_unused_fd(fd); | 366 | put_unused_fd(fd); |
366 | return -ENOMEM; | 367 | return -ENOMEM; |
367 | } | 368 | } |
368 | path.mnt = mntget(sock_mnt); | 369 | path.mnt = mntget(sock_mnt); |
369 | 370 | ||
370 | path.dentry->d_op = &sockfs_dentry_operations; | 371 | d_set_d_op(path.dentry, &sockfs_dentry_operations); |
371 | d_instantiate(path.dentry, SOCK_INODE(sock)); | 372 | d_instantiate(path.dentry, SOCK_INODE(sock)); |
372 | SOCK_INODE(sock)->i_fop = &socket_file_ops; | 373 | SOCK_INODE(sock)->i_fop = &socket_file_ops; |
373 | 374 | ||
@@ -732,6 +733,21 @@ static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, | |||
732 | return ret; | 733 | return ret; |
733 | } | 734 | } |
734 | 735 | ||
736 | /** | ||
737 | * kernel_recvmsg - Receive a message from a socket (kernel space) | ||
738 | * @sock: The socket to receive the message from | ||
739 | * @msg: Received message | ||
740 | * @vec: Input s/g array for message data | ||
741 | * @num: Size of input s/g array | ||
742 | * @size: Number of bytes to read | ||
743 | * @flags: Message flags (MSG_DONTWAIT, etc...) | ||
744 | * | ||
745 | * On return the msg structure contains the scatter/gather array passed in the | ||
746 | * vec argument. The array is modified so that it consists of the unfilled | ||
747 | * portion of the original array. | ||
748 | * | ||
749 | * The returned value is the total number of bytes received, or an error. | ||
750 | */ | ||
735 | int kernel_recvmsg(struct socket *sock, struct msghdr *msg, | 751 | int kernel_recvmsg(struct socket *sock, struct msghdr *msg, |
736 | struct kvec *vec, size_t num, size_t size, int flags) | 752 | struct kvec *vec, size_t num, size_t size, int flags) |
737 | { | 753 | { |
@@ -1200,7 +1216,7 @@ int __sock_create(struct net *net, int family, int type, int protocol, | |||
1200 | * requested real, full-featured networking support upon configuration. | 1216 | * requested real, full-featured networking support upon configuration. |
1201 | * Otherwise module support will break! | 1217 | * Otherwise module support will break! |
1202 | */ | 1218 | */ |
1203 | if (net_families[family] == NULL) | 1219 | if (rcu_access_pointer(net_families[family]) == NULL) |
1204 | request_module("net-pf-%d", family); | 1220 | request_module("net-pf-%d", family); |
1205 | #endif | 1221 | #endif |
1206 | 1222 | ||
@@ -2332,10 +2348,11 @@ int sock_register(const struct net_proto_family *ops) | |||
2332 | } | 2348 | } |
2333 | 2349 | ||
2334 | spin_lock(&net_family_lock); | 2350 | spin_lock(&net_family_lock); |
2335 | if (net_families[ops->family]) | 2351 | if (rcu_dereference_protected(net_families[ops->family], |
2352 | lockdep_is_held(&net_family_lock))) | ||
2336 | err = -EEXIST; | 2353 | err = -EEXIST; |
2337 | else { | 2354 | else { |
2338 | net_families[ops->family] = ops; | 2355 | rcu_assign_pointer(net_families[ops->family], ops); |
2339 | err = 0; | 2356 | err = 0; |
2340 | } | 2357 | } |
2341 | spin_unlock(&net_family_lock); | 2358 | spin_unlock(&net_family_lock); |
@@ -2363,7 +2380,7 @@ void sock_unregister(int family) | |||
2363 | BUG_ON(family < 0 || family >= NPROTO); | 2380 | BUG_ON(family < 0 || family >= NPROTO); |
2364 | 2381 | ||
2365 | spin_lock(&net_family_lock); | 2382 | spin_lock(&net_family_lock); |
2366 | net_families[family] = NULL; | 2383 | rcu_assign_pointer(net_families[family], NULL); |
2367 | spin_unlock(&net_family_lock); | 2384 | spin_unlock(&net_family_lock); |
2368 | 2385 | ||
2369 | synchronize_rcu(); | 2386 | synchronize_rcu(); |
@@ -2374,6 +2391,8 @@ EXPORT_SYMBOL(sock_unregister); | |||
2374 | 2391 | ||
2375 | static int __init sock_init(void) | 2392 | static int __init sock_init(void) |
2376 | { | 2393 | { |
2394 | int err; | ||
2395 | |||
2377 | /* | 2396 | /* |
2378 | * Initialize sock SLAB cache. | 2397 | * Initialize sock SLAB cache. |
2379 | */ | 2398 | */ |
@@ -2390,8 +2409,15 @@ static int __init sock_init(void) | |||
2390 | */ | 2409 | */ |
2391 | 2410 | ||
2392 | init_inodecache(); | 2411 | init_inodecache(); |
2393 | register_filesystem(&sock_fs_type); | 2412 | |
2413 | err = register_filesystem(&sock_fs_type); | ||
2414 | if (err) | ||
2415 | goto out_fs; | ||
2394 | sock_mnt = kern_mount(&sock_fs_type); | 2416 | sock_mnt = kern_mount(&sock_fs_type); |
2417 | if (IS_ERR(sock_mnt)) { | ||
2418 | err = PTR_ERR(sock_mnt); | ||
2419 | goto out_mount; | ||
2420 | } | ||
2395 | 2421 | ||
2396 | /* The real protocol initialization is performed in later initcalls. | 2422 | /* The real protocol initialization is performed in later initcalls. |
2397 | */ | 2423 | */ |
@@ -2404,7 +2430,13 @@ static int __init sock_init(void) | |||
2404 | skb_timestamping_init(); | 2430 | skb_timestamping_init(); |
2405 | #endif | 2431 | #endif |
2406 | 2432 | ||
2407 | return 0; | 2433 | out: |
2434 | return err; | ||
2435 | |||
2436 | out_mount: | ||
2437 | unregister_filesystem(&sock_fs_type); | ||
2438 | out_fs: | ||
2439 | goto out; | ||
2408 | } | 2440 | } |
2409 | 2441 | ||
2410 | core_initcall(sock_init); /* early initcall */ | 2442 | core_initcall(sock_init); /* early initcall */ |