Skip to content
Snippets Groups Projects
tmpfs-idr.patch 6.99 KiB
Newer Older
Philip Müller's avatar
Philip Müller committed
SPDX-License-Identifier: GPL-2.0

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
Helmut Stult's avatar
Helmut Stult committed
index 7a35a6901221..b7af7d8bfa48 100644
Philip Müller's avatar
Philip Müller committed
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -27,10 +27,13 @@ struct shmem_inode_info {
 };
 
 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 */
-	unsigned long max_inodes;   /* How many inodes are allowed */
-	unsigned long free_inodes;  /* How many are left for allocation */
+	int max_inodes;		    /* How many inodes are allowed */
+	int free_inodes;	    /* How many are left for allocation */
 	spinlock_t stat_lock;	    /* Serialize shmem_sb_info changes */
 	umode_t mode;		    /* Mount mode for root directory */
 	unsigned char huge;	    /* Whether to try for hugepages */
diff --git a/mm/shmem.c b/mm/shmem.c
Helmut Stult's avatar
Helmut Stult committed
index bd8840082c94..7f29f8cb3921 100644
Philip Müller's avatar
Philip Müller committed
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -110,7 +110,7 @@ struct shmem_falloc {
 
 struct shmem_options {
 	unsigned long long blocks;
-	unsigned long long inodes;
+	int inodes;
 	struct mempolicy *mpol;
 	kuid_t uid;
 	kgid_t gid;
@@ -128,11 +128,14 @@ static unsigned long shmem_default_max_blocks(void)
 	return totalram_pages() / 2;
 }
 
-static unsigned long shmem_default_max_inodes(void)
+static int shmem_default_max_inodes(void)
 {
 	unsigned long nr_pages = totalram_pages();
+	unsigned long ul;
 
-	return min(nr_pages - totalhigh_pages(), nr_pages / 2);
+	ul = INT_MAX;
+	ul = min3(ul, nr_pages - totalhigh_pages(), nr_pages / 2);
+	return ul;
 }
 #endif
 
Helmut Stult's avatar
Helmut Stult committed
@@ -1100,6 +1103,11 @@ static void shmem_evict_inode(struct inode *inode)
Philip Müller's avatar
Philip Müller committed
 
 	simple_xattrs_free(&info->xattrs);
 	WARN_ON(inode->i_blocks);
+	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);
 	clear_inode(inode);
 }
Helmut Stult's avatar
Helmut Stult committed
@@ -2240,13 +2248,13 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
Philip Müller's avatar
Philip Müller committed
 	struct inode *inode;
 	struct shmem_inode_info *info;
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+	int ino;
 
 	if (shmem_reserve_inode(sb))
 		return NULL;
 
 	inode = new_inode(sb);
 	if (inode) {
-		inode->i_ino = get_next_ino();
 		inode_init_owner(inode, dir, mode);
 		inode->i_blocks = 0;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
Helmut Stult's avatar
Helmut Stult committed
@@ -2290,6 +2298,25 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
Philip Müller's avatar
Philip Müller committed
 			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);
+				__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 = get_next_ino();
+
 		lockdep_annotate_inode_mutex_key(inode);
 	} else
 		shmem_free_inode(sb);
Helmut Stult's avatar
Helmut Stult committed
@@ -3292,8 +3319,7 @@ static struct dentry *shmem_get_parent(struct dentry *child)
Philip Müller's avatar
Philip Müller committed
 static int shmem_match(struct inode *ino, void *vfh)
 {
 	__u32 *fh = vfh;
-	__u64 inum = fh[2];
-	inum = (inum << 32) | fh[1];
+	__u64 inum = fh[1];
 	return ino->i_ino == inum && fh[0] == ino->i_generation;
 }
 
Helmut Stult's avatar
Helmut Stult committed
@@ -3313,14 +3339,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
Philip Müller's avatar
Philip Müller committed
 	struct dentry *dentry = NULL;
 	u64 inum;
 
-	if (fh_len < 3)
+	if (fh_len < 2)
 		return NULL;
 
