How to Increase Inode Count in Linux (MIPS Router with 2.4.17 Kernel)


2 views

When working with an old MIPS router running Linux 2.4.17 kernel, you might encounter a situation where:

$ touch newfile
touch: cannot create 'newfile': No space left on device

Yet paradoxically, you can still write data to existing files:

$ dd if=/dev/zero of=existing_file bs=1M count=1
1+0 records in
1+0 records out

This occurs because tmpfs (your root filesystem) has exhausted its inode allocation while still having available storage space. The 2.4.17 kernel has particularly conservative defaults for tmpfs inode allocation.

For tmpfs, you can remount with increased inodes:

# umount /tmpfs_mount_point
# mount -t tmpfs -o size=3M,nr_inodes=1000 tmpfs /tmpfs_mount_point

But this requires unmounting first - not ideal for root filesystems.

For a lasting solution, you'll need to modify kernel sources:

  1. Locate the tmpfs configuration in mm/shmem.c
  2. Find the SHMEM_MAX_INODES definition
  3. Increase the value (default is often INODE_MAX/2)

Example patch:

--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -50,7 +50,7 @@
 #define SHMEM_DEFAULT_BLOCKS (SHMEM_MAX_BYTES / PAGE_SIZE / 2)
 
 /* default max inodes, modified by nr_blocks and nr_inodes mounts */
-#define SHMEM_MAX_INODES (SHMEM_MAX_BYTES / 16384)
+#define SHMEM_MAX_INODES (SHMEM_MAX_BYTES / 8192)

If kernel rebuild isn't possible:

  • Use a single large file instead of many small files
  • Implement a file pooling system
  • Mount additional tmpfs in non-root locations

Verify your inode situation with:

# df -i
Filesystem     Inodes  IUsed  IFree IUse% Mounted on
tmpfs           1000    1000      0  100% /

For cramfs (/rom), inodes are fixed at filesystem creation.


When working with embedded Linux devices like MIPS routers (kernel 2.4.17 in this case), filesystem constraints become immediately apparent. The situation described - where new file creation fails despite available space while existing files can grow - clearly indicates an inode exhaustion issue in tmpfs.


# Reproduce the issue:
$ touch /tmp/file{1..100}  # Works initially
$ touch /tmp/file101      # Fails with "No space left on device"
$ dd if=/dev/zero of=/tmp/file1 bs=1M count=1 # Appending works

For modern tmpfs implementations (Linux 3.14+), inodes can be adjusted via:


mount -o remount,size=8M,nr_inodes=10k /tmp

However, with the ancient 2.4.17 kernel, dynamic adjustment isn't supported. The nr_inodes is determined at mount time based on the size parameter (default ratio: 1 inode per 4KB).

For permanent changes, modify these in linux-2.4.17/mm/shmem.c:


#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512)
#define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
#define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)

// Original:
// #define SHMEM_MAX_INODES (SHMEM_MAX_BYTES >> 12)
// Modified to double inodes:
#define SHMEM_MAX_INODES (SHMEM_MAX_BYTES >> 11)

After modifying, rebuild the kernel. The exact ratio (>>11 vs >>12) controls how many inodes are allocated per megabyte of tmpfs.

Given the memory constraints (4MB free), consider:


# 1. Use a single file with internal indexing:
echo "offset,length" > /tmp/data_store
dd if=/dev/urandom bs=512 count=1 >> /tmp/data_store

# 2. Mount with optimal initial sizing:
mount -t tmpfs -o size=3M tmpfs /tmp  # Allocates ~768 inodes

For cramfs (/rom), inodes are fixed at filesystem creation time. You'd need to rebuild the image with mkcramfs -N 2048 (for example) to specify inode count. However, the read-only nature makes this impractical for runtime solutions.