generic_file_aio_read can read directly from the tail. No need to unpack Signed-off-by: Dave Kleikamp <shaggy@xxxxxxxxxxxxxxxxxx> --- include/linux/vm_file_tail.h | 13 ++++++++++ mm/file_tail.c | 54 +++++++++++++++++++++++++++++++++++++++++++ mm/filemap.c | 4 ++- 3 files changed, 70 insertions(+), 1 deletion(-) diff -Nurp linux007/include/linux/vm_file_tail.h linux008/include/linux/vm_file_tail.h --- linux007/include/linux/vm_file_tail.h 2007-11-08 10:49:46.000000000 -0600 +++ linux008/include/linux/vm_file_tail.h 2007-11-08 10:49:46.000000000 -0600 @@ -53,6 +53,18 @@ static inline void vm_file_tail_unpack_i vm_file_tail_unpack(mapping); } +extern int __vm_file_tail_read(struct file *, loff_t *, read_descriptor_t *); + +static inline int vm_file_tail_read(struct file *filp, loff_t *ppos, + read_descriptor_t *desc) +{ + struct address_space *mapping = filp->f_mapping; + unsigned long index = *ppos >> PAGE_CACHE_SHIFT; + + if (mapping->tail && index == vm_file_tail_index(mapping)) + return __vm_file_tail_read(filp, ppos, desc); + return 0; +} #else /* !CONFIG_VM_FILE_TAILS */ #define vm_file_tail_packed(mapping) 0 @@ -60,6 +72,7 @@ static inline void vm_file_tail_unpack_i #define vm_file_tail_pack(page) 0 #define vm_file_tail_unpack(mapping) do {} while (0) #define vm_file_tail_unpack_index(mapping, index) do {} while (0) +#define vm_file_tail_read(filp, ppos, desc) 0 #endif /* CONFIG_VM_FILE_TAILS */ diff -Nurp linux007/mm/file_tail.c linux008/mm/file_tail.c --- linux007/mm/file_tail.c 2007-11-08 10:49:46.000000000 -0600 +++ linux008/mm/file_tail.c 2007-11-08 10:49:46.000000000 -0600 @@ -178,3 +178,57 @@ void __vm_file_tail_unpack_on_resize(str vm_file_tail_free(inode->i_mapping); } EXPORT_SYMBOL(__vm_file_tail_unpack_on_resize); + +/* + * Copy tail data to user buffer + * + * Returns 1 on success + */ +int __vm_file_tail_read(struct file *filp, loff_t *ppos, + read_descriptor_t *desc) +{ + unsigned long count = desc->count; + unsigned int flags; + unsigned long left; + struct address_space *mapping = filp->f_mapping; + unsigned long offset; + unsigned long index = *ppos >> PAGE_CACHE_SHIFT; + unsigned long size; + + if (fault_in_pages_writeable(desc->arg.buf, count)) + /* + * Keep this simple since this path is an optimization. Let + * the tricky stuff get handled in the fallback path. + */ + return 0; + + spin_lock_irqsave(&mapping->tail_lock, flags); + + offset = *ppos & ~PAGE_CACHE_MASK; + if (!mapping->tail || index != vm_file_tail_index(mapping) || + offset >= vm_file_tail_length(mapping)) { + spin_unlock_irqrestore(&mapping->tail_lock, flags); + return 0; + } + + size = vm_file_tail_length(mapping) - offset; + if (size > count) + size = count; + + left = __copy_to_user_inatomic(desc->arg.buf, + (char *)mapping->tail + offset, size); + + spin_unlock_irqrestore(&mapping->tail_lock, flags); + + if (left) { + size -= left; + desc->error = -EFAULT; + } + desc->count = count - size; + desc->written += size; + desc->arg.buf += size; + *ppos += size; + file_accessed(filp); + + return 1; +} diff -Nurp linux007/mm/filemap.c linux008/mm/filemap.c --- linux007/mm/filemap.c 2007-11-08 10:49:46.000000000 -0600 +++ linux008/mm/filemap.c 2007-11-08 10:49:46.000000000 -0600 @@ -1195,7 +1195,9 @@ generic_file_aio_read(struct kiocb *iocb if (desc.count == 0) continue; desc.error = 0; - do_generic_file_read(filp,ppos,&desc,file_read_actor); + if (!vm_file_tail_read(filp, ppos, &desc)) + do_generic_file_read(filp, ppos, &desc, + file_read_actor); retval += desc.written; if (desc.error) { retval = retval ?: desc.error; - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html