aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2004-09-13 17:46:13 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-13 17:46:13 -0700
commit669d88ec23e11b44f6f039533c8b4a5b3adae812 (patch)
treedcbc0edc33944fb5dfbe33ec9c539e16bba88820 /mm
parent35049977eaf4829c0d3cb3c911d07110ca95c0c4 (diff)
downloadhistory-669d88ec23e11b44f6f039533c8b4a5b3adae812.tar.gz
[PATCH] shmem: avoid the shmem_inodes list
If we're thinking about shmem scalability... isn't it silly that each shmem object is added to the shmem_inodes list on creation, and removed on deletion, yet the only use for that list is in swapoff (shmem_unuse)? Call it shmem_swaplist; shmem_writepage add inode to swaplist when first swap allocated (usually never); shmem_delete_inode remove inode from the list after truncating (if called before, inode could be re-added to it). Inode can remain on the swaplist after all its pages are swapped back in, just be lazy about it; but if shmem_unuse finds swapped count now 0, save itself time by then removing that inode from the swaplist. Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/shmem.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index db9078676ebfa3..0ba0c8e7890648 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -179,8 +179,8 @@ static struct backing_dev_info shmem_backing_dev_info = {
.unplug_io_fn = default_unplug_io_fn,
};
-static LIST_HEAD(shmem_inodes);
-static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(shmem_swaplist);
+static spinlock_t shmem_swaplist_lock = SPIN_LOCK_UNLOCKED;
static void shmem_free_block(struct inode *inode)
{
@@ -604,12 +604,14 @@ static void shmem_delete_inode(struct inode *inode)
struct shmem_inode_info *info = SHMEM_I(inode);
if (inode->i_op->truncate == shmem_truncate) {
- spin_lock(&shmem_ilock);
- list_del(&info->list);
- spin_unlock(&shmem_ilock);
shmem_unacct_size(info->flags, inode->i_size);
inode->i_size = 0;
shmem_truncate(inode);
+ if (!list_empty(&info->swaplist)) {
+ spin_lock(&shmem_swaplist_lock);
+ list_del_init(&info->swaplist);
+ spin_unlock(&shmem_swaplist_lock);
+ }
}
if (sbinfo) {
BUG_ON(inode->i_blocks);
@@ -721,22 +723,23 @@ found:
*/
int shmem_unuse(swp_entry_t entry, struct page *page)
{
- struct list_head *p;
+ struct list_head *p, *next;
struct shmem_inode_info *info;
int found = 0;
- spin_lock(&shmem_ilock);
- list_for_each(p, &shmem_inodes) {
- info = list_entry(p, struct shmem_inode_info, list);
-
- if (info->swapped && shmem_unuse_inode(info, entry, page)) {
+ spin_lock(&shmem_swaplist_lock);
+ list_for_each_safe(p, next, &shmem_swaplist) {
+ info = list_entry(p, struct shmem_inode_info, swaplist);
+ if (!info->swapped)
+ list_del_init(&info->swaplist);
+ else if (shmem_unuse_inode(info, entry, page)) {
/* move head to start search for next from here */
- list_move_tail(&shmem_inodes, &info->list);
+ list_move_tail(&shmem_swaplist, &info->swaplist);
found = 1;
break;
}
}
- spin_unlock(&shmem_ilock);
+ spin_unlock(&shmem_swaplist_lock);
return found;
}
@@ -778,6 +781,12 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
shmem_swp_set(info, entry, swap.val);
shmem_swp_unmap(entry);
spin_unlock(&info->lock);
+ if (list_empty(&info->swaplist)) {
+ spin_lock(&shmem_swaplist_lock);
+ /* move instead of add in case we're racing */
+ list_move_tail(&info->swaplist, &shmem_swaplist);
+ spin_unlock(&shmem_swaplist_lock);
+ }
unlock_page(page);
return 0;
}
@@ -1226,6 +1235,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
memset(info, 0, (char *)inode - (char *)info);
spin_lock_init(&info->lock);
mpol_shared_policy_init(&info->policy);
+ INIT_LIST_HEAD(&info->swaplist);
+
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
@@ -1233,9 +1244,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
case S_IFREG:
inode->i_op = &shmem_inode_operations;
inode->i_fop = &shmem_file_operations;
- spin_lock(&shmem_ilock);
- list_add_tail(&info->list, &shmem_inodes);
- spin_unlock(&shmem_ilock);
break;
case S_IFDIR:
inode->i_nlink++;
@@ -1703,9 +1711,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return error;
}
inode->i_op = &shmem_symlink_inode_operations;
- spin_lock(&shmem_ilock);
- list_add_tail(&info->list, &shmem_inodes);
- spin_unlock(&shmem_ilock);
kaddr = kmap_atomic(page, KM_USER0);
memcpy(kaddr, symname, len);
kunmap_atomic(kaddr, KM_USER0);