Skip to content

Commit 4a3ef68

Browse files
shligitaxboe
authored andcommitted
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 <[email protected]> Acked-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Shaohua Li <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 7d35079 commit 4a3ef68

File tree

3 files changed

+12
-1
lines changed

3 files changed

+12
-1
lines changed

fs/kernfs/dir.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
623623
unsigned flags)
624624
{
625625
struct kernfs_node *kn;
626+
u32 gen;
627+
int cursor;
626628
int ret;
627629

628630
name = kstrdup_const(name, GFP_KERNEL);
@@ -635,12 +637,17 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
635637

636638
idr_preload(GFP_KERNEL);
637639
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;
639645
spin_unlock(&kernfs_idr_lock);
640646
idr_preload_end();
641647
if (ret < 0)
642648
goto err_out2;
643649
kn->ino = ret;
650+
kn->generation = gen;
644651

645652
atomic_set(&kn->count, 1);
646653
atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
@@ -884,6 +891,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
884891

885892
idr_init(&root->ino_idr);
886893
INIT_LIST_HEAD(&root->supers);
894+
root->next_generation = 1;
887895

888896
kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
889897
KERNFS_DIR);

fs/kernfs/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
220220
inode->i_private = kn;
221221
inode->i_mapping->a_ops = &kernfs_aops;
222222
inode->i_op = &kernfs_iops;
223+
inode->i_generation = kn->generation;
223224

224225
set_default_inode_attr(inode, kn->mode);
225226
kernfs_refresh_inode(kn, inode);

include/linux/kernfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ struct kernfs_node {
135135
umode_t mode;
136136
unsigned int ino;
137137
struct kernfs_iattrs *iattr;
138+
u32 generation;
138139
};
139140

140141
/*
@@ -164,6 +165,7 @@ struct kernfs_root {
164165

165166
/* private fields, do not use outside kernfs proper */
166167
struct idr ino_idr;
168+
u32 next_generation;
167169
struct kernfs_syscall_ops *syscall_ops;
168170

169171
/* list of kernfs_super_info of this root, protected by kernfs_mutex */

0 commit comments

Comments
 (0)