[PATCH] ext2 generation numbers

G. Allen Morris III (gam3@ixlabs.com)
Tue, 28 Sep 1999 20:17:48 -0700


Linus/Alan,

Here is a patch against 2.2.12 that adds generation numbers
to the ext2 filesystem. This code is very simular to what is
in the patch that H.J. distributes.

Where H.J. intialized a global inode_generation_count in
fs/inode.c, I initalize ext2_inode_generation_count in
fs/ext2/super.c. This is becuase generation numbers are
generated differently for each filesystem.

JUSTIFICATION

The NFS states that if two filehandles are the same they must
point to the same file. On linux this is not currently the case.
This patch along with previous nfsd patches solves this problem
for ext2 exports.

TESTS

The basic idea of this patch has been in H.J.'s patch set
for several months.

I compiled it, and used `ext2ed' to see if it worked as expected.

BUGS

The old i_gen is NOT read from disk. So there is a 1/2^{32} chance
that a new generation number will be the same as an old one for files
that where created before the last reboot. For files that are created
after the reboot there is no chance for a collision until 2^{32} free
inodes are allocated. The chance of collision after that is 1 in the
worst case, but I am guessing that it normally remains near 1/2^{32}.

Any code accessing u.ext2_i.i_version directly will no longer
work correctly. There is no such code in the kernel source tree.

CHANGES

File: fs/inode.c
Function clean_inode(...) should be static

File: fs/ext2/ialloc.c

Set i_generation with ext2_inode_generation_count
Removed the inc_inode_version() function

File: fs/ext2/inode.c

All instances of u.ext2_i.i_version changed to i_generation

File: fs/ext2/ioctl.c

All instances of u.ext2_i.i_version changed to i_generation

File: fs/ext2/super.c

Initialize ext2_inode_generation_count with a random #

File: include/linux/ext2_fs.h

Changed the name of structure element i_version to i_gen.

File: include/linux/ext2_fs_i.h

Changed the name of structure element that is no longer used.

File: include/linux/fs.h

Removed `inode_generation_count'

------------------------------------
Index: fs/inode.c
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/fs/inode.c,v
retrieving revision 1.1
diff -u -u -r1.1 inode.c
--- fs/inode.c 1999/09/18 07:41:31 1.1
+++ fs/inode.c 1999/09/28 18:53:54
@@ -516,7 +516,7 @@
* i_sb, i_ino, i_count, i_state and the lists have
* been initialized elsewhere..
*/
-void clean_inode(struct inode *inode)
+static void clean_inode(struct inode *inode)
{
memset(&inode->u, 0, sizeof(inode->u));
inode->i_sock = 0;
Index: fs/ext2/ialloc.c
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/fs/ext2/ialloc.c,v
retrieving revision 1.1
diff -u -u -r1.1 ialloc.c
--- fs/ext2/ialloc.c 1999/09/03 17:20:43 1.1
+++ fs/ext2/ialloc.c 1999/09/28 18:53:54
@@ -38,6 +38,8 @@
#include <asm/bitops.h>
#include <asm/byteorder.h>

+extern __u32 ext2_inode_generation_count;
+
/*
* Read the inode allocation bitmap for a given block_group, reading
* into the specified slot in the superblock's bitmap cache.
@@ -268,21 +270,6 @@
}

/*
- * This function increments the inode version number
- *
- * This may be used one day by the NFS server
- */
-static void inc_inode_version (struct inode * inode,
- struct ext2_group_desc *gdp,
- int mode)
-{
- inode->u.ext2_i.i_version++;
- mark_inode_dirty(inode);
-
- return;
-}
-
-/*
* There are two policies for allocating an inode. If the new inode is
* a directory, then a forward search is made for a block group with both
* free space and a low directory-to-inode ratio; if that fails, then of
@@ -492,9 +479,9 @@
inode->i_op = NULL;
if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
inode->i_flags |= MS_SYNCHRONOUS;
+ inode->i_generation = ext2_inode_generation_count++;
insert_inode_hash(inode);
mark_inode_dirty(inode);
- inc_inode_version (inode, gdp, mode);

unlock_super (sb);
if(DQUOT_ALLOC_INODE(sb, inode)) {
Index: fs/ext2/inode.c
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/fs/ext2/inode.c,v
retrieving revision 1.1
diff -u -u -r1.1 inode.c
--- fs/ext2/inode.c 1999/09/18 07:21:06 1.1
+++ fs/ext2/inode.c 1999/09/28 19:07:59
@@ -537,7 +537,7 @@
<< 32;
#endif
}
- inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
+ inode->i_generation = le32_to_cpu(raw_inode->i_gen);
inode->u.ext2_i.i_block_group = block_group;
inode->u.ext2_i.i_next_alloc_block = 0;
inode->u.ext2_i.i_next_alloc_goal = 0;
@@ -667,7 +667,7 @@
raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
#endif
}
- raw_inode->i_version = cpu_to_le32(inode->u.ext2_i.i_version);
+ raw_inode->i_gen = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
Index: fs/ext2/ioctl.c
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/fs/ext2/ioctl.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -u -r1.1 -r1.2
--- fs/ext2/ioctl.c 1999/09/18 07:21:06 1.1
+++ fs/ext2/ioctl.c 1999/09/18 07:36:13 1.2
@@ -68,13 +68,13 @@
mark_inode_dirty(inode);
return 0;
case EXT2_IOC_GETVERSION:
- return put_user(inode->u.ext2_i.i_version, (int *) arg);
+ return put_user(inode->i_generation, (int *) arg);
case EXT2_IOC_SETVERSION:
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
- if (get_user(inode->u.ext2_i.i_version, (int *) arg))
+ if (get_user(inode->i_generation, (int *) arg))
return -EFAULT;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
Index: fs/ext2/super.c
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/fs/ext2/super.c,v
retrieving revision 1.1
diff -u -u -r1.1 super.c
--- fs/ext2/super.c 1999/09/28 18:28:01 1.1
+++ fs/ext2/super.c 1999/09/28 18:53:54
@@ -34,6 +34,7 @@
#include <linux/locks.h>
#include <linux/blkdev.h>
#include <linux/init.h>
+#include <linux/random.h>

static char error_buf[1024];

@@ -735,15 +736,17 @@
static struct file_system_type ext2_fs_type = {
"ext2",
FS_REQUIRES_DEV /* | FS_IBASKET */, /* ibaskets have unresolved bugs */
- ext2_read_super,
+ ext2_read_super,
NULL
};

