From mboxrd@z Thu Jan 1 00:00:00 1970 From: "J. R. Okajima" Subject: [RFC PATCH v3 1/2] tmpfs: manage the inode-number by IDR, signed int inum Date: Mon, 2 Jun 2014 01:18:56 +0900 Message-ID: <1401639537-6449-2-git-send-email-hooanon05g@gmail.com> References: <20140522151431.GA25517@lst.de> <1401639537-6449-1-git-send-email-hooanon05g@gmail.com> To: linux-fsdevel@vger.kernel.org, dchinner@redhat.com, viro@zeniv.linux.org.uk, Eric Dumazet , Hugh Dickins , Christoph Hellwig , Andreas Dilger , Jan Kara Return-path: Received: from mail02-md.ns.itscom.net ([175.177.155.112]:37036 "EHLO mail02-md.ns.itscom.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752532AbaFAQTA (ORCPT ); Sun, 1 Jun 2014 12:19:00 -0400 In-Reply-To: <1401639537-6449-1-git-send-email-hooanon05g@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: To ensure the uniquness of the inode-number, manage it by IDR. Also it tries using the lowest unused inode-number, so the value will usually be smaller. Another side effect is the type of the inode-number in tmpfs. By using IDR, it is limited to signed int. But I don't think it a big problem. INT_MAX is big enough for the number of inodes in a single tmpfs. Cc: Eric Dumazet Cc: Hugh Dickins Cc: Christoph Hellwig Cc: Andreas Dilger Cc: Jan Kara Signed-off-by: J. R. Okajima --- include/linux/shmem_fs.h | 6 ++++-- mm/shmem.c | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 4d1771c..4ba8b43 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -24,10 +24,12 @@ struct shmem_inode_info { }; struct shmem_sb_info { + struct mutex idr_lock; + 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 */ kuid_t uid; /* Mount uid for root directory */ kgid_t gid; /* Mount gid for root directory */ diff --git a/mm/shmem.c b/mm/shmem.c index 368f314..0023d8d 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -107,9 +107,13 @@ 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) { - return min(totalram_pages - totalhigh_pages, totalram_pages / 2); + int i; + + i = min(totalram_pages - totalhigh_pages, totalram_pages / 2); + i = min(i, INT_MAX); + return i; } #endif @@ -569,6 +573,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) static void shmem_evict_inode(struct inode *inode) { struct shmem_inode_info *info = SHMEM_I(inode); + struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); if (inode->i_mapping->a_ops == &shmem_aops) { shmem_unacct_size(info->flags, inode->i_size); @@ -584,6 +589,11 @@ static void shmem_evict_inode(struct inode *inode) simple_xattrs_free(&info->xattrs); WARN_ON(inode->i_blocks); + if (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); } @@ -1315,13 +1325,13 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode 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_mapping->backing_dev_info = &shmem_backing_dev_info; @@ -1362,6 +1372,18 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode mpol_shared_policy_init(&info->policy, NULL); break; } + + /* 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); + } else { + mutex_unlock(&sbinfo->idr_lock); + iput(inode); /* shmem_free_inode() will be called */ + inode = NULL; + } } else shmem_free_inode(sb); return inode; @@ -2385,7 +2407,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, goto bad_val; } else if (!strcmp(this_char,"nr_inodes")) { sbinfo->max_inodes = memparse(value, &rest); - if (*rest) + if (*rest || sbinfo->max_inodes < 2) goto bad_val; } else if (!strcmp(this_char,"mode")) { if (remount) @@ -2438,7 +2460,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) { struct shmem_sb_info *sbinfo = SHMEM_SB(sb); struct shmem_sb_info config = *sbinfo; - unsigned long inodes; + int inodes; int error = -EINVAL; config.mpol = NULL; @@ -2486,7 +2508,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) seq_printf(seq, ",size=%luk", sbinfo->max_blocks << (PAGE_CACHE_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 != (S_IRWXUGO | S_ISVTX)) seq_printf(seq, ",mode=%03ho", sbinfo->mode); if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID)) @@ -2504,6 +2526,7 @@ static void shmem_put_super(struct super_block *sb) { struct shmem_sb_info *sbinfo = SHMEM_SB(sb); + idr_destroy(&sbinfo->idr); percpu_counter_destroy(&sbinfo->used_blocks); mpol_put(sbinfo->mpol); kfree(sbinfo); @@ -2522,6 +2545,8 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) if (!sbinfo) return -ENOMEM; + mutex_init(&sbinfo->idr_lock); + idr_init(&sbinfo->idr); sbinfo->mode = S_IRWXUGO | S_ISVTX; sbinfo->uid = current_fsuid(); sbinfo->gid = current_fsgid(); -- 1.7.10.4