aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2004-09-13 17:45:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-13 17:45:36 -0700
commit77cdadab214c6d4cbc25ec5c675ebd34015d2323 (patch)
treee191f991ce180b40a46076fb975bcfa16db99013 /mm
parentfe658b15e8afd06f70376ff5318515dc45c655a7 (diff)
downloadhistory-77cdadab214c6d4cbc25ec5c675ebd34015d2323.tar.gz
[PATCH] shmem: inodes and links need lowmem
Keith Mannthey's Bugzilla #3268 drew attention to how tmpfs inodes and dentries and long names and radix-tree nodes pin lowmem. Assuming about 1k of lowmem per inode, we need to lower the default nr_inodes limit on machines with significant highmem. Be conservative, but more generous than in the original patch to Keith: limit to number of lowmem pages, which works out around 200,000 on i386. Easily overridden by giving the nr_inodes= mount option: those who want to sail closer to the rocks should be allowed to do so. Notice how tmpfs dentries cannot be reclaimed in the way that disk-based dentries can: so even hard links need to be costed. They are cheaper than inodes, but easier all round to charge the same. This way, the limit for hard links is equally visible through "df -i": but expect occasional bugreports that tmpfs links are being treated like this. Would have been simpler just to move the free_inodes accounting from shmem_delete_inode to shmem_unlink; but that would lose the charge on unlinked but open files. 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.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 3722aefae02444..5c5d30805bbccb 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1567,6 +1567,20 @@ static int shmem_create(struct inode *dir, struct dentry *dentry, int mode,
static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+
+ /*
+ * No ordinary (disk based) filesystem counts links as inodes;
+ * but each new link needs a new dentry, pinning lowmem, and
+ * tmpfs dentries cannot be pruned until they are unlinked.
+ */
+ spin_lock(&sbinfo->stat_lock);
+ if (!sbinfo->free_inodes) {
+ spin_unlock(&sbinfo->stat_lock);
+ return -ENOSPC;
+ }
+ sbinfo->free_inodes--;
+ spin_unlock(&sbinfo->stat_lock);
dir->i_size += BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1581,6 +1595,13 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
+ if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) {
+ struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+ spin_lock(&sbinfo->stat_lock);
+ sbinfo->free_inodes++;
+ spin_unlock(&sbinfo->stat_lock);
+ }
+
dir->i_size -= BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
inode->i_nlink--;
@@ -1818,9 +1839,12 @@ static int shmem_fill_super(struct super_block *sb,
/*
* Per default we only allow half of the physical ram per
- * tmpfs instance
+ * tmpfs instance, limiting inodes to one per page of lowmem.
*/
- blocks = inodes = totalram_pages / 2;
+ blocks = totalram_pages / 2;
+ inodes = totalram_pages - totalhigh_pages;
+ if (inodes > blocks)
+ inodes = blocks;
#ifdef CONFIG_TMPFS
if (shmem_parse_options(data, &mode, &uid, &gid, &blocks, &inodes)) {