-__u32 inode_generation_count = 0;
+__u32 ext2_inode_generation_count = 0;

__initfunc(int init_ext2_fs(void))
{
- return register_filesystem(&ext2_fs_type);
+ get_random_bytes (&ext2_inode_generation_count,
+ sizeof (ext2_inode_generation_count));
+ return register_filesystem(&ext2_fs_type);
}

#ifdef MODULE
@@ -756,7 +759,7 @@

void cleanup_module(void)
{
- unregister_filesystem(&ext2_fs_type);
+ unregister_filesystem(&ext2_fs_type);
}

#endif
Index: include/linux/ext2_fs.h
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/include/linux/ext2_fs.h,v
retrieving revision 1.1
diff -u -u -r1.1 ext2_fs.h
--- include/linux/ext2_fs.h 1999/09/28 19:05:32 1.1
+++ include/linux/ext2_fs.h 1999/09/28 19:06:01
@@ -238,7 +238,7 @@
} masix1;
} osd1; /* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
- __u32 i_version; /* File version (for NFS) */
+ __u32 i_gen; /* File genertation number (for NFS) */
__u32 i_file_acl; /* File ACL */
__u32 i_dir_acl; /* Directory ACL */
__u32 i_faddr; /* Fragment address */
Index: include/linux/ext2_fs_i.h
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/include/linux/ext2_fs_i.h,v
retrieving revision 1.1
diff -u -u -r1.1 ext2_fs_i.h
--- include/linux/ext2_fs_i.h 1999/09/06 23:53:30 1.1
+++ include/linux/ext2_fs_i.h 1999/09/28 19:06:52
@@ -29,7 +29,7 @@
__u32 i_file_acl;
__u32 i_dir_acl;
__u32 i_dtime;
- __u32 i_version;
+ __u32 i_unused; /* FIXME: unused remove from 2.3 */
__u32 i_block_group;
__u32 i_next_alloc_block;
__u32 i_next_alloc_goal;
Index: include/linux/fs.h
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/include/linux/fs.h,v
retrieving revision 1.1
diff -u -u -r1.1 fs.h
--- include/linux/fs.h 1999/09/03 17:12:00 1.1
+++ include/linux/fs.h 1999/09/28 19:08:25
@@ -946,8 +946,6 @@
extern int inode_change_ok(struct inode *, struct iattr *);
extern void inode_setattr(struct inode *, struct iattr *);

-extern __u32 inode_generation_count;
-
#endif /* __KERNEL__ */

#endif
Index: include/linux/ufs_fs_i.h
===================================================================
RCS file: /home/cvs/cvsroot/linux-2.2/include/linux/ufs_fs_i.h,v
retrieving revision 1.1
diff -u -u -r1.1 ufs_fs_i.h
--- include/linux/ufs_fs_i.h 1999/09/19 20:36:49 1.1
+++ include/linux/ufs_fs_i.h 1998/10/16 07:00:00
@@ -20,7 +20,7 @@
} i_u1;
__u64 i_size;
__u32 i_flags;
- __u32 i_gen;
+ __u32 i_gen; /* FIXME: not used see inode->i_generation */
__u32 i_shadow;
__u32 i_uid;
__u32 i_gid;

--
Allen Morris <gam3@acm.org>

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/