SPDX-License-Identifier: GPL-2.0

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 515a9a6a3c6f..b23b4b5a61dd 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -55,8 +55,12 @@ struct shmem_quota_limits {
 };
 
 struct shmem_sb_info {
+	struct mutex idr_lock;
+	bool idr_nouse;
+	struct idr idr;		    /* manages inode-number */
 	unsigned long max_blocks;   /* How many blocks are allowed */
 	struct percpu_counter used_blocks;  /* How many are allocated */
+	/* keep the type unchanged to reduce the size of tmpfs_idr.patch. */
 	unsigned long max_inodes;   /* How many inodes are allowed */
 	unsigned long free_ispace;  /* How much ispace left for allocation */
 	raw_spinlock_t stat_lock;   /* Serialize shmem_sb_info changes */
diff --git a/mm/shmem.c b/mm/shmem.c
index 568bb290bdce..ea14faf65e87 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -147,9 +147,11 @@ static unsigned long shmem_default_max_blocks(void)
 static unsigned long shmem_default_max_inodes(void)
 {
 	unsigned long nr_pages = totalram_pages();
+	unsigned long ul;
 
-	return min3(nr_pages - totalhigh_pages(), nr_pages / 2,
-			ULONG_MAX / BOGO_INODE_SIZE);
+	ul = INT_MAX;
+	ul = min3(ul, nr_pages - totalhigh_pages(), nr_pages / 2);
+	return ul;
 }
 #endif
 
@@ -1291,6 +1293,11 @@ static void shmem_evict_inode(struct inode *inode)
 	}
 
 	simple_xattrs_free(&info->xattrs, sbinfo->max_inodes ? &freed : NULL);
+	if (!sbinfo->idr_nouse && inode->i_ino) {
+		mutex_lock(&sbinfo->idr_lock);
+		idr_remove(&sbinfo->idr, inode->i_ino);
+		mutex_unlock(&sbinfo->idr_lock);
+	}
 	shmem_free_inode(inode->i_sb, freed);
 	WARN_ON(inode->i_blocks);
 	clear_inode(inode);
@@ -2854,6 +2861,26 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
 		break;
 	}
 
+	if (!sbinfo->idr_nouse) {
+		/* inum 0 and 1 are unused */
+		mutex_lock(&sbinfo->idr_lock);
+		ino = idr_alloc(&sbinfo->idr, inode, 2, INT_MAX,
+				GFP_NOFS);
+		if (ino > 0) {
+			inode->i_ino = ino;
+			mutex_unlock(&sbinfo->idr_lock);
+			/* postpone it as the original does */
+			/* __insert_inode_hash(inode, inode->i_ino); */
+		} else {
+			inode->i_ino = 0;
+			mutex_unlock(&sbinfo->idr_lock);
+			iput(inode);
+			/* shmem_free_inode() will be called */
+			inode = NULL;
+		}
+	} else
+		inode->i_ino = ino;
+
 	lockdep_annotate_inode_mutex_key(inode);
 	return inode;
 }
@@ -4259,7 +4286,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
 		break;
 	case Opt_nr_inodes:
 		ctx->inodes = memparse(param->string, &rest);
-		if (*rest || ctx->inodes > ULONG_MAX / BOGO_INODE_SIZE)
+		if (*rest || ctx->inodes < 2 || ctx->inodes > INT_MAX)
 			goto bad_value;
 		ctx->seen |= SHMEM_SEEN_INODES;
 		break;
@@ -4613,6 +4640,8 @@ static void shmem_put_super(struct super_block *sb)
 #ifdef CONFIG_TMPFS_QUOTA
 	shmem_disable_quotas(sb);
 #endif
+	if (!sbinfo->idr_nouse)
+		idr_destroy(&sbinfo->idr);
 	free_percpu(sbinfo->ino_batch);
 	percpu_counter_destroy(&sbinfo->used_blocks);
 	mpol_put(sbinfo->mpol);
@@ -4657,6 +4686,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
 #else
 	sb->s_flags |= SB_NOUSER;
 #endif
+	mutex_init(&sbinfo->idr_lock);
+	idr_init(&sbinfo->idr);
 	sbinfo->max_blocks = ctx->blocks;
 	sbinfo->max_inodes = ctx->inodes;
 	sbinfo->free_ispace = sbinfo->max_inodes * BOGO_INODE_SIZE;
@@ -4804,6 +4835,15 @@ static int shmem_error_remove_folio(struct address_space *mapping,
 	return 0;
 }
 
+static __init void shmem_no_idr(struct super_block *sb)
+{
+	struct shmem_sb_info *sbinfo;
+
+	sbinfo = SHMEM_SB(sb);
+	sbinfo->idr_nouse = true;
+	idr_destroy(&sbinfo->idr);
+}
+
 static const struct address_space_operations shmem_aops = {
 	.writepage	= shmem_writepage,
 	.dirty_folio	= noop_dirty_folio,
@@ -4968,6 +5008,7 @@ void __init shmem_init(void)
 		pr_err("Could not kern_mount tmpfs\n");
 		goto out1;
 	}
+	shmem_no_idr(shm_mnt->mnt_sb);
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY)
