From: Andrew Morton <akpm@zip.com.au>
To: Linus Torvalds <torvalds@transmeta.com>
Cc: lkml <linux-kernel@vger.kernel.org>
Subject: [patch 10/21] batched removal of pages from the LRU
Date: Sun, 11 Aug 2002 00:39:12 -0700 [thread overview]
Message-ID: <3D5614A0.ECA8FD88@zip.com.au> (raw)
Convert all the bulk callers of lru_cache_del() to use the batched
pagevec_lru_del() function.
Change truncate_complete_page() to not delete the page from the LRU.
Do it in page_cache_release() instead. (This reintroduces the problem
with final-release-from-interrupt. THat gets fixed further on).
This patch changes the truncate locking somewhat. The removal from the
LRU now happens _after_ the page has been removed from the
address_space and has been unlocked. So there is now a window where
the shrink_cache code can discover the to-be-freed page via the LRU
list. But that's OK - the page is clean, its buffers (if any) are
clean. It's not attached to any mapping.
filemap.c | 79 +++++++++++++++++++++++++++++++++-----------------------------
swap.c | 2 -
2 files changed, 44 insertions(+), 37 deletions(-)
--- 2.5.31/mm/filemap.c~batched-lru-del Sun Aug 11 00:20:33 2002
+++ 2.5.31-akpm/mm/filemap.c Sun Aug 11 00:21:02 2002
@@ -118,10 +118,10 @@ void invalidate_inode_pages(struct inode
struct list_head *head, *curr;
struct page * page;
struct address_space *mapping = inode->i_mapping;
+ struct pagevec lru_pvec;
head = &mapping->clean_pages;
-
- spin_lock(&pagemap_lru_lock);
+ pagevec_init(&lru_pvec);
write_lock(&mapping->page_lock);
curr = head->next;
@@ -143,10 +143,10 @@ void invalidate_inode_pages(struct inode
if (page_count(page) != 1)
goto unlock;
- __lru_cache_del(page);
__remove_from_page_cache(page);
unlock_page(page);
- page_cache_release(page);
+ if (!pagevec_add(&lru_pvec, page))
+ __pagevec_lru_del(&lru_pvec);
continue;
unlock:
unlock_page(page);
@@ -154,7 +154,7 @@ unlock:
}
write_unlock(&mapping->page_lock);
- spin_unlock(&pagemap_lru_lock);
+ pagevec_lru_del(&lru_pvec);
}
static int do_invalidatepage(struct page *page, unsigned long offset)
@@ -174,16 +174,14 @@ static inline void truncate_partial_page
}
/*
- * If truncate can remove the fs-private metadata from the page, it
- * removes the page from the LRU immediately. This because some other thread
- * of control (eg, sendfile) may have a reference to the page. But dropping
- * the final reference to an LRU page in interrupt context is illegal - it may
- * deadlock over pagemap_lru_lock.
+ * If truncate cannot remove the fs-private metadata from the page, the page
+ * becomes anonymous. It will be left on the LRU and may even be mapped into
+ * user pagetables if we're racing with filemap_nopage().
*/
static void truncate_complete_page(struct page *page)
{
- if (!PagePrivate(page) || do_invalidatepage(page, 0))
- lru_cache_del(page);
+ if (PagePrivate(page))
+ do_invalidatepage(page, 0);
ClearPageDirty(page);
ClearPageUptodate(page);
@@ -204,8 +202,10 @@ static int truncate_list_pages(struct ad
struct list_head *curr;
struct page * page;
int unlocked = 0;
+ struct pagevec release_pvec;
- restart:
+ pagevec_init(&release_pvec);
+restart:
curr = head->next;
while (curr != head) {
unsigned long offset;
@@ -225,18 +225,17 @@ static int truncate_list_pages(struct ad
list_add_tail(head, curr);
write_unlock(&mapping->page_lock);
wait_on_page_writeback(page);
- page_cache_release(page);
+ if (!pagevec_add(&release_pvec, page))
+ __pagevec_release(&release_pvec);
unlocked = 1;
write_lock(&mapping->page_lock);
goto restart;
}
list_del(head);
- if (!failed)
- /* Restart after this page */
+ if (!failed) /* Restart after this page */
list_add(head, curr);
- else
- /* Restart on this page */
+ else /* Restart on this page */
list_add_tail(head, curr);
write_unlock(&mapping->page_lock);
@@ -246,25 +245,27 @@ static int truncate_list_pages(struct ad
if (*partial && (offset + 1) == start) {
truncate_partial_page(page, *partial);
*partial = 0;
- } else
+ } else {
truncate_complete_page(page);
-
+ }
unlock_page(page);
- } else
+ } else {
wait_on_page_locked(page);
-
- page_cache_release(page);
-
- if (need_resched()) {
- __set_current_state(TASK_RUNNING);
- schedule();
}
-
+ if (!pagevec_add(&release_pvec, page))
+ __pagevec_release(&release_pvec);
+ cond_resched();
write_lock(&mapping->page_lock);
goto restart;
}
curr = curr->next;
}
+ if (pagevec_count(&release_pvec)) {
+ write_unlock(&mapping->page_lock);
+ pagevec_release(&release_pvec);
+ write_lock(&mapping->page_lock);
+ unlocked = 1;
+ }
return unlocked;
}
@@ -362,8 +363,10 @@ static int invalidate_list_pages2(struct
struct list_head *curr;
struct page * page;
int unlocked = 0;
+ struct pagevec release_pvec;
- restart:
+ pagevec_init(&release_pvec);
+restart:
curr = head->prev;
while (curr != head) {
page = list_entry(curr, struct page, list);
@@ -380,7 +383,8 @@ static int invalidate_list_pages2(struct
goto restart;
}
- __unlocked = invalidate_this_page2(mapping, page, curr, head);
+ __unlocked = invalidate_this_page2(mapping,
+ page, curr, head);
unlock_page(page);
unlocked |= __unlocked;
if (!__unlocked) {
@@ -398,15 +402,18 @@ static int invalidate_list_pages2(struct
wait_on_page_locked(page);
}
- page_cache_release(page);
- if (need_resched()) {
- __set_current_state(TASK_RUNNING);
- schedule();
- }
-
+ if (!pagevec_add(&release_pvec, page))
+ __pagevec_release(&release_pvec);
+ cond_resched();
write_lock(&mapping->page_lock);
goto restart;
}
+ if (pagevec_count(&release_pvec)) {
+ write_unlock(&mapping->page_lock);
+ pagevec_release(&release_pvec);
+ write_lock(&mapping->page_lock);
+ unlocked = 1;
+ }
return unlocked;
}
--- 2.5.31/mm/swap.c~batched-lru-del Sun Aug 11 00:20:33 2002
+++ 2.5.31-akpm/mm/swap.c Sun Aug 11 00:21:02 2002
@@ -115,7 +115,7 @@ void __pagevec_release(struct pagevec *p
if (!put_page_testzero(page))
continue;
- if (!lock_held && PageLRU(page)) {
+ if (!lock_held) {
spin_lock(&pagemap_lru_lock);
lock_held = 1;
}
.
reply other threads:[~2002-08-11 7:26 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3D5614A0.ECA8FD88@zip.com.au \
--to=akpm@zip.com.au \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@transmeta.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.