[PATCH] reduce sizeof(struct file)
Eric Dumazet [Sun, 30 Oct 2005 23:02:16 +0000 (15:02 -0800)]
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>

drivers/char/tty_io.c
fs/dquot.c
fs/file_table.c
fs/proc/generic.c
fs/super.c
include/linux/fs.h
security/selinux/hooks.c
security/selinux/selinuxfs.c

index f5649a3..c586bfa 100644 (file)
@@ -809,7 +809,7 @@ static void do_tty_hangup(void *data)
        check_tty_count(tty, "do_tty_hangup");
        file_list_lock();
        /* This breaks for file handles being sent over AF_UNIX sockets ? */
-       list_for_each_entry(filp, &tty->tty_files, f_list) {
+       list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
                if (filp->f_op->write == redirected_tty_write)
                        cons_filp = filp;
                if (filp->f_op->write != tty_write)
index 05f3327..ea76442 100644 (file)
@@ -662,7 +662,7 @@ static void add_dquot_ref(struct super_block *sb, int type)
 restart:
        file_list_lock();
        list_for_each(p, &sb->s_files) {
-               struct file *filp = list_entry(p, struct file, f_list);
+               struct file *filp = list_entry(p, struct file, f_u.fu_list);
                struct inode *inode = filp->f_dentry->d_inode;
                if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
                        struct dentry *dentry = dget(filp->f_dentry);
index 86ec8ae..4dc2055 100644 (file)
@@ -56,13 +56,13 @@ void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags)
 
 static inline void file_free_rcu(struct rcu_head *head)
 {
-       struct file *f =  container_of(head, struct file, f_rcuhead);
+       struct file *f =  container_of(head, struct file, f_u.fu_rcuhead);
        kmem_cache_free(filp_cachep, f);
 }
 
 static inline void file_free(struct file *f)
 {
-       call_rcu(&f->f_rcuhead, file_free_rcu);
+       call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
 }
 
 /* Find an unused file structure and return a pointer to it.
@@ -95,7 +95,7 @@ struct file *get_empty_filp(void)
        f->f_gid = current->fsgid;
        rwlock_init(&f->f_owner.lock);
        /* f->f_version: 0 */
-       INIT_LIST_HEAD(&f->f_list);
+       INIT_LIST_HEAD(&f->f_u.fu_list);
        return f;
 
 over:
@@ -225,15 +225,15 @@ void file_move(struct file *file, struct list_head *list)
        if (!list)
                return;
        file_list_lock();
-       list_move(&file->f_list, list);
+       list_move(&file->f_u.fu_list, list);
        file_list_unlock();
 }
 
 void file_kill(struct file *file)
 {
-       if (!list_empty(&file->f_list)) {
+       if (!list_empty(&file->f_u.fu_list)) {
                file_list_lock();
-               list_del_init(&file->f_list);
+               list_del_init(&file->f_u.fu_list);
                file_list_unlock();
        }
 }
@@ -245,7 +245,7 @@ int fs_may_remount_ro(struct super_block *sb)
        /* Check that no files are currently opened for writing. */
        file_list_lock();
        list_for_each(p, &sb->s_files) {
-               struct file *file = list_entry(p, struct file, f_list);
+               struct file *file = list_entry(p, struct file, f_u.fu_list);
                struct inode *inode = file->f_dentry->d_inode;
 
                /* File with pending delete? */
index 8a8c344..b638fb5 100644 (file)
@@ -533,7 +533,7 @@ static void proc_kill_inodes(struct proc_dir_entry *de)
         */
        file_list_lock();
        list_for_each(p, &sb->s_files) {
-               struct file * filp = list_entry(p, struct file, f_list);
+               struct file * filp = list_entry(p, struct file, f_u.fu_list);
                struct dentry * dentry = filp->f_dentry;
                struct inode * inode;
                struct file_operations *fops;
index 6e57ee2..f60155e 100644 (file)
@@ -513,7 +513,7 @@ static void mark_files_ro(struct super_block *sb)
        struct file *f;
 
        file_list_lock();
-       list_for_each_entry(f, &sb->s_files, f_list) {
+       list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
                if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f))
                        f->f_mode &= ~FMODE_WRITE;
        }
index f83d997..6d62267 100644 (file)
@@ -574,7 +574,14 @@ struct file_ra_state {
 #define RA_FLAG_INCACHE 0x02   /* file is already in cache */
 
 struct file {
-       struct list_head        f_list;
+       /*
+        * fu_list becomes invalid after file_free is called and queued via
+        * fu_rcuhead for RCU freeing
+        */
+       union {
+               struct list_head        fu_list;
+               struct rcu_head         fu_rcuhead;
+       } f_u;
        struct dentry           *f_dentry;
        struct vfsmount         *f_vfsmnt;
        struct file_operations  *f_op;
@@ -598,7 +605,6 @@ struct file {
        spinlock_t              f_ep_lock;
 #endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
-       struct rcu_head         f_rcuhead;
 };
 extern spinlock_t files_lock;
 #define file_list_lock() spin_lock(&files_lock);
index d50d7a7..bb62838 100644 (file)
@@ -1609,7 +1609,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
 
        if (tty) {
                file_list_lock();
-               file = list_entry(tty->tty_files.next, typeof(*file), f_list);
+               file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
                if (file) {
                        /* Revalidate access to controlling tty.
                           Use inode_has_perm on the tty inode directly rather
index 7a387fe..fdc3823 100644 (file)
@@ -914,7 +914,7 @@ static void sel_remove_bools(struct dentry *de)
 
        file_list_lock();
        list_for_each(p, &sb->s_files) {
-               struct file * filp = list_entry(p, struct file, f_list);
+               struct file * filp = list_entry(p, struct file, f_u.fu_list);
                struct dentry * dentry = filp->f_dentry;
 
                if (dentry->d_parent != de) {