diff -purN -X /home/mbligh/.diff.exclude 550-gang_lookup_next/mm/page-writeback.c 555-aio-gang_lookup-fix/mm/page-writeback.c --- 550-gang_lookup_next/mm/page-writeback.c 2004-02-28 11:21:41.000000000 -0800 +++ 555-aio-gang_lookup-fix/mm/page-writeback.c 2004-02-28 11:21:53.000000000 -0800 @@ -576,7 +576,7 @@ static ssize_t operate_on_page_range(str { pgoff_t first = pos >> PAGE_CACHE_SHIFT; pgoff_t last = (pos + count - 1) >> PAGE_CACHE_SHIFT; /* inclusive */ - pgoff_t next = first; + pgoff_t next = first, curr = first; struct pagevec pvec; ssize_t ret = 0, bytes = 0; int i; @@ -585,25 +585,25 @@ static ssize_t operate_on_page_range(str return 0; pagevec_init(&pvec, 0); - while (pagevec_lookup(&pvec, mapping, next, + while (pagevec_lookup(&pvec, mapping, &next, min((pgoff_t)PAGEVEC_SIZE, last - next + 1))) { for (i = 0; i < pagevec_count(&pvec); i++) { struct page *page = pvec.pages[i]; - lock_page(page); /* stabilise ->index */ - if (!page->mapping) { /* truncated */ - unlock_page(page); - next++; - continue; - } - next = page->index + 1; - ret = (*operator)(page); - if (ret == -EIOCBRETRY) + curr = page->index; + if ((curr > next) || !page->mapping) /* truncated ?*/ { + curr = next; break; - if (PageError(page)) { - if (!ret) - ret = -EIO; + } else { + ret = (*operator)(page); + if (ret == -EIOCBRETRY) + break; + if (PageError(page)) { + if (!ret) + ret = -EIO; + } } + curr++; if (next > last) break; } @@ -611,7 +611,7 @@ static ssize_t operate_on_page_range(str if ((next > last) || (ret == -EIOCBRETRY)) break; } - bytes = (next << PAGE_CACHE_SHIFT) - pos; + bytes = (curr << PAGE_CACHE_SHIFT) - pos; if (bytes > count) bytes = count; return (bytes && (!ret || (ret == -EIOCBRETRY))) ? bytes : ret; @@ -619,7 +619,6 @@ static ssize_t operate_on_page_range(str static int page_waiter(struct page *page) { - unlock_page(page); return wait_on_page_writeback_wq(page, current->io_wait); } @@ -636,6 +635,11 @@ static int page_writer(struct page *page .nr_to_write = 1, }; + lock_page(page); + if (!page->mapping) { /* truncated */ + unlock_page(page); + return 0; + } if (!test_clear_page_dirty(page)) { unlock_page(page); return 0;