diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 125 |
1 files changed, 35 insertions, 90 deletions
diff --git a/net/socket.c b/net/socket.c index b94c3dd71015..769c386bd428 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -312,18 +312,6 @@ static struct file_system_type sock_fs_type = { | |||
312 | .kill_sb = kill_anon_super, | 312 | .kill_sb = kill_anon_super, |
313 | }; | 313 | }; |
314 | 314 | ||
315 | static int sockfs_delete_dentry(struct dentry *dentry) | ||
316 | { | ||
317 | /* | ||
318 | * At creation time, we pretended this dentry was hashed | ||
319 | * (by clearing DCACHE_UNHASHED bit in d_flags) | ||
320 | * At delete time, we restore the truth : not hashed. | ||
321 | * (so that dput() can proceed correctly) | ||
322 | */ | ||
323 | dentry->d_flags |= DCACHE_UNHASHED; | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /* | 315 | /* |
328 | * sockfs_dname() is called from d_path(). | 316 | * sockfs_dname() is called from d_path(). |
329 | */ | 317 | */ |
@@ -334,7 +322,6 @@ static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) | |||
334 | } | 322 | } |
335 | 323 | ||
336 | static const struct dentry_operations sockfs_dentry_operations = { | 324 | static const struct dentry_operations sockfs_dentry_operations = { |
337 | .d_delete = sockfs_delete_dentry, | ||
338 | .d_dname = sockfs_dname, | 325 | .d_dname = sockfs_dname, |
339 | }; | 326 | }; |
340 | 327 | ||
@@ -355,68 +342,55 @@ static const struct dentry_operations sockfs_dentry_operations = { | |||
355 | * but we take care of internal coherence yet. | 342 | * but we take care of internal coherence yet. |
356 | */ | 343 | */ |
357 | 344 | ||
358 | static int sock_alloc_fd(struct file **filep, int flags) | 345 | static int sock_alloc_file(struct socket *sock, struct file **f, int flags) |
359 | { | 346 | { |
347 | struct qstr name = { .name = "" }; | ||
348 | struct path path; | ||
349 | struct file *file; | ||
360 | int fd; | 350 | int fd; |
361 | 351 | ||
362 | fd = get_unused_fd_flags(flags); | 352 | fd = get_unused_fd_flags(flags); |
363 | if (likely(fd >= 0)) { | 353 | if (unlikely(fd < 0)) |
364 | struct file *file = get_empty_filp(); | 354 | return fd; |
365 | |||
366 | *filep = file; | ||
367 | if (unlikely(!file)) { | ||
368 | put_unused_fd(fd); | ||
369 | return -ENFILE; | ||
370 | } | ||
371 | } else | ||
372 | *filep = NULL; | ||
373 | return fd; | ||
374 | } | ||
375 | |||
376 | static int sock_attach_fd(struct socket *sock, struct file *file, int flags) | ||
377 | { | ||
378 | struct dentry *dentry; | ||
379 | struct qstr name = { .name = "" }; | ||
380 | 355 | ||
381 | dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); | 356 | path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); |
382 | if (unlikely(!dentry)) | 357 | if (unlikely(!path.dentry)) { |
358 | put_unused_fd(fd); | ||
383 | return -ENOMEM; | 359 | return -ENOMEM; |
360 | } | ||
361 | path.mnt = mntget(sock_mnt); | ||
384 | 362 | ||
385 | dentry->d_op = &sockfs_dentry_operations; | 363 | path.dentry->d_op = &sockfs_dentry_operations; |
386 | /* | 364 | d_instantiate(path.dentry, SOCK_INODE(sock)); |
387 | * We dont want to push this dentry into global dentry hash table. | 365 | SOCK_INODE(sock)->i_fop = &socket_file_ops; |
388 | * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED | ||
389 | * This permits a working /proc/$pid/fd/XXX on sockets | ||
390 | */ | ||
391 | dentry->d_flags &= ~DCACHE_UNHASHED; | ||
392 | d_instantiate(dentry, SOCK_INODE(sock)); | ||
393 | 366 | ||
394 | sock->file = file; | 367 | file = alloc_file(&path, FMODE_READ | FMODE_WRITE, |
395 | init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE, | ||
396 | &socket_file_ops); | 368 | &socket_file_ops); |
397 | SOCK_INODE(sock)->i_fop = &socket_file_ops; | 369 | if (unlikely(!file)) { |
370 | /* drop dentry, keep inode */ | ||
371 | atomic_inc(&path.dentry->d_inode->i_count); | ||
372 | path_put(&path); | ||
373 | put_unused_fd(fd); | ||
374 | return -ENFILE; | ||
375 | } | ||
376 | |||
377 | sock->file = file; | ||
398 | file->f_flags = O_RDWR | (flags & O_NONBLOCK); | 378 | file->f_flags = O_RDWR | (flags & O_NONBLOCK); |
399 | file->f_pos = 0; | 379 | file->f_pos = 0; |
400 | file->private_data = sock; | 380 | file->private_data = sock; |
401 | 381 | ||
402 | return 0; | 382 | *f = file; |
383 | return fd; | ||
403 | } | 384 | } |
404 | 385 | ||
405 | int sock_map_fd(struct socket *sock, int flags) | 386 | int sock_map_fd(struct socket *sock, int flags) |
406 | { | 387 | { |
407 | struct file *newfile; | 388 | struct file *newfile; |
408 | int fd = sock_alloc_fd(&newfile, flags); | 389 | int fd = sock_alloc_file(sock, &newfile, flags); |
409 | 390 | ||
410 | if (likely(fd >= 0)) { | 391 | if (likely(fd >= 0)) |
411 | int err = sock_attach_fd(sock, newfile, flags); | ||
412 | |||
413 | if (unlikely(err < 0)) { | ||
414 | put_filp(newfile); | ||
415 | put_unused_fd(fd); | ||
416 | return err; | ||
417 | } | ||
418 | fd_install(fd, newfile); | 392 | fd_install(fd, newfile); |
419 | } | 393 | |
420 | return fd; | 394 | return fd; |
421 | } | 395 | } |
422 | 396 | ||
@@ -1390,29 +1364,19 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, | |||
1390 | if (err < 0) | 1364 | if (err < 0) |
1391 | goto out_release_both; | 1365 | goto out_release_both; |
1392 | 1366 | ||
1393 | fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC); | 1367 | fd1 = sock_alloc_file(sock1, &newfile1, flags); |
1394 | if (unlikely(fd1 < 0)) { | 1368 | if (unlikely(fd1 < 0)) { |
1395 | err = fd1; | 1369 | err = fd1; |
1396 | goto out_release_both; | 1370 | goto out_release_both; |
1397 | } | 1371 | } |
1398 | 1372 | ||
1399 | fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC); | 1373 | fd2 = sock_alloc_file(sock2, &newfile2, flags); |
1400 | if (unlikely(fd2 < 0)) { | 1374 | if (unlikely(fd2 < 0)) { |
1401 | err = fd2; | 1375 | err = fd2; |
1402 | put_filp(newfile1); | ||
1403 | put_unused_fd(fd1); | ||
1404 | goto out_release_both; | ||
1405 | } | ||
1406 | |||
1407 | err = sock_attach_fd(sock1, newfile1, flags & O_NONBLOCK); | ||
1408 | if (unlikely(err < 0)) { | ||
1409 | goto out_fd2; | ||
1410 | } | ||
1411 | |||
1412 | err = sock_attach_fd(sock2, newfile2, flags & O_NONBLOCK); | ||
1413 | if (unlikely(err < 0)) { | ||
1414 | fput(newfile1); | 1376 | fput(newfile1); |
1415 | goto out_fd1; | 1377 | put_unused_fd(fd1); |
1378 | sock_release(sock2); | ||
1379 | goto out; | ||
1416 | } | 1380 | } |
1417 | 1381 | ||
1418 | audit_fd_pair(fd1, fd2); | 1382 | audit_fd_pair(fd1, fd2); |
@@ -1438,16 +1402,6 @@ out_release_1: | |||
1438 | sock_release(sock1); | 1402 | sock_release(sock1); |
1439 | out: | 1403 | out: |
1440 | return err; | 1404 | return err; |
1441 | |||
1442 | out_fd2: | ||
1443 | put_filp(newfile1); | ||
1444 | sock_release(sock1); | ||
1445 | out_fd1: | ||
1446 | put_filp(newfile2); | ||
1447 | sock_release(sock2); | ||
1448 | put_unused_fd(fd1); | ||
1449 | put_unused_fd(fd2); | ||
1450 | goto out; | ||
1451 | } | 1405 | } |
1452 | 1406 | ||
1453 | /* | 1407 | /* |
@@ -1551,17 +1505,13 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, | |||
1551 | */ | 1505 | */ |
1552 | __module_get(newsock->ops->owner); | 1506 | __module_get(newsock->ops->owner); |
1553 | 1507 | ||
1554 | newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC); | 1508 | newfd = sock_alloc_file(newsock, &newfile, flags); |
1555 | if (unlikely(newfd < 0)) { | 1509 | if (unlikely(newfd < 0)) { |
1556 | err = newfd; | 1510 | err = newfd; |
1557 | sock_release(newsock); | 1511 | sock_release(newsock); |
1558 | goto out_put; | 1512 | goto out_put; |
1559 | } | 1513 | } |
1560 | 1514 | ||
1561 | err = sock_attach_fd(newsock, newfile, flags & O_NONBLOCK); | ||
1562 | if (err < 0) | ||
1563 | goto out_fd_simple; | ||
1564 | |||
1565 | err = security_socket_accept(sock, newsock); | 1515 | err = security_socket_accept(sock, newsock); |
1566 | if (err) | 1516 | if (err) |
1567 | goto out_fd; | 1517 | goto out_fd; |
@@ -1591,11 +1541,6 @@ out_put: | |||
1591 | fput_light(sock->file, fput_needed); | 1541 | fput_light(sock->file, fput_needed); |
1592 | out: | 1542 | out: |
1593 | return err; | 1543 | return err; |
1594 | out_fd_simple: | ||
1595 | sock_release(newsock); | ||
1596 | put_filp(newfile); | ||
1597 | put_unused_fd(newfd); | ||
1598 | goto out_put; | ||
1599 | out_fd: | 1544 | out_fd: |
1600 | fput(newfile); | 1545 | fput(newfile); |
1601 | put_unused_fd(newfd); | 1546 | put_unused_fd(newfd); |