diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2010-11-03 20:01:07 +0000 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2010-11-15 12:44:42 +0000 |
commit | 044b9414c7caf9a26192c73a5b88fa1a8a32a1c1 (patch) | |
tree | 9596bb669a68b04eebc40864c3b3fd71d3d1e273 /fs/gfs2/inode.h | |
parent | 0143832cc96d0bf78486297aad5c8fb2c2ead02a (diff) | |
download | op-kernel-dev-044b9414c7caf9a26192c73a5b88fa1a8a32a1c1.zip op-kernel-dev-044b9414c7caf9a26192c73a5b88fa1a8a32a1c1.tar.gz |
GFS2: Fix inode deallocation race
This area of the code has always been a bit delicate due to the
subtleties of lock ordering. The problem is that for "normal"
alloc/dealloc, we always grab the inode locks first and the rgrp lock
later.
In order to ensure no races in looking up the unlinked, but still
allocated inodes, we need to hold the rgrp lock when we do the lookup,
which means that we can't take the inode glock.
The solution is to borrow the technique already used by NFS to solve
what is essentially the same problem (given an inode number, look up
the inode carefully, checking that it really is in the expected
state).
We cannot do that directly from the allocation code (lock ordering
again) so we give the job to the pre-existing delete workqueue and
carry on with the allocation as normal.
If we find there is no space, we do a journal flush (required anyway
if space from a deallocation is to be released) which should block
against the pending deallocations, so we should always get the space
back.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.h')
-rw-r--r-- | fs/gfs2/inode.h | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 6720d7d..d8499fa 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -99,7 +99,9 @@ err: extern void gfs2_set_iop(struct inode *inode); extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, u64 no_addr, u64 no_formal_ino); -extern void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr); +extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, + u64 *no_formal_ino, + unsigned int blktype); extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); extern int gfs2_inode_refresh(struct gfs2_inode *ip); |