Commit f286d627 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

gfs2: Keep track of deleted inode generations in LVBs

When deleting an inode, keep track of the generation of the deleted inode in
the inode glock Lock Value Block (LVB).  When trying to delete an inode
remotely, check the last-known inode generation against the deleted inode
generation to skip duplicate remote deletes.  This avoids taking the resource
group glock in order to verify the block type.
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent 15f2547b
...@@ -755,6 +755,25 @@ __acquires(&gl->gl_lockref.lock) ...@@ -755,6 +755,25 @@ __acquires(&gl->gl_lockref.lock)
return; return;
} }
void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation)
{
struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr;
if (ri->ri_magic == 0)
ri->ri_magic = cpu_to_be32(GFS2_MAGIC);
if (ri->ri_magic == cpu_to_be32(GFS2_MAGIC))
ri->ri_generation_deleted = cpu_to_be64(generation);
}
bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation)
{
struct gfs2_inode_lvb *ri = (void *)gl->gl_lksb.sb_lvbptr;
if (ri->ri_magic != cpu_to_be32(GFS2_MAGIC))
return false;
return generation <= be64_to_cpu(ri->ri_generation_deleted);
}
static void delete_work_func(struct work_struct *work) static void delete_work_func(struct work_struct *work)
{ {
struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete); struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
......
...@@ -306,4 +306,7 @@ static inline void glock_clear_object(struct gfs2_glock *gl, void *object) ...@@ -306,4 +306,7 @@ static inline void glock_clear_object(struct gfs2_glock *gl, void *object)
spin_unlock(&gl->gl_lockref.lock); spin_unlock(&gl->gl_lockref.lock);
} }
extern void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation);
extern bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation);
#endif /* __GLOCK_DOT_H__ */ #endif /* __GLOCK_DOT_H__ */
...@@ -692,7 +692,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { ...@@ -692,7 +692,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
.go_lock = inode_go_lock, .go_lock = inode_go_lock,
.go_dump = inode_go_dump, .go_dump = inode_go_dump,
.go_type = LM_TYPE_INODE, .go_type = LM_TYPE_INODE,
.go_flags = GLOF_ASPACE | GLOF_LRU, .go_flags = GLOF_ASPACE | GLOF_LRU | GLOF_LVB,
.go_free = inode_go_free, .go_free = inode_go_free,
}; };
......
...@@ -1315,6 +1315,8 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1315,6 +1315,8 @@ static void gfs2_evict_inode(struct inode *inode)
goto out; goto out;
} }
if (gfs2_inode_already_deleted(ip->i_gl, ip->i_no_formal_ino))
goto out_truncate;
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED); error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
if (error) if (error)
goto out_truncate; goto out_truncate;
...@@ -1368,6 +1370,7 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1368,6 +1370,7 @@ static void gfs2_evict_inode(struct inode *inode)
that subsequent inode creates don't see an old gl_object. */ that subsequent inode creates don't see an old gl_object. */
glock_clear_object(ip->i_gl, ip); glock_clear_object(ip->i_gl, ip);
error = gfs2_dinode_dealloc(ip); error = gfs2_dinode_dealloc(ip);
gfs2_inode_remember_delete(ip->i_gl, ip->i_no_formal_ino);
goto out_unlock; goto out_unlock;
out_truncate: out_truncate:
......
...@@ -171,6 +171,12 @@ struct gfs2_rindex { ...@@ -171,6 +171,12 @@ struct gfs2_rindex {
#define GFS2_RGF_NOALLOC 0x00000008 #define GFS2_RGF_NOALLOC 0x00000008
#define GFS2_RGF_TRIMMED 0x00000010 #define GFS2_RGF_TRIMMED 0x00000010
struct gfs2_inode_lvb {
__be32 ri_magic;
__be32 __pad;
__be64 ri_generation_deleted;
};
struct gfs2_rgrp_lvb { struct gfs2_rgrp_lvb {
__be32 rl_magic; __be32 rl_magic;
__be32 rl_flags; __be32 rl_flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment