@@ -84,36 +84,62 @@ struct file_operations {
8484};
8585
8686static inline bool in_userfd (int fd );
87+ static const int user_fdtable_initsize = 64 ;
8788static const int vkern_fdtable_maxsize = 64 ;
89+ static const int fdtable_alloc_unit = 64 ; // must be a multiple of 64
8890
8991static inline void set_fdbit (struct fdtable * table , uint64_t * fdbits , int fd );
9092static inline void clear_fdbit (struct fdtable * table , uint64_t * fdbits , int fd );
9193
94+ static inline int div_ceil (int x , int y ) { return (x + y - 1 ) / y ; }
95+
96+ int
97+ alloc_fdtable (struct fdtable * fdtable , int newsize )
98+ {
99+ newsize = div_ceil (newsize , fdtable_alloc_unit ) * fdtable_alloc_unit ;
100+ int oldsize = fdtable -> size ;
101+ if (newsize <= oldsize )
102+ return 0 ;
103+
104+ int newunit = newsize / fdtable_alloc_unit ;
105+ int oldunit = oldsize / fdtable_alloc_unit ;
106+ fdtable -> files = realloc (fdtable -> files , sizeof (struct file * ) * newunit );
107+ if (fdtable -> files == NULL )
108+ return - LINUX_ENOMEM ;
109+ for (int i = oldunit ; i < newunit ; i ++ ) {
110+ fdtable -> files [i ] = calloc (fdtable_alloc_unit , sizeof (struct file ));
111+ if (fdtable -> files [i ] == NULL )
112+ return - LINUX_ENOMEM ;
113+ }
114+
115+ int newfdslen = newsize / 8 ;
116+ fdtable -> open_fds = realloc (fdtable -> open_fds , newfdslen );
117+ if (fdtable -> open_fds == NULL )
118+ return - LINUX_ENOMEM ;
119+ fdtable -> cloexec_fds = realloc (fdtable -> cloexec_fds , newfdslen );
120+ if (fdtable -> cloexec_fds == NULL )
121+ return - LINUX_ENOMEM ;
122+ int offset = oldsize / 8 ;
123+ int size = newfdslen - offset ;
124+ bzero (fdtable -> open_fds + offset , size );
125+ bzero (fdtable -> cloexec_fds + offset , size );
126+
127+ fdtable -> size = newsize ;
128+ return 0 ;
129+ }
130+
92131void
93132init_fileinfo (int rootfd )
94133{
95134 struct rlimit limit ;
96135 struct fileinfo * fileinfo = & proc .fileinfo ;
97136
98137 getrlimit (RLIMIT_NOFILE , & limit );
99- fileinfo -> vkern_fdtable = (struct fdtable ) {
100- .start = limit .rlim_cur - 64 ,
101- .size = 64 ,
102- .files = malloc (sizeof (struct file ) * 64 ),
103- .open_fds = malloc (sizeof (uint64_t )),
104- .cloexec_fds = malloc (sizeof (uint64_t ))
105- };
106- fileinfo -> vkern_fdtable .open_fds [0 ] = 0 ;
107- fileinfo -> vkern_fdtable .cloexec_fds [0 ] = 0 ;
108- fileinfo -> fdtable = (struct fdtable ) {
109- .start = 0 ,
110- .size = vkern_fdtable_maxsize ,
111- .files = malloc (sizeof (struct file ) * vkern_fdtable_maxsize ),
112- .open_fds = malloc (sizeof (uint64_t )),
113- .cloexec_fds = malloc (sizeof (uint64_t ))
114- };
115- fileinfo -> fdtable .open_fds [0 ] = 0 ;
116- fileinfo -> fdtable .cloexec_fds [0 ] = 0 ;
138+ fileinfo -> vkern_fdtable = (struct fdtable ) { 0 , 0 , NULL , NULL , NULL };
139+ fileinfo -> vkern_fdtable .start = limit .rlim_cur - vkern_fdtable_maxsize ;
140+ alloc_fdtable (& fileinfo -> vkern_fdtable , vkern_fdtable_maxsize );
141+ fileinfo -> fdtable = (struct fdtable ) { 0 , 0 , NULL , NULL , NULL };
142+ alloc_fdtable (& fileinfo -> fdtable , user_fdtable_initsize );
117143
118144 for (int i = 0 ; i < (int ) limit .rlim_cur ; i ++ ) {
119145 if (i == rootfd ) {
@@ -500,7 +526,8 @@ alloc_file(struct fdtable *table, int fd)
500526 darwinfs_fchmod ,
501527 };
502528
503- struct file * file = table -> files + (fd - table -> start );
529+ int offset = fd - table -> start ;
530+ struct file * file = & table -> files [offset / fdtable_alloc_unit ][offset % fdtable_alloc_unit ];
504531 file -> ops = & ops ;
505532 file -> fd = fd ;
506533}
@@ -518,16 +545,9 @@ register_fd(int fd, bool is_cloexec)
518545 }
519546 struct fdtable * fdtable = & proc .fileinfo .fdtable ;
520547 if (proc .fileinfo .fdtable .size <= fd ) {
521- // Expand table
522- int new_size = roundup (fd , sizeof (uint64_t ));
523- size_t old_nunits = proc .fileinfo .fdtable .size / 64 ;
524- size_t new_nunits = new_size / 64 ;
525- fdtable -> files = realloc (fdtable -> files , new_size * sizeof (struct file ));
526- fdtable -> open_fds = realloc (fdtable -> open_fds , sizeof (uint64_t ) * new_nunits );
527- fdtable -> cloexec_fds = realloc (fdtable -> cloexec_fds , sizeof (uint64_t ) * new_nunits );
528- bzero (fdtable -> open_fds + old_nunits , (new_nunits - old_nunits ) * sizeof (uint64_t ));
529- bzero (fdtable -> cloexec_fds + old_nunits , (new_nunits - old_nunits ) * sizeof (uint64_t ));
530- fdtable -> size = new_size ;
548+ int err = alloc_fdtable (fdtable , fd + 1 );
549+ if (err < 0 )
550+ return err ;
531551 }
532552 set_fdbit (fdtable , fdtable -> open_fds , fd );
533553 if (is_cloexec ) {
@@ -570,18 +590,25 @@ vkern_dup_fd(int fd, bool is_cloexec)
570590}
571591
572592struct file *
573- get_file ( int fd )
593+ do_get_file ( struct fdtable * table , int fd )
574594{
575- if (fd < 0 || fd >= proc . fileinfo . fdtable . size ) {
595+ if (! test_fdbit ( table , table -> open_fds , fd ) ) {
576596 return NULL ;
577597 }
598+ int offset = fd - table -> start ;
599+ return & table -> files [offset / fdtable_alloc_unit ][offset % fdtable_alloc_unit ];
600+ }
578601
602+ struct file *
603+ get_file (int fd )
604+ {
579605 struct file * ret = NULL ;
606+ struct fdtable * table = & proc .fileinfo .fdtable ;
580607 pthread_rwlock_rdlock (& proc .fileinfo .fdtable_lock );
581- if (! test_fdbit ( & proc . fileinfo . fdtable , proc . fileinfo . fdtable . open_fds , fd ) ) {
608+ if (fd < 0 || fd >= table -> size ) {
582609 goto out ;
583610 }
584- ret = & proc . fileinfo . fdtable . files [ fd - proc . fileinfo . fdtable . start ] ;
611+ ret = do_get_file ( table , fd ) ;
585612
586613out :
587614 pthread_rwlock_unlock (& proc .fileinfo .fdtable_lock );
@@ -1161,8 +1188,9 @@ do_close(struct fdtable *table, int fd)
11611188 if (!test_fdbit (table , table -> open_fds , fd )) {
11621189 return - LINUX_EBADF ;
11631190 }
1164- struct file * file = & table -> files [fd - table -> start ];
1165- assert (file );
1191+ struct file * file = do_get_file (table , fd );
1192+ if (file == NULL )
1193+ return - LINUX_EBADF ;
11661194 int n = file -> ops -> close (file );
11671195 clear_fdbit (table , table -> open_fds , fd );
11681196 clear_fdbit (table , table -> cloexec_fds , fd );
0 commit comments