aboutsummaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2006-03-20 20:13:49 -0500
committerDavid S. Miller <davem@davemloft.net>2006-03-20 20:13:49 -0500
commit39d8c1b6fbaeb8d6adec4a8c08365cc9eaca6ae4 (patch)
treee604ee025c6711caca1bf6ec2a406197bf5be843 /net/socket.c
parent77d2ca350018c507815f5d38a40ffb597eb9ae25 (diff)
[NET]: Do not lose accepted socket when -ENFILE/-EMFILE.
Try to allocate the struct file and an unused file descriptor before we try to pull a newly accepted socket out of the protocol layer. Based upon a patch by Prassana Meda. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c113
1 files changed, 71 insertions, 42 deletions
diff --git a/net/socket.c b/net/socket.c
index 7e1bdef8b09e..74283610db15 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -348,8 +348,8 @@ static struct dentry_operations sockfs_dentry_operations = {
348/* 348/*
349 * Obtains the first available file descriptor and sets it up for use. 349 * Obtains the first available file descriptor and sets it up for use.
350 * 350 *
351 * This function creates file structure and maps it to fd space 351 * These functions create file structures and maps them to fd space
352 * of current process. On success it returns file descriptor 352 * of the current process. On success it returns file descriptor
353 * and file struct implicitly stored in sock->file. 353 * and file struct implicitly stored in sock->file.
354 * Note that another thread may close file descriptor before we return 354 * Note that another thread may close file descriptor before we return
355 * from this function. We use the fact that now we do not refer 355 * from this function. We use the fact that now we do not refer
@@ -362,52 +362,67 @@ static struct dentry_operations sockfs_dentry_operations = {
362 * but we take care of internal coherence yet. 362 * but we take care of internal coherence yet.
363 */ 363 */
364 364
365int sock_map_fd(struct socket *sock) 365static int sock_alloc_fd(struct file **filep)
366{ 366{
367 int fd; 367 int fd;
368 struct qstr this;
369 char name[32];
370
371 /*
372 * Find a file descriptor suitable for return to the user.
373 */
374 368
375 fd = get_unused_fd(); 369 fd = get_unused_fd();
376 if (fd >= 0) { 370 if (likely(fd >= 0)) {
377 struct file *file = get_empty_filp(); 371 struct file *file = get_empty_filp();
378 372
379 if (!file) { 373 *filep = file;
374 if (unlikely(!file)) {
380 put_unused_fd(fd); 375 put_unused_fd(fd);
381 fd = -ENFILE; 376 return -ENFILE;
382 goto out;
383 } 377 }
378 } else
379 *filep = NULL;
380 return fd;
381}
384 382
385 this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); 383static int sock_attach_fd(struct socket *sock, struct file *file)
386 this.name = name; 384{
387 this.hash = SOCK_INODE(sock)->i_ino; 385 struct qstr this;
386 char name[32];
387
388 this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
389 this.name = name;
390 this.hash = SOCK_INODE(sock)->i_ino;
391
392 file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
393 if (unlikely(!file->f_dentry))
394 return -ENOMEM;
395
396 file->f_dentry->d_op = &sockfs_dentry_operations;
397 d_add(file->f_dentry, SOCK_INODE(sock));
398 file->f_vfsmnt = mntget(sock_mnt);
399 file->f_mapping = file->f_dentry->d_inode->i_mapping;
400
401 sock->file = file;
402 file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
403 file->f_mode = FMODE_READ | FMODE_WRITE;
404 file->f_flags = O_RDWR;
405 file->f_pos = 0;
406 file->private_data = sock;
388 407
389 file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); 408 return 0;
390 if (!file->f_dentry) { 409}
391 put_filp(file); 410
411int sock_map_fd(struct socket *sock)
412{
413 struct file *newfile;
414 int fd = sock_alloc_fd(&newfile);
415
416 if (likely(fd >= 0)) {
417 int err = sock_attach_fd(sock, newfile);
418
419 if (unlikely(err < 0)) {
420 put_filp(newfile);
392 put_unused_fd(fd); 421 put_unused_fd(fd);
393 fd = -ENOMEM; 422 return err;
394 goto out;
395 } 423 }
396 file->f_dentry->d_op = &sockfs_dentry_operations; 424 fd_install(fd, newfile);
397 d_add(file->f_dentry, SOCK_INODE(sock));
398 file->f_vfsmnt = mntget(sock_mnt);
399 file->f_mapping = file->f_dentry->d_inode->i_mapping;
400
401 sock->file = file;
402 file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
403 file->f_mode = FMODE_READ | FMODE_WRITE;
404 file->f_flags = O_RDWR;
405 file->f_pos = 0;
406 file->private_data = sock;
407 fd_install(fd, file);
408 } 425 }
409
410out:
411 return fd; 426 return fd;
412} 427}
413 428
@@ -1349,7 +1364,8 @@ asmlinkage long sys_listen(int fd, int backlog)
1349asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen) 1364asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen)
1350{ 1365{
1351 struct socket *sock, *newsock; 1366 struct socket *sock, *newsock;
1352 int err, len; 1367 struct file *newfile;
1368 int err, len, newfd;
1353 char address[MAX_SOCK_ADDR]; 1369 char address[MAX_SOCK_ADDR];
1354 1370
1355 sock = sockfd_lookup(fd, &err); 1371 sock = sockfd_lookup(fd, &err);
@@ -1369,28 +1385,38 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
1369 */ 1385 */
1370 __module_get(newsock->ops->owner); 1386 __module_get(newsock->ops->owner);
1371 1387
1388 newfd = sock_alloc_fd(&newfile);
1389 if (unlikely(newfd < 0)) {
1390 err = newfd;
1391 goto out_release;
1392 }
1393
1394 err = sock_attach_fd(newsock, newfile);
1395 if (err < 0)
1396 goto out_fd;
1397
1372 err = security_socket_accept(sock, newsock); 1398 err = security_socket_accept(sock, newsock);
1373 if (err) 1399 if (err)
1374 goto out_release; 1400 goto out_fd;
1375 1401
1376 err = sock->ops->accept(sock, newsock, sock->file->f_flags); 1402 err = sock->ops->accept(sock, newsock, sock->file->f_flags);
1377 if (err < 0) 1403 if (err < 0)
1378 goto out_release; 1404 goto out_fd;
1379 1405
1380 if (upeer_sockaddr) { 1406 if (upeer_sockaddr) {
1381 if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { 1407 if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
1382 err = -ECONNABORTED; 1408 err = -ECONNABORTED;
1383 goto out_release; 1409 goto out_fd;
1384 } 1410 }
1385 err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); 1411 err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
1386 if (err < 0) 1412 if (err < 0)
1387 goto out_release; 1413 goto out_fd;
1388 } 1414 }
1389 1415
1390 /* File flags are not inherited via accept() unlike another OSes. */ 1416 /* File flags are not inherited via accept() unlike another OSes. */
1391 1417
1392 if ((err = sock_map_fd(newsock)) < 0) 1418 fd_install(newfd, newfile);
1393 goto out_release; 1419 err = newfd;
1394 1420
1395 security_socket_post_accept(sock, newsock); 1421 security_socket_post_accept(sock, newsock);
1396 1422
@@ -1398,6 +1424,9 @@ out_put:
1398 sockfd_put(sock); 1424 sockfd_put(sock);
1399out: 1425out:
1400 return err; 1426 return err;
1427out_fd:
1428 put_filp(newfile);
1429 put_unused_fd(newfd);
1401out_release: 1430out_release:
1402 sock_release(newsock); 1431 sock_release(newsock);
1403 goto out_put; 1432 goto out_put;