-	inum = fid->raw[2];
-	inum = (inum << 32) | fid->raw[1];
-
-	inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
-			shmem_match, fid->raw);
+	inum = fid->raw[1];
+	inode = ilookup5(sb, inum, shmem_match, fid->raw);
 	if (inode) {
 		dentry = shmem_find_alias(inode);
 		iput(inode);
Helmut Stult's avatar
Helmut Stult committed
@@ -3332,30 +3355,15 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
Philip Müller's avatar
Philip Müller committed
 static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
 				struct inode *parent)
 {
-	if (*len < 3) {
-		*len = 3;
+	if (*len < 2) {
+		*len = 2;
 		return FILEID_INVALID;
 	}
 
-	if (inode_unhashed(inode)) {
-		/* Unfortunately insert_inode_hash is not idempotent,
-		 * so as we hash inodes here rather than at creation
-		 * time, we need a lock to ensure we only try
-		 * to do it once
-		 */
-		static DEFINE_SPINLOCK(lock);
-		spin_lock(&lock);
-		if (inode_unhashed(inode))
-			__insert_inode_hash(inode,
-					    inode->i_ino + inode->i_generation);
-		spin_unlock(&lock);
-	}
-
 	fh[0] = inode->i_generation;
 	fh[1] = inode->i_ino;
-	fh[2] = ((__u64)inode->i_ino) >> 32;
 
-	*len = 3;
+	*len = 2;
 	return 1;
 }
 
Helmut Stult's avatar
Helmut Stult committed
@@ -3430,7 +3438,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
Philip Müller's avatar
Philip Müller committed
 		break;
 	case Opt_nr_inodes:
 		ctx->inodes = memparse(param->string, &rest);
-		if (*rest)
+		if (*rest || ctx->inodes < 2)
 			goto bad_value;
 		ctx->seen |= SHMEM_SEEN_INODES;
 		break;
Helmut Stult's avatar
Helmut Stult committed
@@ -3528,7 +3536,7 @@ static int shmem_reconfigure(struct fs_context *fc)
Philip Müller's avatar
Philip Müller committed
 {
 	struct shmem_options *ctx = fc->fs_private;
 	struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb);
-	unsigned long inodes;
+	int inodes;
 	const char *err;
 
 	spin_lock(&sbinfo->stat_lock);
Helmut Stult's avatar
Helmut Stult committed
@@ -3587,7 +3595,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
Philip Müller's avatar
Philip Müller committed
 		seq_printf(seq, ",size=%luk",
 			sbinfo->max_blocks << (PAGE_SHIFT - 10));
 	if (sbinfo->max_inodes != shmem_default_max_inodes())
-		seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
+		seq_printf(seq, ",nr_inodes=%d", sbinfo->max_inodes);
 	if (sbinfo->mode != (0777 | S_ISVTX))
 		seq_printf(seq, ",mode=%03ho", sbinfo->mode);
 	if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
Helmut Stult's avatar
Helmut Stult committed
@@ -3611,6 +3619,8 @@ static void shmem_put_super(struct super_block *sb)
Philip Müller's avatar
Philip Müller committed
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
+	if (!sbinfo->idr_nouse)
+		idr_destroy(&sbinfo->idr);
 	percpu_counter_destroy(&sbinfo->used_blocks);
 	mpol_put(sbinfo->mpol);
 	kfree(sbinfo);
Helmut Stult's avatar
Helmut Stult committed
@@ -3651,6 +3661,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
Philip Müller's avatar
Philip Müller committed
 #else
 	sb->s_flags |= SB_NOUSER;
 #endif
+	mutex_init(&sbinfo->idr_lock);
+	idr_init(&sbinfo->idr);
 	sbinfo->max_blocks = ctx->blocks;
 	sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes;
 	sbinfo->uid = ctx->uid;
Helmut Stult's avatar
Helmut Stult committed
@@ -3762,6 +3774,15 @@ static void shmem_destroy_inodecache(void)
Philip Müller's avatar
Philip Müller committed
 	kmem_cache_destroy(shmem_inode_cachep);
 }
 
+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,
 	.set_page_dirty	= __set_page_dirty_no_writeback,
Helmut Stult's avatar
Helmut Stult committed
@@ -3902,6 +3923,7 @@ int __init shmem_init(void)
Philip Müller's avatar
Philip Müller committed
 		pr_err("Could not kern_mount tmpfs\n");
 		goto out1;
 	}
+	shmem_no_idr(shm_mnt->mnt_sb);
 
Helmut Stult's avatar
Helmut Stult committed
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
Philip Müller's avatar
Philip Müller committed
 	if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY)