aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-30 07:28:54 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-30 07:28:54 -0700
commit2fc0873fe08fd1d01678ee022db184ee5a3bc817 (patch)
tree07b256ff007496f075c2e36a3164d9ff0f2a9f40 /mm
parent61a948c4df03e6383e931b016b60dad546c5d66f (diff)
downloadhistory-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.c32
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;