Messages in this thread Patch in this message | | | Date | Thu, 18 Aug 2005 11:05:25 +0200 | From | Eric Dumazet <> | Subject | [PATCH] Put the very large file_ra_state outside of 'struct file' |
| |
[PATCH]
* struct file cleanup : the very large file_ra_state is now allocated only on demand, using a dedicated "filp_ra_cache" slab. machines handling lot of sockets or pipes can save about 80 bytes (or 40 bytes on 32bits platforms) per file.
* private_data : The field is moved close to f_count and f_op fields to speedup sockfd_lookups
Thank you
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
--- linux-2.6.13-rc6/include/linux/fs.h 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/include/linux/fs.h 2005-08-18 10:30:35.000000000 +0200 @@ -586,20 +586,18 @@ struct dentry *f_dentry; struct vfsmount *f_vfsmnt; struct file_operations *f_op; + void *private_data; atomic_t f_count; unsigned int f_flags; mode_t f_mode; loff_t f_pos; struct fown_struct f_owner; unsigned int f_uid, f_gid; - struct file_ra_state f_ra; size_t f_maxcount; unsigned long f_version; void *f_security; - /* needed for tty driver, and maybe others */ - void *private_data; #ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ @@ -1480,7 +1478,10 @@ __insert_inode_hash(inode, inode->i_ino); } -extern struct file * get_empty_filp(void); +#define FILP_NO_READ_AHEAD 0 +#define FILP_WITH_READ_AHEAD 1 +extern struct file * get_empty_filp(int need_read_ahead); + extern void file_move(struct file *f, struct list_head *list); extern void file_kill(struct file *f); struct bio; @@ -1514,8 +1515,7 @@ extern void do_generic_mapping_read(struct address_space *mapping, struct file_ra_state *, struct file *, loff_t *, read_descriptor_t *, read_actor_t); -extern void -file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); +extern void file_ra_state_init(struct file *); extern ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs); extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, @@ -1545,12 +1545,16 @@ } #endif +static inline struct file_ra_state *get_ra_state(struct file *f) +{ + return (struct file_ra_state *)(f+1); +} static inline void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor) { do_generic_mapping_read(filp->f_mapping, - &filp->f_ra, + get_ra_state(filp), filp, ppos, desc, --- linux-2.6.13-rc6/include/linux/slab.h 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/include/linux/slab.h 2005-08-18 09:46:40.000000000 +0200 @@ -125,6 +125,7 @@ extern kmem_cache_t *names_cachep; extern kmem_cache_t *files_cachep; extern kmem_cache_t *filp_cachep; +extern kmem_cache_t *filp_ra_cachep; extern kmem_cache_t *fs_cachep; extern kmem_cache_t *signal_cachep; extern kmem_cache_t *sighand_cachep; --- linux-2.6.13-rc6/mm/readahead.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/mm/readahead.c 2005-08-18 10:41:13.000000000 +0200 @@ -33,9 +33,10 @@ * memset *ra to zero. */ void -file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping) +file_ra_state_init(struct file *file) { - ra->ra_pages = mapping->backing_dev_info->ra_pages; + struct file_ra_state *ra = get_ra_state(file); + ra->ra_pages = file->f_mapping->host->i_mapping->backing_dev_info->ra_pages; ra->prev_page = -1; } --- linux-2.6.13-rc6/mm/filemap.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/mm/filemap.c 2005-08-18 10:46:53.000000000 +0200 @@ -1187,7 +1187,7 @@ int error; struct file *file = area->vm_file; struct address_space *mapping = file->f_mapping; - struct file_ra_state *ra = &file->f_ra; + struct file_ra_state *ra = get_ra_state(file); struct inode *inode = mapping->host; struct page *page; unsigned long size, pgoff; @@ -1243,7 +1243,7 @@ inc_page_state(pgmajfault); } did_readaround = 1; - ra_pages = max_sane_readahead(file->f_ra.ra_pages); + ra_pages = max_sane_readahead(ra->ra_pages); if (ra_pages) { pgoff_t start = 0; --- linux-2.6.13-rc6/mm/fadvise.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/mm/fadvise.c 2005-08-18 10:44:16.000000000 +0200 @@ -28,6 +28,7 @@ struct file *file = fget(fd); struct address_space *mapping; struct backing_dev_info *bdi; + struct file_ra_state *ra; loff_t endbyte; pgoff_t start_index; pgoff_t end_index; @@ -54,15 +55,20 @@ bdi = mapping->backing_dev_info; + /* + * FIXME : Are we sure here this 'file' has ra_state available ? + */ + ra = get_ra_state(file); + switch (advice) { case POSIX_FADV_NORMAL: - file->f_ra.ra_pages = bdi->ra_pages; + ra->ra_pages = bdi->ra_pages; break; case POSIX_FADV_RANDOM: - file->f_ra.ra_pages = 0; + ra->ra_pages = 0; break; case POSIX_FADV_SEQUENTIAL: - file->f_ra.ra_pages = bdi->ra_pages * 2; + ra->ra_pages = bdi->ra_pages * 2; break; case POSIX_FADV_WILLNEED: case POSIX_FADV_NOREUSE: --- linux-2.6.13-rc6/fs/file_table.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/file_table.c 2005-08-18 10:46:53.000000000 +0200 @@ -53,16 +53,20 @@ spin_unlock_irqrestore(&filp_count_lock, flags); } +/* + * a file can belong to different kmem_cache (filp_cache or filp_ra_cache), + * so let kfree() find it + */ static inline void file_free(struct file *f) { - kmem_cache_free(filp_cachep, f); + kfree(f); } /* Find an unused file structure and return a pointer to it. * Returns NULL, if there are no more free file structures or * we run out of memory. */ -struct file *get_empty_filp(void) +struct file *get_empty_filp(int need_read_ahead) { static int old_max; struct file * f; @@ -74,11 +78,11 @@ !capable(CAP_SYS_ADMIN)) goto over; - f = kmem_cache_alloc(filp_cachep, GFP_KERNEL); + f = kmem_cache_alloc(need_read_ahead ? filp_ra_cachep : filp_cachep, GFP_KERNEL); if (f == NULL) goto fail; - memset(f, 0, sizeof(*f)); + memset(f, 0, need_read_ahead ? sizeof(struct file) + sizeof(struct file_ra_state) : sizeof(struct file)); if (security_file_alloc(f)) goto fail_sec; --- linux-2.6.13-rc6/fs/open.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/open.c 2005-08-18 10:30:35.000000000 +0200 @@ -778,7 +778,7 @@ int error; error = -ENFILE; - f = get_empty_filp(); + f = get_empty_filp(FILP_WITH_READ_AHEAD); if (!f) goto cleanup_dentry; f->f_flags = flags; @@ -804,7 +804,7 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); + file_ra_state_init(f); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { --- linux-2.6.13-rc6/fs/dcache.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/dcache.c 2005-08-18 09:48:41.000000000 +0200 @@ -1703,8 +1703,10 @@ /* SLAB cache for __getname() consumers */ kmem_cache_t *names_cachep; -/* SLAB cache for file structures */ +/* SLAB cache for file structures without read ahead state data */ kmem_cache_t *filp_cachep; +/* SLAB cache for file structures with read ahead state data */ +kmem_cache_t *filp_ra_cachep; EXPORT_SYMBOL(d_genocide); @@ -1733,6 +1735,9 @@ filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, filp_ctor, filp_dtor); + filp_ra_cachep = kmem_cache_create("filp_ra", sizeof(struct file) + sizeof(struct file_ra_state), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, filp_ctor, filp_dtor); + dcache_init(mempages); inode_init(mempages); files_init(mempages); --- linux-2.6.13-rc6/net/socket.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/net/socket.c 2005-08-18 10:30:35.000000000 +0200 @@ -375,7 +375,7 @@ fd = get_unused_fd(); if (fd >= 0) { - struct file *file = get_empty_filp(); + struct file *file = get_empty_filp(FILP_NO_READ_AHEAD); if (!file) { put_unused_fd(fd); --- linux-2.6.13-rc6/fs/eventpoll.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/eventpoll.c 2005-08-18 10:30:35.000000000 +0200 @@ -717,7 +717,7 @@ /* Get an ready to use file */ error = -ENFILE; - file = get_empty_filp(); + file = get_empty_filp(FILP_NO_READ_AHEAD); if (!file) goto eexit_1; --- linux-2.6.13-rc6/kernel/futex.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/kernel/futex.c 2005-08-18 10:30:35.000000000 +0200 @@ -661,7 +661,7 @@ ret = get_unused_fd(); if (ret < 0) goto out; - filp = get_empty_filp(); + filp = get_empty_filp(FILP_NO_READ_AHEAD); if (!filp) { put_unused_fd(ret); ret = -ENFILE; --- linux-2.6.13-rc6/mm/shmem.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/mm/shmem.c 2005-08-18 10:30:35.000000000 +0200 @@ -2272,7 +2272,7 @@ goto put_memory; error = -ENFILE; - file = get_empty_filp(); + file = get_empty_filp(FILP_WITH_READ_AHEAD); if (!file) goto put_dentry; --- linux-2.6.13-rc6/fs/pipe.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/pipe.c 2005-08-18 10:30:35.000000000 +0200 @@ -723,11 +723,11 @@ int i,j; error = -ENFILE; - f1 = get_empty_filp(); + f1 = get_empty_filp(FILP_NO_READ_AHEAD); if (!f1) goto no_files; - f2 = get_empty_filp(); + f2 = get_empty_filp(FILP_NO_READ_AHEAD); if (!f2) goto close_f1; --- linux-2.6.13-rc6/fs/inotify.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/inotify.c 2005-08-18 10:30:35.000000000 +0200 @@ -865,7 +865,7 @@ if (fd < 0) return fd; - filp = get_empty_filp(); + filp = get_empty_filp(FILP_NO_READ_AHEAD); if (!filp) { ret = -ENFILE; goto out_put_fd; --- linux-2.6.13-rc6/fs/hugetlbfs/inode.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/fs/hugetlbfs/inode.c 2005-08-18 10:30:35.000000000 +0200 @@ -785,7 +785,7 @@ goto out_shm_unlock; error = -ENFILE; - file = get_empty_filp(); + file = get_empty_filp(FILP_WITH_READ_AHEAD); if (!file) goto out_dentry; --- linux-2.6.13-rc6/arch/ia64/kernel/perfmon.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/arch/ia64/kernel/perfmon.c 2005-08-18 10:36:28.000000000 +0200 @@ -2157,7 +2157,7 @@ ret = -ENFILE; - file = get_empty_filp(); + file = get_empty_filp(FILP_WITH_READ_AHEAD); if (!file) goto out; /* --- linux-2.6.13-rc6/drivers/infiniband/core/uverbs_main.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/drivers/infiniband/core/uverbs_main.c 2005-08-18 10:30:35.000000000 +0200 @@ -367,7 +367,7 @@ if (file->fd < 0) return file->fd; - filp = get_empty_filp(); + filp = get_empty_filp(FILP_NO_READ_AHEAD); if (!filp) { put_unused_fd(file->fd); return -ENFILE; --- linux-2.6.13-rc6/mm/tiny-shmem.c 2005-08-07 20:18:56.000000000 +0200 +++ linux-2.6.13-rc6-ed/mm/tiny-shmem.c 2005-08-18 10:30:35.000000000 +0200 @@ -68,7 +68,7 @@ goto put_memory; error = -ENFILE; - file = get_empty_filp(); + file = get_empty_filp(FILP_WITH_READ_AHEAD); if (!file) goto put_dentry; | |