]> git.neil.brown.name Git - history.git/commitdiff
Fix fixed fadvice length handling
authorLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 30 Apr 2004 14:28:54 +0000 (07:28 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 30 Apr 2004 14:28:54 +0000 (07:28 -0700)
 - 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.

mm/fadvise.c

index 0f0b750f82d79e167a446ab0d44185e612de5c13..e6d1c32d85feb1f81d8c09c663cb8648b818e5ec 100644 (file)
@@ -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;