summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorShaohua Li <shli@fb.com>2017-07-12 14:49:47 -0400
committerJens Axboe <axboe@kernel.dk>2017-07-29 11:00:03 -0400
commit4a3ef68acacf31570066e69593de5cc49cc91638 (patch)
tree5cdcf8c5c9208f323152af655e1da6be0093316a /fs
parent7d35079f8277b653d6a3075eea9edd4dbf7c2b29 (diff)
kernfs: implement i_generation
Set i_generation for kernfs inode. This is required to implement exportfs operations. The generation is 32-bit, so it's possible the generation wraps up and we find stale files. To reduce the posssibility, we don't reuse inode numer immediately. When the inode number allocation wraps, we increase generation number. In this way generation/inode number consist of a 64-bit number which is unlikely duplicated. This does make the idr tree more sparse and waste some memory. Since idr manages 32-bit keys, idr uses a 6-level radix tree, each level covers 6 bits of the key. In a 100k inode kernfs, the worst case will have around 300k radix tree node. Each node is 576bytes, so the tree will use about ~150M memory. Sounds not too bad, if this really is a problem, we should find better data structure. Acked-by: Tejun Heo <tj@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Shaohua Li <shli@fb.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'fs')
-rw-r--r--fs/kernfs/dir.c10
-rw-r--r--fs/kernfs/inode.c1
2 files changed, 10 insertions, 1 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 8ad7a17895fe..33f711f6b86e 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -623,6 +623,8 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
623 unsigned flags) 623 unsigned flags)
624{ 624{
625 struct kernfs_node *kn; 625 struct kernfs_node *kn;
626 u32 gen;
627 int cursor;
626 int ret; 628 int ret;
627 629
628 name = kstrdup_const(name, GFP_KERNEL); 630 name = kstrdup_const(name, GFP_KERNEL);
@@ -635,12 +637,17 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
635 637
636 idr_preload(GFP_KERNEL); 638 idr_preload(GFP_KERNEL);
637 spin_lock(&kernfs_idr_lock); 639 spin_lock(&kernfs_idr_lock);
638 ret = idr_alloc(&root->ino_idr, kn, 1, 0, GFP_ATOMIC); 640 cursor = idr_get_cursor(&root->ino_idr);
641 ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC);
642 if (ret >= 0 && ret < cursor)
643 root->next_generation++;
644 gen = root->next_generation;
639 spin_unlock(&kernfs_idr_lock); 645 spin_unlock(&kernfs_idr_lock);
640 idr_preload_end(); 646 idr_preload_end();
641 if (ret < 0) 647 if (ret < 0)
642 goto err_out2; 648 goto err_out2;
643 kn->ino = ret; 649 kn->ino = ret;
650 kn->generation = gen;
644 651
645 atomic_set(&kn->count, 1); 652 atomic_set(&kn->count, 1);
646 atomic_set(&kn->active, KN_DEACTIVATED_BIAS); 653 atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
@@ -884,6 +891,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
884 891
885 idr_init(&root->ino_idr); 892 idr_init(&root->ino_idr);
886 INIT_LIST_HEAD(&root->supers); 893 INIT_LIST_HEAD(&root->supers);
894 root->next_generation = 1;
887 895
888 kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, 896 kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
889 KERNFS_DIR); 897 KERNFS_DIR);
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index fb4b4a79a0d6..79cdae4758fb 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -220,6 +220,7 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
220 inode->i_private = kn; 220 inode->i_private = kn;
221 inode->i_mapping->a_ops = &kernfs_aops; 221 inode->i_mapping->a_ops = &kernfs_aops;
222 inode->i_op = &kernfs_iops; 222 inode->i_op = &kernfs_iops;
223 inode->i_generation = kn->generation;
223 224
224 set_default_inode_attr(inode, kn->mode); 225 set_default_inode_attr(inode, kn->mode);
225 kernfs_refresh_inode(kn, inode); 226 kernfs_refresh_inode(kn, inode);