diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 108 |
1 files changed, 36 insertions, 72 deletions
diff --git a/net/socket.c b/net/socket.c index b94c3dd71015..dbfdfa96d29b 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -355,68 +355,61 @@ static const struct dentry_operations sockfs_dentry_operations = { | |||
355 | * but we take care of internal coherence yet. | 355 | * but we take care of internal coherence yet. |
356 | */ | 356 | */ |
357 | 357 | ||
358 | static int sock_alloc_fd(struct file **filep, int flags) | 358 | static int sock_alloc_file(struct socket *sock, struct file **f, int flags) |
359 | { | 359 | { |
360 | struct qstr name = { .name = "" }; | ||
361 | struct path path; | ||
362 | struct file *file; | ||
360 | int fd; | 363 | int fd; |
361 | 364 | ||
362 | fd = get_unused_fd_flags(flags); | 365 | fd = get_unused_fd_flags(flags); |
363 | if (likely(fd >= 0)) { | 366 | if (unlikely(fd < 0)) |
364 | struct file *file = get_empty_filp(); | 367 | 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 | 368 | ||
381 | dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); | 369 | path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name); |
382 | if (unlikely(!dentry)) | 370 | if (unlikely(!path.dentry)) { |
371 | put_unused_fd(fd); | ||
383 | return -ENOMEM; | 372 | return -ENOMEM; |
373 | } | ||
374 | path.mnt = mntget(sock_mnt); | ||
384 | 375 | ||
385 | dentry->d_op = &sockfs_dentry_operations; | 376 | path.dentry->d_op = &sockfs_dentry_operations; |
386 | /* | 377 | /* |
387 | * We dont want to push this dentry into global dentry hash table. | 378 | * We dont want to push this dentry into global dentry hash table. |
388 | * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED | 379 | * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED |
389 | * This permits a working /proc/$pid/fd/XXX on sockets | 380 | * This permits a working /proc/$pid/fd/XXX on sockets |
390 | */ | 381 | */ |
391 | dentry->d_flags &= ~DCACHE_UNHASHED; | 382 | path.dentry->d_flags &= ~DCACHE_UNHASHED; |
392 | d_instantiate(dentry, SOCK_INODE(sock)); | 383 | d_instantiate(path.dentry, SOCK_INODE(sock)); |
384 | SOCK_INODE(sock)->i_fop = &socket_file_ops; | ||
393 | 385 | ||
394 | sock->file = file; | 386 | file = alloc_file(&path, FMODE_READ | FMODE_WRITE, |
395 | init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE, | ||
396 | &socket_file_ops); | 387 | &socket_file_ops); |
397 | SOCK_INODE(sock)->i_fop = &socket_file_ops; | 388 | if (unlikely(!file)) { |
389 | /* drop dentry, keep inode */ | ||
390 | atomic_inc(&path.dentry->d_inode->i_count); | ||
391 | path_put(&path); | ||
392 | put_unused_fd(fd); | ||
393 | return -ENFILE; | ||
394 | } | ||
395 | |||
396 | sock->file = file; | ||
398 | file->f_flags = O_RDWR | (flags & O_NONBLOCK); | 397 | file->f_flags = O_RDWR | (flags & O_NONBLOCK); |
399 | file->f_pos = 0; | 398 | file->f_pos = 0; |
400 | file->private_data = sock; | 399 | file->private_data = sock; |
401 | 400 | ||
402 | return 0; | 401 | *f = file; |
402 | return fd; | ||
403 | } | 403 | } |
404 | 404 | ||
405 | int sock_map_fd(struct socket *sock, int flags) | 405 | int sock_map_fd(struct socket *sock, int flags) |
406 | { | 406 | { |
407 | struct file *newfile; | 407 | struct file *newfile; |
408 | int fd = sock_alloc_fd(&newfile, flags); | 408 | int fd = sock_alloc_file(sock, &newfile, flags); |
409 | |||
410 | if (likely(fd >= 0)) { | ||
411 | int err = sock_attach_fd(sock, newfile, flags); | ||
412 | 409 | ||
413 | if (unlikely(err < 0)) { | 410 | if (likely(fd >= 0)) |
414 | put_filp(newfile); | ||
415 | put_unused_fd(fd); | ||
416 | return err; | ||
417 | } | ||
418 | fd_install(fd, newfile); | 411 | fd_install(fd, newfile); |
419 | } | 412 | |
420 | return fd; | 413 | return fd; |
421 | } | 414 | } |
422 | 415 | ||
@@ -1390,29 +1383,19 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, | |||
1390 | if (err < 0) | 1383 | if (err < 0) |
1391 | goto out_release_both; | 1384 | goto out_release_both; |
1392 | 1385 | ||
1393 | fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC); | 1386 | fd1 = sock_alloc_file(sock1, &newfile1, flags); |
1394 | if (unlikely(fd1 < 0)) { | 1387 | if (unlikely(fd1 < 0)) { |
1395 | err = fd1; | 1388 | err = fd1; |
1396 | goto out_release_both; | 1389 | goto out_release_both; |
1397 | } | 1390 | } |
1398 | 1391 | ||
1399 | fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC); | 1392 | fd2 = sock_alloc_file(sock2, &newfile2, flags); |
1400 | if (unlikely(fd2 < 0)) { | 1393 | if (unlikely(fd2 < 0)) { |
1401 | err = fd2; | 1394 | 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); | 1395 | fput(newfile1); |
1415 | goto out_fd1; | 1396 | put_unused_fd(fd1); |
1397 | sock_release(sock2); | ||
1398 | goto out; | ||
1416 | } | 1399 | } |
1417 | 1400 | ||
1418 | audit_fd_pair(fd1, fd2); | 1401 | audit_fd_pair(fd1, fd2); |
@@ -1438,16 +1421,6 @@ out_release_1: | |||
1438 | sock_release(sock1); | 1421 | sock_release(sock1); |
1439 | out: | 1422 | out: |
1440 | return err; | 1423 | 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 | } | 1424 | } |
1452 | 1425 | ||
1453 | /* | 1426 | /* |
@@ -1551,17 +1524,13 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, | |||
1551 | */ | 1524 | */ |
1552 | __module_get(newsock->ops->owner); | 1525 | __module_get(newsock->ops->owner); |
1553 | 1526 | ||
1554 | newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC); | 1527 | newfd = sock_alloc_file(newsock, &newfile, flags); |
1555 | if (unlikely(newfd < 0)) { | 1528 | if (unlikely(newfd < 0)) { |
1556 | err = newfd; | 1529 | err = newfd; |
1557 | sock_release(newsock); | 1530 | sock_release(newsock); |
1558 | goto out_put; | 1531 | goto out_put; |
1559 | } | 1532 | } |
1560 | 1533 | ||
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); | 1534 | err = security_socket_accept(sock, newsock); |
1566 | if (err) | 1535 | if (err) |
1567 | goto out_fd; | 1536 | goto out_fd; |
@@ -1591,11 +1560,6 @@ out_put: | |||
1591 | fput_light(sock->file, fput_needed); | 1560 | fput_light(sock->file, fput_needed); |
1592 | out: | 1561 | out: |
1593 | return err; | 1562 | 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: | 1563 | out_fd: |
1600 | fput(newfile); | 1564 | fput(newfile); |
1601 | put_unused_fd(newfd); | 1565 | put_unused_fd(newfd); |