diff options
author | David Chinner <dgc@sgi.com> | 2008-04-28 22:53:32 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-04-29 01:58:56 -0400 |
commit | 359346a9655c8800408ed3ca44517ac7ea95c197 (patch) | |
tree | 4a97c2956dc5204fd28c26008bbf1f27c1e684bf | |
parent | 86c4d62305649848164ae311a0959fc569b0d964 (diff) |
[XFS] Don't initialise new inode generation numbers to zero
When we allocation new inode chunks, we initialise the generation numbers
to zero. This works fine until we delete a chunk and then reallocate it,
resulting in the same inode numbers but with a reset generation count.
This can result in inode/generation pairs of different inodes occurring
relatively close together.
Given that the inode/gen pair makes up the "unique" portion of an NFS
filehandle on XFS, this can result in file handles cached on clients being
seen on the wire from the server but refer to a different file. This
causes .... issues for NFS clients.
Hence we need a unique generation number initialisation for each inode to
prevent reuse of a small portion of the generation number space. Use a
random number to initialise the generation number so we don't need to keep
any new state on disk whilst making the new number difficult to guess from
previous allocations.
SGI-PV: 979416
SGI-Modid: xfs-linux-melb:xfs-kern:31001a
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index a64dfbd565a5..aad8c5da38af 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -147,6 +147,7 @@ xfs_ialloc_ag_alloc( | |||
147 | int version; /* inode version number to use */ | 147 | int version; /* inode version number to use */ |
148 | int isaligned = 0; /* inode allocation at stripe unit */ | 148 | int isaligned = 0; /* inode allocation at stripe unit */ |
149 | /* boundary */ | 149 | /* boundary */ |
150 | unsigned int gen; | ||
150 | 151 | ||
151 | args.tp = tp; | 152 | args.tp = tp; |
152 | args.mp = tp->t_mountp; | 153 | args.mp = tp->t_mountp; |
@@ -290,6 +291,14 @@ xfs_ialloc_ag_alloc( | |||
290 | else | 291 | else |
291 | version = XFS_DINODE_VERSION_1; | 292 | version = XFS_DINODE_VERSION_1; |
292 | 293 | ||
294 | /* | ||
295 | * Seed the new inode cluster with a random generation number. This | ||
296 | * prevents short-term reuse of generation numbers if a chunk is | ||
297 | * freed and then immediately reallocated. We use random numbers | ||
298 | * rather than a linear progression to prevent the next generation | ||
299 | * number from being easily guessable. | ||
300 | */ | ||
301 | gen = random32(); | ||
293 | for (j = 0; j < nbufs; j++) { | 302 | for (j = 0; j < nbufs; j++) { |
294 | /* | 303 | /* |
295 | * Get the block. | 304 | * Get the block. |
@@ -309,6 +318,7 @@ xfs_ialloc_ag_alloc( | |||
309 | free = XFS_MAKE_IPTR(args.mp, fbuf, i); | 318 | free = XFS_MAKE_IPTR(args.mp, fbuf, i); |
310 | free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC); | 319 | free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC); |
311 | free->di_core.di_version = version; | 320 | free->di_core.di_version = version; |
321 | free->di_core.di_gen = cpu_to_be32(gen); | ||
312 | free->di_next_unlinked = cpu_to_be32(NULLAGINO); | 322 | free->di_next_unlinked = cpu_to_be32(NULLAGINO); |
313 | xfs_ialloc_log_di(tp, fbuf, i, | 323 | xfs_ialloc_log_di(tp, fbuf, i, |
314 | XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); | 324 | XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); |