[Patch] tmpfs accounting cleanup for -ac series

Christoph Rohland (cr@sap.com)
17 May 2001 17:02:06 +0200


Hi Alan,

While looking at the -ac version of ramfs I noticed that there is a
new address operation introduced which I can use to cleanup shmem.

This patch throws away some magic recalculation and makes the
accounting of shmem accurate.

It also encapsulates all accesses to the superblock_info into a macro.

The patch is on top of my previous ones.

Greetings
Christoph

diff -uNr 4-ac9/fs/proc/proc_misc.c c/fs/proc/proc_misc.c
--- 4-ac9/fs/proc/proc_misc.c Thu May 17 13:17:37 2001
+++ c/fs/proc/proc_misc.c Thu May 17 13:11:30 2001
@@ -140,17 +140,9 @@
{
struct sysinfo i;
int len;
- unsigned int cached, shmem;
+ unsigned int cached;

- /*
- * There may be some inconsistency because shmem_nrpages
- * update is delayed to page_cache_size
- * We make sure the cached value does not get below zero
- */
- cached = atomic_read(&page_cache_size);
- shmem = atomic_read(&shmem_nrpages);
- if (shmem < cached)
- cached -= shmem;
+ cached = atomic_read(&page_cache_size) - atomic_read(&shmem_nrpages);

/*
* display in kilobytes.
diff -uNr 4-ac9/mm/mmap.c c/mm/mmap.c
--- 4-ac9/mm/mmap.c Thu May 17 13:17:37 2001
+++ c/mm/mmap.c Thu May 17 10:54:22 2001
@@ -56,24 +56,14 @@
*/

long free;
- unsigned long cached, shmem;
-
- /*
- * There may be some inconsistency because shmem_nrpages
- * update is delayed to the page_cache_size
- * We make sure the cached value does not get below zero
- */
- cached = atomic_read(&page_cache_size);
- shmem = atomic_read(&shmem_nrpages);
- if (cached > shmem)
- cached -= shmem;

/* Sometimes we want to use more memory than we have. */
if (sysctl_overcommit_memory)
return 1;

free = atomic_read(&buffermem_pages);
- free += cached;
+ free += atomic_read(&page_cache_size) ;
+ free -= atomic_read(&shmem_nrpages);
free += nr_free_pages();
free += nr_swap_pages;

diff -uNr 4-ac9/mm/shmem.c c/mm/shmem.c
--- 4-ac9/mm/shmem.c Thu May 17 13:17:37 2001
+++ c/mm/shmem.c Thu May 17 10:54:03 2001
@@ -35,6 +35,8 @@

#define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))

+#define SHMEM_SB(sb) (&sb->u.shmem_sb)
+
static struct super_operations shmem_ops;
static struct address_space_operations shmem_aops;
static struct file_operations shmem_file_operations;
@@ -50,44 +52,6 @@
#define BLOCKS_PER_PAGE (PAGE_SIZE/512)

/*
- * shmem_recalc_inode - recalculate the size of an inode
- *
- * @inode: inode to recalc
- * @swap: additional swap pages freed externally
- *
- * We have to calculate the free blocks since the mm can drop pages
- * behind our back
- *
- * But we know that normally
- * inodes->i_blocks/BLOCKS_PER_PAGE ==
- * inode->i_mapping->nrpages + info->swapped
- *
- * So the mm freed
- * inodes->i_blocks/BLOCKS_PER_PAGE -
- * (inode->i_mapping->nrpages + info->swapped)
- *
- * It has to be called with the spinlock held.
- *
- * The swap parameter is a performance hack for truncate.
- */
-
-static void shmem_recalc_inode(struct inode * inode, unsigned long swap)
-{
- unsigned long freed;
-
- freed = (inode->i_blocks/BLOCKS_PER_PAGE) -
- (inode->i_mapping->nrpages + SHMEM_I(inode)->swapped);
- if (freed){
- struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb;
- inode->i_blocks -= freed*BLOCKS_PER_PAGE;
- spin_lock (&info->stat_lock);
- info->free_blocks += freed;
- spin_unlock (&info->stat_lock);
- atomic_sub(freed-swap, &shmem_nrpages);
- }
-}
-
-/*
* shmem_swp_entry - find the swap vector position in the info structure
*
* @info: info structure for the inode
@@ -318,6 +282,7 @@
unsigned long index;
unsigned long freed = 0;
struct shmem_inode_info * info = SHMEM_I(inode);
+ struct shmem_sb_info * sbinfo = SHMEM_SB(inode->i_sb);

down(&info->sem);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@ -328,14 +293,28 @@
freed += shmem_truncate_indirect(info, index);

info->swapped -= freed;
- shmem_recalc_inode(inode, freed);
+ spin_lock(&sbinfo->stat_lock);
+ sbinfo->free_blocks += freed;
+ spin_unlock(&sbinfo->stat_lock);
spin_unlock (&info->lock);
up(&info->sem);
}

+static void shmem_truncatepage(struct page *page)
+{
+ struct inode *inode = (struct inode *)page->mapping->host;
+ struct shmem_sb_info * sbinfo = SHMEM_SB(inode->i_sb);
+
+ inode->i_blocks -= BLOCKS_PER_PAGE;
+ spin_lock (&sbinfo->stat_lock);
+ sbinfo->free_blocks++;
+ spin_unlock (&sbinfo->stat_lock);
+ atomic_dec(&shmem_nrpages);
+}
+
static void shmem_delete_inode(struct inode * inode)
{
- struct shmem_sb_info *info = &inode->i_sb->u.shmem_sb;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);

inode->i_size = 0;
if (inode->i_op->truncate == shmem_truncate){
@@ -344,9 +323,9 @@
spin_unlock (&shmem_ilock);
shmem_truncate(inode);
}
- spin_lock (&info->stat_lock);
- info->free_inodes++;
- spin_unlock (&info->stat_lock);
+ spin_lock (&sbinfo->stat_lock);
+ sbinfo->free_inodes++;
+ spin_unlock (&sbinfo->stat_lock);
clear_inode(inode);
}

@@ -383,7 +362,6 @@
entry = shmem_swp_entry(info, page->index, 0);
if (IS_ERR(entry)) /* this had been allocted on page allocation */
BUG();
- shmem_recalc_inode(page->mapping->host, 0);
error = -EAGAIN;
if (entry->val)
BUG();
@@ -421,6 +399,7 @@
static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode * inode, unsigned long idx)
{
struct address_space * mapping = inode->i_mapping;
+ struct shmem_sb_info * sbinfo;
struct page * page;
swp_entry_t *entry;

@@ -487,12 +466,13 @@
info->swapped--;
spin_unlock (&info->lock);
} else {
+ sbinfo = SHMEM_SB(inode->i_sb);
spin_unlock (&info->lock);
- spin_lock (&inode->i_sb->u.shmem_sb.stat_lock);
- if (inode->i_sb->u.shmem_sb.free_blocks == 0)
+ spin_lock (&sbinfo->stat_lock);
+ if (sbinfo->free_blocks == 0)
goto no_space;
- inode->i_sb->u.shmem_sb.free_blocks--;
- spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
+ sbinfo->free_blocks--;
+ spin_unlock (&sbinfo->stat_lock);

/* Ok, get a new page. We don't have to worry about the
* info->lock spinlock here: we cannot race against
@@ -516,7 +496,7 @@
page_cache_get(page);
return page;
no_space:
- spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
+ spin_unlock (&sbinfo->stat_lock);
return ERR_PTR(-ENOSPC);

wait_retry:
@@ -638,14 +618,15 @@
{
struct inode * inode;
struct shmem_inode_info *info;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(sb);

- spin_lock (&sb->u.shmem_sb.stat_lock);
- if (!sb->u.shmem_sb.free_inodes) {
- spin_unlock (&sb->u.shmem_sb.stat_lock);
+ spin_lock (&sbinfo->stat_lock);
+ if (!sbinfo->free_inodes) {
+ spin_unlock (&sbinfo->stat_lock);
return NULL;
}
- sb->u.shmem_sb.free_inodes--;
- spin_unlock (&sb->u.shmem_sb.stat_lock);
+ sbinfo->free_inodes--;
+ spin_unlock (&sbinfo->stat_lock);

inode = new_inode(sb);
if (inode) {
@@ -903,24 +884,26 @@

static int shmem_statfs(struct super_block *sb, struct statfs *buf)
{
+ struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+
buf->f_type = TMPFS_MAGIC;
buf->f_bsize = PAGE_CACHE_SIZE;
- spin_lock (&sb->u.shmem_sb.stat_lock);
- if (sb->u.shmem_sb.max_blocks == ULONG_MAX) {
+ spin_lock (&sbinfo->stat_lock);
+ if (sbinfo->max_blocks == ULONG_MAX) {
/*
* This is only a guestimate and not honoured.
* We need it to make some programs happy which like to
* test the free space of a file system.
*/
buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages);
- buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks;
+ buf->f_blocks = buf->f_bfree + ULONG_MAX - sbinfo->free_blocks;
} else {
- buf->f_blocks = sb->u.shmem_sb.max_blocks;
- buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
+ buf->f_blocks = sbinfo->max_blocks;
+ buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
}
- buf->f_files = sb->u.shmem_sb.max_inodes;
- buf->f_ffree = sb->u.shmem_sb.free_inodes;
- spin_unlock (&sb->u.shmem_sb.stat_lock);
+ buf->f_files = sbinfo->max_inodes;
+ buf->f_ffree = sbinfo->free_inodes;
+ spin_unlock (&sbinfo->stat_lock);
buf->f_namelen = 255;
return 0;
}
@@ -1202,26 +1185,26 @@
int error;
unsigned long max_blocks, blocks;
unsigned long max_inodes, inodes;
- struct shmem_sb_info *info = &sb->u.shmem_sb;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(sb);

