diff options
author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2013-02-11 15:40:45 +0900 |
---|---|---|
committer | Daniel Phillips <daniel@tux3.org> | 2013-02-11 15:40:45 +0900 |
commit | 9528403904fec1bbf9999fa910374170457d466b (patch) | |
tree | 0062c48c158cb9595d3036591302ef27fc6583bf | |
parent | 46de4a7f9511547dfb8d4b1f6506cdae9a9d6d2b (diff) | |
download | linux-tux3-9528403904fec1bbf9999fa910374170457d466b.tar.gz |
tux3: Free pages related to inode for evict_inode() path
We call free_forked_buffers() on evict_inode() path to free forked
buffers. Currently, free_forked_buffers() checks all pages even if
inode was specified, to try to free forked pages as possible as early.
But evict_inode() is called arbitrary timing, and pages on
sb->forked_buffers list would usually be under I/O path. Because
free_forked_buffers() is called for each end of commit (i.e. only if
there is race with frontend and commit, pages are remaining on
forked_buffers after commit).
So, this changes to not try to free unrelated pages if inode was
specified to free_forked_buffers().
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
-rw-r--r-- | fs/tux3/buffer.h | 2 | ||||
-rw-r--r-- | fs/tux3/buffer_fork.c | 19 | ||||
-rw-r--r-- | fs/tux3/inode.c | 2 |
3 files changed, 12 insertions, 11 deletions
diff --git a/fs/tux3/buffer.h b/fs/tux3/buffer.h index 0b3865661a8b4..e6c31a63fc3ce 100644 --- a/fs/tux3/buffer.h +++ b/fs/tux3/buffer.h @@ -151,7 +151,7 @@ static inline int buffer_forked(struct buffer_head *buffer) return PageForked(buffer->b_page); } -void free_forked_buffers(struct sb *sb, struct inode *inode, int umount); +void free_forked_buffers(struct sb *sb, struct inode *inode, int force); struct buffer_head *blockdirty(struct buffer_head *buffer, unsigned newdelta); struct page *pagefork_for_blockdirty(struct page *oldpage, unsigned newdelta); int bufferfork_to_invalidate(struct address_space *mapping, struct page *page); diff --git a/fs/tux3/buffer_fork.c b/fs/tux3/buffer_fork.c index 9892ad77e7735..3cf1e25f278ec 100644 --- a/fs/tux3/buffer_fork.c +++ b/fs/tux3/buffer_fork.c @@ -113,17 +113,17 @@ static int is_freeable_forked(struct buffer_head *buffer, struct page *page) } /* - * Try to free forked page. If it is called from umount or evict_inode + * Try to free forked page. (If it is called from umount or evict_inode * path, there should be no referencer. So we free forked page - * forcefully. + * forcefully.) * - * inode: If caller is evicting inode, pass inode. Otherwise NULL. - * umount: If caller is umount path, 1. Otherwise 0. + * inode: Free only if page is related to this inode. + * force: If true, even if refcount != 0 try to free. * * FIXME: we need the better way, instead of polling the freeable * forked pages periodically. */ -void free_forked_buffers(struct sb *sb, struct inode *inode, int umount) +void free_forked_buffers(struct sb *sb, struct inode *inode, int force) { struct link free_list, *node, *prev, *n; @@ -134,14 +134,15 @@ void free_forked_buffers(struct sb *sb, struct inode *inode, int umount) link_for_each_safe(node, prev, n, &sb->forked_buffers) { struct buffer_head *buffer = buffer_link_entry(node); struct page *page = buffer->b_page; - int force = 0; trace_on("buffer %p, page %p, count %u", buffer, page, page_count(page)); - /* We have to free this forked page forcefully */ - if (umount || (inode && inode->i_mapping == page->mapping)) - force = 1; + if (inode) { + /* Free only if page is related to inode */ + if (page->mapping != inode->i_mapping) + continue; + } #ifdef DISABLE_ASYNC_BACKEND /* The page should already be submitted if no async frontend */ diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c index e6319ec95affd..b88be3a44f6f0 100644 --- a/fs/tux3/inode.c +++ b/fs/tux3/inode.c @@ -715,7 +715,7 @@ void tux3_evict_inode(struct inode *inode) * refcount to free). If impossible, we would want to use * per-inode forked-buffers list, instead. */ - free_forked_buffers(sb, inode, 0); + free_forked_buffers(sb, inode, 1); clear_inode(inode); free_xcache(inode); |