diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-30 07:28:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-30 07:28:54 -0700 |
commit | 2fc0873fe08fd1d01678ee022db184ee5a3bc817 (patch) | |
tree | 07b256ff007496f075c2e36a3164d9ff0f2a9f40 /mm | |
parent | 61a948c4df03e6383e931b016b60dad546c5d66f (diff) | |
download | history-2fc0873fe08fd1d01678ee022db184ee5a3bc817.tar.gz |
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.
Diffstat (limited to 'mm')
-rw-r--r-- | mm/fadvise.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/mm/fadvise.c b/mm/fadvise.c index 0f0b750f82d79e..e6d1c32d85feb1 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -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 address_space *mapping; struct backing_dev_info *bdi; + loff_t endbyte; pgoff_t start_index; pgoff_t end_index; + unsigned long nrpages; int ret = 0; if (!file) @@ -38,8 +40,10 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) goto out; } - if (len == 0) /* 0 == "all data following offset" */ - len = -1; + /* Careful about overflows. Len == 0 means "as much as possible" */ + endbyte = offset + len; + if (!len || endbyte < len) + endbyte = -1; bdi = mapping->backing_dev_info; @@ -59,18 +63,32 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) ret = -EINVAL; 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, - offset >> PAGE_CACHE_SHIFT, - max_sane_readahead(len >> PAGE_CACHE_SHIFT)); + start_index, + max_sane_readahead(nrpages)); if (ret > 0) ret = 0; break; case POSIX_FADV_DONTNEED: if (!bdi_write_congested(mapping->backing_dev_info)) filemap_flush(mapping); - start_index = (offset + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT; - end_index = ((offset + len) >> PAGE_CACHE_SHIFT) - 1; - invalidate_mapping_pages(mapping, start_index, end_index); + + /* First and last FULL page! */ + 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; default: ret = -EINVAL; |