From: Badari Pulavarty Various fixes to hugetlbfs_read() support - handle HOLES correcty - clean up weird looking loop condition reported by Ken Chen - integrated "not updating file offset after read" fix by Ken Chen - holding i_mutex to prevent any unwanted interactions with truncate Signed-off-by: Badari Pulavarty Cc: William Irwin Cc: Nishanth Aravamudan Cc: Nick Piggin Acked-by: Ken Chen Cc: Adam Litke Cc: David Gibson Signed-off-by: Andrew Morton --- diff -puN fs/hugetlbfs/inode.c~hugetlbfs-read-support-fix-2-fix fs/hugetlbfs/inode.c --- a/fs/hugetlbfs/inode.c~hugetlbfs-read-support-fix-2-fix +++ a/fs/hugetlbfs/inode.c @@ -228,11 +228,13 @@ static ssize_t hugetlbfs_read(struct fil struct address_space *mapping = filp->f_mapping; struct inode *inode = mapping->host; unsigned long index = *ppos >> HPAGE_SHIFT; + unsigned long offset = *ppos & ~HPAGE_MASK; unsigned long end_index; loff_t isize; - unsigned long offset; ssize_t retval = 0; + mutex_lock(&inode->i_mutex); + /* validate length */ if (len == 0) goto out; @@ -241,7 +243,6 @@ static ssize_t hugetlbfs_read(struct fil if (!isize) goto out; - offset = *ppos & ~HPAGE_MASK; end_index = (isize - 1) >> HPAGE_SHIFT; for (;;) { struct page *page; @@ -263,18 +264,23 @@ static ssize_t hugetlbfs_read(struct fil page = find_get_page(mapping, index); if (unlikely(page == NULL)) { /* - * We can't find the page in the cache - bail out ? + * We have a HOLE, zero out the user-buffer for the + * length of the hole or request. */ - goto out; + ret = len < nr ? len : nr; + if (clear_user(buf, ret)) + ret = -EFAULT; + } else { + /* + * We have the page, copy it to user space buffer. + */ + ret = hugetlbfs_read_actor(page, offset, buf, len, nr); } - /* - * Ok, we have the page, copy it to user space buffer. - */ - ret = hugetlbfs_read_actor(page, offset, buf, len, nr); if (ret < 0) { if (retval == 0) retval = ret; - page_cache_release(page); + if (page) + page_cache_release(page); goto out; } @@ -284,12 +290,16 @@ static ssize_t hugetlbfs_read(struct fil index += offset >> HPAGE_SHIFT; offset &= ~HPAGE_MASK; - page_cache_release(page); - if (ret == nr && len) - continue; - goto out; + if (page) + page_cache_release(page); + + /* short read or no more work */ + if ((ret != nr) || (len == 0)) + break; } out: + *ppos = ((loff_t)index << HPAGE_SHIFT) + offset; + mutex_unlock(&inode->i_mutex); return retval; } _