Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tmpfs: track free_ispace instead of free_inodes

In preparation for assigning some inode space to extended attributes,
keep track of free_ispace instead of number of free_inodes: as if one
tmpfs inode (and accompanying dentry) occupies very approximately 1KiB.

Unsigned long is large enough for free_ispace, on 64-bit and on 32-bit:
but take care to enforce the maximum. And fix the nr_blocks maximum on
32-bit: S64_MAX would be too big for it there, so say LONG_MAX instead.

Delete the incorrect limited<->unlimited blocks/inodes comment above
shmem_reconfigure(): leave it to the error messages below to describe.

Signed-off-by: Hugh Dickins <hughd@google.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Message-Id: <4fe1739-d9e7-8dfd-5bce-12e7339711da@google.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Hugh Dickins and committed by
Christian Brauner
e07c469e 5de75970

+18 -17
+1 -1
include/linux/shmem_fs.h
··· 54 54 unsigned long max_blocks; /* How many blocks are allowed */ 55 55 struct percpu_counter used_blocks; /* How many are allocated */ 56 56 unsigned long max_inodes; /* How many inodes are allowed */ 57 - unsigned long free_inodes; /* How many are left for allocation */ 57 + unsigned long free_ispace; /* How much ispace left for allocation */ 58 58 raw_spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ 59 59 umode_t mode; /* Mount mode for root directory */ 60 60 unsigned char huge; /* Whether to try for hugepages */
+17 -16
mm/shmem.c
··· 90 90 /* Pretend that each entry is of this size in directory's i_size */ 91 91 #define BOGO_DIRENT_SIZE 20 92 92 93 + /* Pretend that one inode + its dentry occupy this much memory */ 94 + #define BOGO_INODE_SIZE 1024 95 + 93 96 /* Symlink up to this size is kmalloc'ed instead of using a swappable page */ 94 97 #define SHORT_SYMLINK_LEN 128 95 98 ··· 140 137 { 141 138 unsigned long nr_pages = totalram_pages(); 142 139 143 - return min(nr_pages - totalhigh_pages(), nr_pages / 2); 140 + return min3(nr_pages - totalhigh_pages(), nr_pages / 2, 141 + ULONG_MAX / BOGO_INODE_SIZE); 144 142 } 145 143 #endif 146 144 ··· 335 331 if (!(sb->s_flags & SB_KERNMOUNT)) { 336 332 raw_spin_lock(&sbinfo->stat_lock); 337 333 if (sbinfo->max_inodes) { 338 - if (!sbinfo->free_inodes) { 334 + if (sbinfo->free_ispace < BOGO_INODE_SIZE) { 339 335 raw_spin_unlock(&sbinfo->stat_lock); 340 336 return -ENOSPC; 341 337 } 342 - sbinfo->free_inodes--; 338 + sbinfo->free_ispace -= BOGO_INODE_SIZE; 343 339 } 344 340 if (inop) { 345 341 ino = sbinfo->next_ino++; ··· 398 394 struct shmem_sb_info *sbinfo = SHMEM_SB(sb); 399 395 if (sbinfo->max_inodes) { 400 396 raw_spin_lock(&sbinfo->stat_lock); 401 - sbinfo->free_inodes++; 397 + sbinfo->free_ispace += BOGO_INODE_SIZE; 402 398 raw_spin_unlock(&sbinfo->stat_lock); 403 399 } 404 400 } ··· 3162 3158 } 3163 3159 if (sbinfo->max_inodes) { 3164 3160 buf->f_files = sbinfo->max_inodes; 3165 - buf->f_ffree = sbinfo->free_inodes; 3161 + buf->f_ffree = sbinfo->free_ispace / BOGO_INODE_SIZE; 3166 3162 } 3167 3163 /* else leave those fields 0 like simple_statfs */ 3168 3164 ··· 3822 3818 break; 3823 3819 case Opt_nr_blocks: 3824 3820 ctx->blocks = memparse(param->string, &rest); 3825 - if (*rest || ctx->blocks > S64_MAX) 3821 + if (*rest || ctx->blocks > LONG_MAX) 3826 3822 goto bad_value; 3827 3823 ctx->seen |= SHMEM_SEEN_BLOCKS; 3828 3824 break; 3829 3825 case Opt_nr_inodes: 3830 3826 ctx->inodes = memparse(param->string, &rest); 3831 - if (*rest) 3827 + if (*rest || ctx->inodes > ULONG_MAX / BOGO_INODE_SIZE) 3832 3828 goto bad_value; 3833 3829 ctx->seen |= SHMEM_SEEN_INODES; 3834 3830 break; ··· 4009 4005 4010 4006 /* 4011 4007 * Reconfigure a shmem filesystem. 4012 - * 4013 - * Note that we disallow change from limited->unlimited blocks/inodes while any 4014 - * are in use; but we must separately disallow unlimited->limited, because in 4015 - * that case we have no record of how much is already in use. 4016 4008 */ 4017 4009 static int shmem_reconfigure(struct fs_context *fc) 4018 4010 { 4019 4011 struct shmem_options *ctx = fc->fs_private; 4020 4012 struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb); 4021 - unsigned long inodes; 4013 + unsigned long used_isp; 4022 4014 struct mempolicy *mpol = NULL; 4023 4015 const char *err; 4024 4016 4025 4017 raw_spin_lock(&sbinfo->stat_lock); 4026 - inodes = sbinfo->max_inodes - sbinfo->free_inodes; 4018 + used_isp = sbinfo->max_inodes * BOGO_INODE_SIZE - sbinfo->free_ispace; 4027 4019 4028 4020 if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) { 4029 4021 if (!sbinfo->max_blocks) { ··· 4037 4037 err = "Cannot retroactively limit inodes"; 4038 4038 goto out; 4039 4039 } 4040 - if (ctx->inodes < inodes) { 4040 + if (ctx->inodes * BOGO_INODE_SIZE < used_isp) { 4041 4041 err = "Too few inodes for current use"; 4042 4042 goto out; 4043 4043 } ··· 4083 4083 sbinfo->max_blocks = ctx->blocks; 4084 4084 if (ctx->seen & SHMEM_SEEN_INODES) { 4085 4085 sbinfo->max_inodes = ctx->inodes; 4086 - sbinfo->free_inodes = ctx->inodes - inodes; 4086 + sbinfo->free_ispace = ctx->inodes * BOGO_INODE_SIZE - used_isp; 4087 4087 } 4088 4088 4089 4089 /* ··· 4214 4214 sb->s_flags |= SB_NOUSER; 4215 4215 #endif 4216 4216 sbinfo->max_blocks = ctx->blocks; 4217 - sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes; 4217 + sbinfo->max_inodes = ctx->inodes; 4218 + sbinfo->free_ispace = sbinfo->max_inodes * BOGO_INODE_SIZE; 4218 4219 if (sb->s_flags & SB_KERNMOUNT) { 4219 4220 sbinfo->ino_batch = alloc_percpu(ino_t); 4220 4221 if (!sbinfo->ino_batch)