|
@@ -40,37 +40,61 @@ struct gfs2_inum_range_host {
|
|
|
u64 ir_length;
|
|
|
};
|
|
|
|
|
|
+struct gfs2_skip_data {
|
|
|
+ u64 no_addr;
|
|
|
+ int skipped;
|
|
|
+ int non_block;
|
|
|
+};
|
|
|
+
|
|
|
static int iget_test(struct inode *inode, void *opaque)
|
|
|
{
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
- u64 *no_addr = opaque;
|
|
|
+ struct gfs2_skip_data *data = opaque;
|
|
|
|
|
|
- if (ip->i_no_addr == *no_addr)
|
|
|
+ if (ip->i_no_addr == data->no_addr) {
|
|
|
+ if (data->non_block &&
|
|
|
+ inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) {
|
|
|
+ data->skipped = 1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
return 1;
|
|
|
-
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int iget_set(struct inode *inode, void *opaque)
|
|
|
{
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
- u64 *no_addr = opaque;
|
|
|
+ struct gfs2_skip_data *data = opaque;
|
|
|
|
|
|
- inode->i_ino = (unsigned long)*no_addr;
|
|
|
- ip->i_no_addr = *no_addr;
|
|
|
+ if (data->skipped)
|
|
|
+ return -ENOENT;
|
|
|
+ inode->i_ino = (unsigned long)(data->no_addr);
|
|
|
+ ip->i_no_addr = data->no_addr;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr)
|
|
|
{
|
|
|
unsigned long hash = (unsigned long)no_addr;
|
|
|
- return ilookup5(sb, hash, iget_test, &no_addr);
|
|
|
+ struct gfs2_skip_data data;
|
|
|
+
|
|
|
+ data.no_addr = no_addr;
|
|
|
+ data.skipped = 0;
|
|
|
+ data.non_block = 0;
|
|
|
+ return ilookup5(sb, hash, iget_test, &data);
|
|
|
}
|
|
|
|
|
|
-static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
|
|
|
+static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr,
|
|
|
+ int non_block)
|
|
|
{
|
|
|
+ struct gfs2_skip_data data;
|
|
|
unsigned long hash = (unsigned long)no_addr;
|
|
|
- return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);
|
|
|
+
|
|
|
+ data.no_addr = no_addr;
|
|
|
+ data.skipped = 0;
|
|
|
+ data.non_block = non_block;
|
|
|
+ return iget5_locked(sb, hash, iget_test, iget_set, &data);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -111,19 +135,20 @@ static void gfs2_set_iop(struct inode *inode)
|
|
|
* @sb: The super block
|
|
|
* @no_addr: The inode number
|
|
|
* @type: The type of the inode
|
|
|
+ * non_block: Can we block on inodes that are being freed?
|
|
|
*
|
|
|
* Returns: A VFS inode, or an error
|
|
|
*/
|
|
|
|
|
|
struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
|
|
|
- u64 no_addr, u64 no_formal_ino)
|
|
|
+ u64 no_addr, u64 no_formal_ino, int non_block)
|
|
|
{
|
|
|
struct inode *inode;
|
|
|
struct gfs2_inode *ip;
|
|
|
struct gfs2_glock *io_gl = NULL;
|
|
|
int error;
|
|
|
|
|
|
- inode = gfs2_iget(sb, no_addr);
|
|
|
+ inode = gfs2_iget(sb, no_addr, non_block);
|
|
|
ip = GFS2_I(inode);
|
|
|
|
|
|
if (!inode)
|
|
@@ -185,11 +210,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
|
|
|
{
|
|
|
struct super_block *sb = sdp->sd_vfs;
|
|
|
struct gfs2_holder i_gh;
|
|
|
- struct inode *inode;
|
|
|
+ struct inode *inode = NULL;
|
|
|
int error;
|
|
|
|
|
|
+ /* Must not read in block until block type is verified */
|
|
|
error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops,
|
|
|
- LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
|
|
|
+ LM_ST_EXCLUSIVE, GL_SKIP, &i_gh);
|
|
|
if (error)
|
|
|
return ERR_PTR(error);
|
|
|
|
|
@@ -197,7 +223,7 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
|
|
|
if (error)
|
|
|
goto fail;
|
|
|
|
|
|
- inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0);
|
|
|
+ inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1);
|
|
|
if (IS_ERR(inode))
|
|
|
goto fail;
|
|
|
|
|
@@ -843,7 +869,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
|
|
|
goto fail_gunlock2;
|
|
|
|
|
|
inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr,
|
|
|
- inum.no_formal_ino);
|
|
|
+ inum.no_formal_ino, 0);
|
|
|
if (IS_ERR(inode))
|
|
|
goto fail_gunlock2;
|
|
|
|