Commit 2fc0873f authored by Linus Torvalds's avatar Linus Torvalds

Fix fixed fadvice length handling

 - Correctly handle wraparound on offset+len
 - fix FADV_WILLNEED handling of non-page-aligned (offset+len)

Let's hope we don't need to fix the fixed fix.
parent 61a948c4
...@@ -25,8 +25,10 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -25,8 +25,10 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
struct file *file = fget(fd); struct file *file = fget(fd);
struct address_space *mapping; struct address_space *mapping;
struct backing_dev_info *bdi; struct backing_dev_info *bdi;
loff_t endbyte;
pgoff_t start_index; pgoff_t start_index;
pgoff_t end_index; pgoff_t end_index;
unsigned long nrpages;
int ret = 0; int ret = 0;
if (!file) if (!file)
...@@ -38,8 +40,10 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -38,8 +40,10 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
goto out; goto out;
} }
if (len == 0) /* 0 == "all data following offset" */ /* Careful about overflows. Len == 0 means "as much as possible" */
len = -1; endbyte = offset + len;
if (!len || endbyte < len)
endbyte = -1;
bdi = mapping->backing_dev_info; bdi = mapping->backing_dev_info;
...@@ -59,18 +63,32 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ...@@ -59,18 +63,32 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
/* First and last PARTIAL page! */
start_index = offset >> PAGE_CACHE_SHIFT;
end_index = (endbyte-1) >> PAGE_CACHE_SHIFT;
/* Careful about overflow on the "+1" */
nrpages = end_index - start_index + 1;
if (!nrpages)
nrpages = ~0UL;
ret = force_page_cache_readahead(mapping, file, ret = force_page_cache_readahead(mapping, file,
offset >> PAGE_CACHE_SHIFT, start_index,
max_sane_readahead(len >> PAGE_CACHE_SHIFT)); max_sane_readahead(nrpages));
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
break; break;
case POSIX_FADV_DONTNEED: case POSIX_FADV_DONTNEED:
if (!bdi_write_congested(mapping->backing_dev_info)) if (!bdi_write_congested(mapping->backing_dev_info))
filemap_flush(mapping); filemap_flush(mapping);
start_index = (offset + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
end_index = ((offset + len) >> PAGE_CACHE_SHIFT) - 1; /* First and last FULL page! */
invalidate_mapping_pages(mapping, start_index, end_index); start_index = (offset + (PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
end_index = (endbyte >> PAGE_CACHE_SHIFT);
if (end_index > start_index)
invalidate_mapping_pages(mapping, start_index, end_index-1);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment