diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 63 |
1 files changed, 40 insertions, 23 deletions
diff --git a/net/socket.c b/net/socket.c index 088fb3fd45e0..ac2219f90d5d 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); |
@@ -305,20 +306,6 @@ static const struct super_operations sockfs_ops = { | |||
305 | .statfs = simple_statfs, | 306 | .statfs = simple_statfs, |
306 | }; | 307 | }; |
307 | 308 | ||
308 | static struct dentry *sockfs_mount(struct file_system_type *fs_type, | ||
309 | int flags, const char *dev_name, void *data) | ||
310 | { | ||
311 | return mount_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); | ||
312 | } | ||
313 | |||
314 | static struct vfsmount *sock_mnt __read_mostly; | ||
315 | |||
316 | static struct file_system_type sock_fs_type = { | ||
317 | .name = "sockfs", | ||
318 | .mount = sockfs_mount, | ||
319 | .kill_sb = kill_anon_super, | ||
320 | }; | ||
321 | |||
322 | /* | 309 | /* |
323 | * sockfs_dname() is called from d_path(). | 310 | * sockfs_dname() is called from d_path(). |
324 | */ | 311 | */ |
@@ -332,6 +319,21 @@ static const struct dentry_operations sockfs_dentry_operations = { | |||
332 | .d_dname = sockfs_dname, | 319 | .d_dname = sockfs_dname, |
333 | }; | 320 | }; |
334 | 321 | ||
322 | static struct dentry *sockfs_mount(struct file_system_type *fs_type, | ||
323 | int flags, const char *dev_name, void *data) | ||
324 | { | ||
325 | return mount_pseudo(fs_type, "socket:", &sockfs_ops, | ||
326 | &sockfs_dentry_operations, SOCKFS_MAGIC); | ||
327 | } | ||
328 | |||
329 | static struct vfsmount *sock_mnt __read_mostly; | ||
330 | |||
331 | static struct file_system_type sock_fs_type = { | ||
332 | .name = "sockfs", | ||
333 | .mount = sockfs_mount, | ||
334 | .kill_sb = kill_anon_super, | ||
335 | }; | ||
336 | |||
335 | /* | 337 | /* |
336 | * Obtains the first available file descriptor and sets it up for use. | 338 | * Obtains the first available file descriptor and sets it up for use. |
337 | * | 339 | * |
@@ -360,14 +362,13 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags) | |||
360 | if (unlikely(fd < 0)) | 362 | if (unlikely(fd < 0)) |
361 | return fd; | 363 | return fd; |
362 | 364 | ||
363 | path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); | 365 | path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); |
364 | if (unlikely(!path.dentry)) { | 366 | if (unlikely(!path.dentry)) { |
365 | put_unused_fd(fd); | 367 | put_unused_fd(fd); |
366 | return -ENOMEM; | 368 | return -ENOMEM; |
367 | } | 369 | } |
368 | path.mnt = mntget(sock_mnt); | 370 | path.mnt = mntget(sock_mnt); |
369 | 371 | ||
370 | path.dentry->d_op = &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 | ||
@@ -1215,7 +1216,7 @@ int __sock_create(struct net *net, int family, int type, int protocol, | |||
1215 | * requested real, full-featured networking support upon configuration. | 1216 | * requested real, full-featured networking support upon configuration. |
1216 | * Otherwise module support will break! | 1217 | * Otherwise module support will break! |
1217 | */ | 1218 | */ |
1218 | if (net_families[family] == NULL) | 1219 | if (rcu_access_pointer(net_families[family]) == NULL) |
1219 | request_module("net-pf-%d", family); | 1220 | request_module("net-pf-%d", family); |
1220 | #endif | 1221 | #endif |
1221 | 1222 | ||
@@ -2347,10 +2348,11 @@ int sock_register(const struct net_proto_family *ops) | |||
2347 | } | 2348 | } |
2348 | 2349 | ||
2349 | spin_lock(&net_family_lock); | 2350 | spin_lock(&net_family_lock); |
2350 | if (net_families[ops->family]) | 2351 | if (rcu_dereference_protected(net_families[ops->family], |
2352 | lockdep_is_held(&net_family_lock))) | ||
2351 | err = -EEXIST; | 2353 | err = -EEXIST; |
2352 | else { | 2354 | else { |
2353 | net_families[ops->family] = ops; | 2355 | rcu_assign_pointer(net_families[ops->family], ops); |
2354 | err = 0; | 2356 | err = 0; |
2355 | } | 2357 | } |
2356 | spin_unlock(&net_family_lock); | 2358 | spin_unlock(&net_family_lock); |
@@ -2378,7 +2380,7 @@ void sock_unregister(int family) | |||
2378 | BUG_ON(family < 0 || family >= NPROTO); | 2380 | BUG_ON(family < 0 || family >= NPROTO); |
2379 | 2381 | ||
2380 | spin_lock(&net_family_lock); | 2382 | spin_lock(&net_family_lock); |
2381 | net_families[family] = NULL; | 2383 | rcu_assign_pointer(net_families[family], NULL); |
2382 | spin_unlock(&net_family_lock); | 2384 | spin_unlock(&net_family_lock); |
2383 | 2385 | ||
2384 | synchronize_rcu(); | 2386 | synchronize_rcu(); |
@@ -2389,6 +2391,8 @@ EXPORT_SYMBOL(sock_unregister); | |||
2389 | 2391 | ||
2390 | static int __init sock_init(void) | 2392 | static int __init sock_init(void) |
2391 | { | 2393 | { |
2394 | int err; | ||
2395 | |||
2392 | /* | 2396 | /* |
2393 | * Initialize sock SLAB cache. | 2397 | * Initialize sock SLAB cache. |
2394 | */ | 2398 | */ |
@@ -2405,8 +2409,15 @@ static int __init sock_init(void) | |||
2405 | */ | 2409 | */ |
2406 | 2410 | ||
2407 | init_inodecache(); | 2411 | init_inodecache(); |
2408 | register_filesystem(&sock_fs_type); | 2412 | |
2413 | err = register_filesystem(&sock_fs_type); | ||
2414 | if (err) | ||
2415 | goto out_fs; | ||
2409 | 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 | } | ||
2410 | 2421 | ||
2411 | /* The real protocol initialization is performed in later initcalls. | 2422 | /* The real protocol initialization is performed in later initcalls. |
2412 | */ | 2423 | */ |
@@ -2419,7 +2430,13 @@ static int __init sock_init(void) | |||
2419 | skb_timestamping_init(); | 2430 | skb_timestamping_init(); |
2420 | #endif | 2431 | #endif |
2421 | 2432 | ||
2422 | return 0; | 2433 | out: |
2434 | return err; | ||
2435 | |||
2436 | out_mount: | ||
2437 | unregister_filesystem(&sock_fs_type); | ||
2438 | out_fs: | ||
2439 | goto out; | ||
2423 | } | 2440 | } |
2424 | 2441 | ||
2425 | core_initcall(sock_init); /* early initcall */ | 2442 | core_initcall(sock_init); /* early initcall */ |