if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
return -EINVAL;

- spin_lock(&info->stat_lock);
- blocks = info->max_blocks - info->free_blocks;
- inodes = info->max_inodes - info->free_inodes;
+ spin_lock(&sbinfo->stat_lock);
+ blocks = sbinfo->max_blocks - sbinfo->free_blocks;
+ inodes = sbinfo->max_inodes - sbinfo->free_inodes;
error = -EINVAL;
if (max_blocks < blocks)
goto out;
if (max_inodes < inodes)
goto out;
error = 0;
- info->max_blocks = max_blocks;
- info->free_blocks = max_blocks - blocks;
- info->max_inodes = max_inodes;
- info->free_inodes = max_inodes - inodes;
+ sbinfo->max_blocks = max_blocks;
+ sbinfo->free_blocks = max_blocks - blocks;
+ sbinfo->max_inodes = max_inodes;
+ sbinfo->free_inodes = max_inodes - inodes;
out:
- spin_unlock(&info->stat_lock);
+ spin_unlock(&sbinfo->stat_lock);
return error;
}

@@ -1238,6 +1221,7 @@
unsigned long blocks = ULONG_MAX; /* unlimited */
unsigned long inodes = ULONG_MAX; /* unlimited */
int mode = S_IRWXUGO | S_ISVTX;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(sb);

#ifdef CONFIG_TMPFS
if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
@@ -1246,11 +1230,11 @@
}
#endif

- spin_lock_init (&sb->u.shmem_sb.stat_lock);
- sb->u.shmem_sb.max_blocks = blocks;
- sb->u.shmem_sb.free_blocks = blocks;
- sb->u.shmem_sb.max_inodes = inodes;
- sb->u.shmem_sb.free_inodes = inodes;
+ spin_lock_init (&sbinfo->stat_lock);
+ sbinfo->max_blocks = blocks;
+ sbinfo->free_blocks = blocks;
+ sbinfo->max_inodes = inodes;
+ sbinfo->free_inodes = inodes;
sb->s_maxbytes = (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -1272,7 +1256,8 @@


static struct address_space_operations shmem_aops = {
- writepage: shmem_writepage
+ truncatepage: shmem_truncatepage,
+ writepage: shmem_writepage,
};

static struct file_operations shmem_file_operations = {

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/