[RFC][PATCH] ensure i_ino uniqueness in filesystems without permanent inode numbers (via lazy hashing)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Here is a different approach to the problem of i_ino uniqueness. Again,
I'll refer to my original email and patch for a description of the problem...

With this patch, I'm taking the approach of only assigning out an i_ino
value when it's actually needed. This adds a lazy_getattr function. If
i_ino is 0, then this does an iunique and hashes the inode before doing
the actual getattr.

This patch is still a proof-of-concept. For a "real" patch, we'd need to:

1) add lazy functions for readdir and encode_fh (maybe also others)
2) clean up how root inode i_ino values are handled in superblocks
3) probably just have new_inode not have a counter, so that new inodes
created by it always get i_ino=0
4) convert all callers of new_inode that don't have a scheme to ensure
uniqueness

This patch does hash inodes in the standard way, but the lazy
approach could also be combined with the earlier patch I posted that
uses IDR, or a different hashing scheme that keeps these out of the
normal inode_hashtable. I figured I'd go with the approach of not adding
more infrastructure than was necessary as a first stab.

If this general approach seems alright, then could someone confirm whether using generic_delete_inode as the drop_inode function is OK, or whether I need to have pipefs actually handle the nlink counter correctly and use generic_drop_inode?

Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>


diff --git a/fs/inode.c b/fs/inode.c
index 26cdb11..9d7da59 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -524,7 +524,7 @@ repeat:
  */
 struct inode *new_inode(struct super_block *sb)
 {
-	static unsigned long last_ino;
+	static unsigned int last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
@@ -683,7 +683,7 @@ static unsigned long hash(struct super_b
  */
 ino_t iunique(struct super_block *sb, ino_t max_reserved)
 {
-	static ino_t counter;
+	static unsigned int counter;
 	struct inode *inode;
 	struct hlist_head * head;
 	ino_t res;
diff --git a/fs/libfs.c b/fs/libfs.c
index bd08e0e..75f8371 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -20,6 +20,18 @@ int simple_getattr(struct vfsmount *mnt,
 	return 0;
 }
 
+/* same as simple_getattr, but get a unique inode number and hash the inode
+ * prior to doing the getattr */
+int lazy_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		   struct kstat *stat)
+{
+	if (dentry->d_inode->i_ino == 0) {
+		dentry->d_inode->i_ino = iunique(dentry->d_sb, 0);
+		insert_inode_hash(dentry->d_inode);
+	}
+	return simple_getattr(mnt, dentry, stat);
+}
+
 int simple_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	buf->f_type = dentry->d_sb->s_magic;
@@ -639,3 +651,4 @@ EXPORT_SYMBOL_GPL(simple_attr_open);
 EXPORT_SYMBOL_GPL(simple_attr_close);
 EXPORT_SYMBOL_GPL(simple_attr_read);
 EXPORT_SYMBOL_GPL(simple_attr_write);
+EXPORT_SYMBOL_GPL(lazy_getattr);
diff --git a/fs/pipe.c b/fs/pipe.c
index b1626f2..6910081 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -837,6 +837,10 @@ static struct dentry_operations pipefs_d
 	.d_delete	= pipefs_delete_dentry,
 };
 
+static struct inode_operations pipefs_inode_operations = {
+	.getattr	= lazy_getattr,
+};
+
 static struct inode * get_pipe_inode(void)
 {
 	struct inode *inode = new_inode(pipe_mnt->mnt_sb);
@@ -845,6 +849,10 @@ static struct inode * get_pipe_inode(voi
 	if (!inode)
 		goto fail_inode;
 
+	/* reset this to 0 to cue lazy_getattr to give us a unique i_ino value
+	 * if this ever has a getattr run against it */
+	inode->i_ino = 0;
+
 	pipe = alloc_pipe_info(inode);
 	if (!pipe)
 		goto fail_iput;
@@ -852,6 +860,7 @@ static struct inode * get_pipe_inode(voi
 
 	pipe->readers = pipe->writers = 1;
 	inode->i_fop = &rdwr_pipe_fops;
+	inode->i_op = &pipefs_inode_operations;
 
 	/*
 	 * Mark the inode dirty from the very beginning,
@@ -998,7 +1007,12 @@ static int pipefs_get_sb(struct file_sys
 			 int flags, const char *dev_name, void *data,
 			 struct vfsmount *mnt)
 {
-	return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC, mnt);
+        static struct super_operations default_ops = {
+		.statfs	=	simple_statfs,
+		.drop_inode =	generic_delete_inode,
+	};
+	
+	return get_sb_pseudo(fs_type, "pipe:", &default_ops, PIPEFS_MAGIC, mnt);
 }
 
 static struct file_system_type pipe_fs_type = {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2fe6e3f..41571c1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1885,6 +1885,7 @@ extern int dcache_dir_close(struct inode
 extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
 extern int dcache_readdir(struct file *, void *, filldir_t);
 extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int lazy_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int simple_statfs(struct dentry *, struct kstatfs *);
 extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux