GFS2: Rework reclaiming unlinked dinodes
The previous patch I wrote for reclaiming unlinked dinodes had some shortcomings and did not prevent all hangs. This version is much cleaner and more logical, and has passed very difficult testing. Sorry for the churn. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
This commit is contained in:
parent
d7dbf4ffee
commit
ed4878e8a4
|
@ -242,34 +242,38 @@ fail:
|
|||
}
|
||||
|
||||
/**
|
||||
* gfs2_unlinked_inode_lookup - Lookup an unlinked inode for reclamation
|
||||
* gfs2_process_unlinked_inode - Lookup an unlinked inode for reclamation
|
||||
* and try to reclaim it by doing iput.
|
||||
*
|
||||
* This function assumes no rgrp locks are currently held.
|
||||
*
|
||||
* @sb: The super block
|
||||
* no_addr: The inode number
|
||||
* @@inode: A pointer to the inode found, if any
|
||||
*
|
||||
* Returns: 0 and *inode if no errors occurred. If an error occurs,
|
||||
* the resulting *inode may or may not be NULL.
|
||||
*/
|
||||
|
||||
int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
|
||||
struct inode **inode)
|
||||
void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr)
|
||||
{
|
||||
struct gfs2_sbd *sdp;
|
||||
struct gfs2_inode *ip;
|
||||
struct gfs2_glock *io_gl;
|
||||
int error;
|
||||
struct gfs2_holder gh;
|
||||
struct inode *inode;
|
||||
|
||||
*inode = gfs2_iget_skip(sb, no_addr);
|
||||
inode = gfs2_iget_skip(sb, no_addr);
|
||||
|
||||
if (!(*inode))
|
||||
return -ENOBUFS;
|
||||
if (!inode)
|
||||
return;
|
||||
|
||||
if (!((*inode)->i_state & I_NEW))
|
||||
return -ENOBUFS;
|
||||
/* If it's not a new inode, someone's using it, so leave it alone. */
|
||||
if (!(inode->i_state & I_NEW)) {
|
||||
iput(inode);
|
||||
return;
|
||||
}
|
||||
|
||||
ip = GFS2_I(*inode);
|
||||
sdp = GFS2_SB(*inode);
|
||||
ip = GFS2_I(inode);
|
||||
sdp = GFS2_SB(inode);
|
||||
ip->i_no_formal_ino = -1;
|
||||
|
||||
error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
|
||||
|
@ -284,15 +288,13 @@ int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
|
|||
set_bit(GIF_INVALID, &ip->i_flags);
|
||||
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, LM_FLAG_TRY | GL_EXACT,
|
||||
&ip->i_iopen_gh);
|
||||
if (unlikely(error)) {
|
||||
if (error == GLR_TRYFAILED)
|
||||
error = 0;
|
||||
if (unlikely(error))
|
||||
goto fail_iopen;
|
||||
}
|
||||
|
||||
ip->i_iopen_gh.gh_gl->gl_object = ip;
|
||||
gfs2_glock_put(io_gl);
|
||||
|
||||
(*inode)->i_mode = DT2IF(DT_UNKNOWN);
|
||||
inode->i_mode = DT2IF(DT_UNKNOWN);
|
||||
|
||||
/*
|
||||
* We must read the inode in order to work out its type in
|
||||
|
@ -303,16 +305,17 @@ int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
|
|||
*/
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY,
|
||||
&gh);
|
||||
if (unlikely(error)) {
|
||||
if (error == GLR_TRYFAILED)
|
||||
error = 0;
|
||||
if (unlikely(error))
|
||||
goto fail_glock;
|
||||
}
|
||||
|
||||
/* Inode is now uptodate */
|
||||
gfs2_glock_dq_uninit(&gh);
|
||||
gfs2_set_iop(*inode);
|
||||
gfs2_set_iop(inode);
|
||||
|
||||
/* The iput will cause it to be deleted. */
|
||||
iput(inode);
|
||||
return;
|
||||
|
||||
return 0;
|
||||
fail_glock:
|
||||
gfs2_glock_dq(&ip->i_iopen_gh);
|
||||
fail_iopen:
|
||||
|
@ -321,7 +324,8 @@ fail_put:
|
|||
ip->i_gl->gl_object = NULL;
|
||||
gfs2_glock_put(ip->i_gl);
|
||||
fail:
|
||||
return error;
|
||||
iget_failed(inode);
|
||||
return;
|
||||
}
|
||||
|
||||
static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
|
||||
|
|
|
@ -84,8 +84,7 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,
|
|||
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 int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr,
|
||||
struct inode **inode);
|
||||
extern void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr);
|
||||
extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
|
||||
|
||||
extern int gfs2_inode_refresh(struct gfs2_inode *ip);
|
||||
|
|
|
@ -696,7 +696,7 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
|
|||
*
|
||||
*/
|
||||
|
||||
void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
|
||||
void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
|
||||
{
|
||||
struct gfs2_ail *ai;
|
||||
|
||||
|
|
|
@ -47,28 +47,21 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
|
|||
sdp->sd_log_head = sdp->sd_log_tail = value;
|
||||
}
|
||||
|
||||
unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
|
||||
extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
|
||||
unsigned int ssize);
|
||||
|
||||
int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
|
||||
void gfs2_log_incr_head(struct gfs2_sbd *sdp);
|
||||
extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
|
||||
extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
|
||||
|
||||
struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
|
||||
struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
|
||||
extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
|
||||
extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
|
||||
struct buffer_head *real);
|
||||
void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
|
||||
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
|
||||
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
|
||||
extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
|
||||
|
||||
static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl)
|
||||
{
|
||||
if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags))
|
||||
__gfs2_log_flush(sbd, gl);
|
||||
}
|
||||
|
||||
void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
|
||||
void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
|
||||
|
||||
void gfs2_log_shutdown(struct gfs2_sbd *sdp);
|
||||
void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
|
||||
int gfs2_logd(void *data);
|
||||
extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
|
||||
extern void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
|
||||
extern int gfs2_logd(void *data);
|
||||
|
||||
#endif /* __LOG_DOT_H__ */
|
||||
|
|
|
@ -1191,7 +1191,6 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
|
|||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct gfs2_alloc *al = ip->i_alloc;
|
||||
struct inode *inode;
|
||||
int error = 0;
|
||||
u64 last_unlinked = NO_BLOCK, unlinked;
|
||||
|
||||
|
@ -1209,22 +1208,27 @@ try_again:
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
/* Find an rgrp suitable for allocation. If it encounters any unlinked
|
||||
dinodes along the way, error will equal -EAGAIN and unlinked will
|
||||
contains it block address. We then need to look up that inode and
|
||||
try to free it, and try the allocation again. */
|
||||
error = get_local_rgrp(ip, &unlinked, &last_unlinked);
|
||||
if (error) {
|
||||
if (ip != GFS2_I(sdp->sd_rindex))
|
||||
gfs2_glock_dq_uninit(&al->al_ri_gh);
|
||||
if (error != -EAGAIN)
|
||||
return error;
|
||||
error = gfs2_unlinked_inode_lookup(ip->i_inode.i_sb,
|
||||
unlinked, &inode);
|
||||
if (inode)
|
||||
iput(inode);
|
||||
|
||||
gfs2_process_unlinked_inode(ip->i_inode.i_sb, unlinked);
|
||||
/* regardless of whether or not gfs2_process_unlinked_inode
|
||||
was successful, we don't want to repeat it again. */
|
||||
last_unlinked = unlinked;
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
if (error == GLR_TRYFAILED)
|
||||
error = 0;
|
||||
error = 0;
|
||||
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
/* no error, so we have the rgrp set in the inode's allocation. */
|
||||
al->al_file = file;
|
||||
al->al_line = line;
|
||||
|
||||
|
|
Loading…
Reference in New Issue