Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] reduce sizeof(struct file)

Now that RCU applied on 'struct file' seems stable, we can place f_rcuhead
in a memory location that is not anymore used at call_rcu(&f->f_rcuhead,
file_free_rcu) time, to reduce the size of this critical kernel object.

The trick I used is to move f_rcuhead and f_list in an union called f_u

The callers are changed so that f_rcuhead becomes f_u.fu_rcuhead and f_list
becomes f_u.f_list

Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Eric Dumazet and committed by
Linus Torvalds
2f512016 503af334

+21 -15
+1 -1
drivers/char/tty_io.c
··· 809 809 check_tty_count(tty, "do_tty_hangup"); 810 810 file_list_lock(); 811 811 /* This breaks for file handles being sent over AF_UNIX sockets ? */ 812 - list_for_each_entry(filp, &tty->tty_files, f_list) { 812 + list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { 813 813 if (filp->f_op->write == redirected_tty_write) 814 814 cons_filp = filp; 815 815 if (filp->f_op->write != tty_write)
+1 -1
fs/dquot.c
··· 662 662 restart: 663 663 file_list_lock(); 664 664 list_for_each(p, &sb->s_files) { 665 - struct file *filp = list_entry(p, struct file, f_list); 665 + struct file *filp = list_entry(p, struct file, f_u.fu_list); 666 666 struct inode *inode = filp->f_dentry->d_inode; 667 667 if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { 668 668 struct dentry *dentry = dget(filp->f_dentry);
+7 -7
fs/file_table.c
··· 56 56 57 57 static inline void file_free_rcu(struct rcu_head *head) 58 58 { 59 - struct file *f = container_of(head, struct file, f_rcuhead); 59 + struct file *f = container_of(head, struct file, f_u.fu_rcuhead); 60 60 kmem_cache_free(filp_cachep, f); 61 61 } 62 62 63 63 static inline void file_free(struct file *f) 64 64 { 65 - call_rcu(&f->f_rcuhead, file_free_rcu); 65 + call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); 66 66 } 67 67 68 68 /* Find an unused file structure and return a pointer to it. ··· 95 95 f->f_gid = current->fsgid; 96 96 rwlock_init(&f->f_owner.lock); 97 97 /* f->f_version: 0 */ 98 - INIT_LIST_HEAD(&f->f_list); 98 + INIT_LIST_HEAD(&f->f_u.fu_list); 99 99 return f; 100 100 101 101 over: ··· 225 225 if (!list) 226 226 return; 227 227 file_list_lock(); 228 - list_move(&file->f_list, list); 228 + list_move(&file->f_u.fu_list, list); 229 229 file_list_unlock(); 230 230 } 231 231 232 232 void file_kill(struct file *file) 233 233 { 234 - if (!list_empty(&file->f_list)) { 234 + if (!list_empty(&file->f_u.fu_list)) { 235 235 file_list_lock(); 236 - list_del_init(&file->f_list); 236 + list_del_init(&file->f_u.fu_list); 237 237 file_list_unlock(); 238 238 } 239 239 } ··· 245 245 /* Check that no files are currently opened for writing. */ 246 246 file_list_lock(); 247 247 list_for_each(p, &sb->s_files) { 248 - struct file *file = list_entry(p, struct file, f_list); 248 + struct file *file = list_entry(p, struct file, f_u.fu_list); 249 249 struct inode *inode = file->f_dentry->d_inode; 250 250 251 251 /* File with pending delete? */
+1 -1
fs/proc/generic.c
··· 533 533 */ 534 534 file_list_lock(); 535 535 list_for_each(p, &sb->s_files) { 536 - struct file * filp = list_entry(p, struct file, f_list); 536 + struct file * filp = list_entry(p, struct file, f_u.fu_list); 537 537 struct dentry * dentry = filp->f_dentry; 538 538 struct inode * inode; 539 539 struct file_operations *fops;
+1 -1
fs/super.c
··· 513 513 struct file *f; 514 514 515 515 file_list_lock(); 516 - list_for_each_entry(f, &sb->s_files, f_list) { 516 + list_for_each_entry(f, &sb->s_files, f_u.fu_list) { 517 517 if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f)) 518 518 f->f_mode &= ~FMODE_WRITE; 519 519 }
+8 -2
include/linux/fs.h
··· 574 574 #define RA_FLAG_INCACHE 0x02 /* file is already in cache */ 575 575 576 576 struct file { 577 - struct list_head f_list; 577 + /* 578 + * fu_list becomes invalid after file_free is called and queued via 579 + * fu_rcuhead for RCU freeing 580 + */ 581 + union { 582 + struct list_head fu_list; 583 + struct rcu_head fu_rcuhead; 584 + } f_u; 578 585 struct dentry *f_dentry; 579 586 struct vfsmount *f_vfsmnt; 580 587 struct file_operations *f_op; ··· 605 598 spinlock_t f_ep_lock; 606 599 #endif /* #ifdef CONFIG_EPOLL */ 607 600 struct address_space *f_mapping; 608 - struct rcu_head f_rcuhead; 609 601 }; 610 602 extern spinlock_t files_lock; 611 603 #define file_list_lock() spin_lock(&files_lock);
+1 -1
security/selinux/hooks.c
··· 1609 1609 1610 1610 if (tty) { 1611 1611 file_list_lock(); 1612 - file = list_entry(tty->tty_files.next, typeof(*file), f_list); 1612 + file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list); 1613 1613 if (file) { 1614 1614 /* Revalidate access to controlling tty. 1615 1615 Use inode_has_perm on the tty inode directly rather
+1 -1
security/selinux/selinuxfs.c
··· 914 914 915 915 file_list_lock(); 916 916 list_for_each(p, &sb->s_files) { 917 - struct file * filp = list_entry(p, struct file, f_list); 917 + struct file * filp = list_entry(p, struct file, f_u.fu_list); 918 918 struct dentry * dentry = filp->f_dentry; 919 919 920 920 if (dentry->d_parent != de) {