[GFS2] filesystem consistency error from do_strip
This patch fixes a GFS2 filesystem consistency error reported from function do_strip. The problem was caused by a timing window that allowed two vfs inodes to be created in memory that point to the same file. The problem is fixed by making the vfs's iget_test, iget_set mechanism check and set a new bit in the in-core gfs2_inode structure while the vfs inode spin_lock is held. Signed-off-by: Bob Peterson <rpeterso@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
This commit is contained in:
parent
492c2e476e
commit
091806edd4
@ -249,7 +249,7 @@ static int inode_go_lock(struct gfs2_holder *gh)
|
|||||||
struct gfs2_inode *ip = gl->gl_object;
|
struct gfs2_inode *ip = gl->gl_object;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if (!ip)
|
if (!ip || (gh->gh_flags & GL_SKIP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (test_bit(GIF_INVALID, &ip->i_flags)) {
|
if (test_bit(GIF_INVALID, &ip->i_flags)) {
|
||||||
|
@ -236,6 +236,7 @@ enum {
|
|||||||
GIF_INVALID = 0,
|
GIF_INVALID = 0,
|
||||||
GIF_QD_LOCKED = 1,
|
GIF_QD_LOCKED = 1,
|
||||||
GIF_SW_PAGED = 3,
|
GIF_SW_PAGED = 3,
|
||||||
|
GIF_USER = 4, /* user inode, not metadata addr space */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gfs2_dinode_host {
|
struct gfs2_dinode_host {
|
||||||
|
@ -47,8 +47,7 @@ static int iget_test(struct inode *inode, void *opaque)
|
|||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
u64 *no_addr = opaque;
|
u64 *no_addr = opaque;
|
||||||
|
|
||||||
if (ip->i_no_addr == *no_addr &&
|
if (ip->i_no_addr == *no_addr && test_bit(GIF_USER, &ip->i_flags))
|
||||||
inode->i_private != NULL)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -61,6 +60,7 @@ static int iget_set(struct inode *inode, void *opaque)
|
|||||||
|
|
||||||
inode->i_ino = (unsigned long)*no_addr;
|
inode->i_ino = (unsigned long)*no_addr;
|
||||||
ip->i_no_addr = *no_addr;
|
ip->i_no_addr = *no_addr;
|
||||||
|
set_bit(GIF_USER, &ip->i_flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ static int iget_skip_test(struct inode *inode, void *opaque)
|
|||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
struct gfs2_skip_data *data = opaque;
|
struct gfs2_skip_data *data = opaque;
|
||||||
|
|
||||||
if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){
|
if (ip->i_no_addr == data->no_addr && test_bit(GIF_USER, &ip->i_flags)){
|
||||||
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){
|
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){
|
||||||
data->skipped = 1;
|
data->skipped = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -105,6 +105,7 @@ static int iget_skip_set(struct inode *inode, void *opaque)
|
|||||||
return 1;
|
return 1;
|
||||||
inode->i_ino = (unsigned long)(data->no_addr);
|
inode->i_ino = (unsigned long)(data->no_addr);
|
||||||
ip->i_no_addr = data->no_addr;
|
ip->i_no_addr = data->no_addr;
|
||||||
|
set_bit(GIF_USER, &ip->i_flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +188,6 @@ struct inode *gfs2_inode_lookup(struct super_block *sb,
|
|||||||
|
|
||||||
if (inode->i_state & I_NEW) {
|
if (inode->i_state & I_NEW) {
|
||||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||||
inode->i_private = ip;
|
|
||||||
ip->i_no_formal_ino = no_formal_ino;
|
ip->i_no_formal_ino = no_formal_ino;
|
||||||
|
|
||||||
error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
|
error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* modify, copy, or redistribute it subject to the terms and conditions
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
@ -69,13 +69,15 @@ static const struct address_space_operations aspace_aops = {
|
|||||||
struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp)
|
struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
struct inode *aspace;
|
struct inode *aspace;
|
||||||
|
struct gfs2_inode *ip;
|
||||||
|
|
||||||
aspace = new_inode(sdp->sd_vfs);
|
aspace = new_inode(sdp->sd_vfs);
|
||||||
if (aspace) {
|
if (aspace) {
|
||||||
mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS);
|
mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS);
|
||||||
aspace->i_mapping->a_ops = &aspace_aops;
|
aspace->i_mapping->a_ops = &aspace_aops;
|
||||||
aspace->i_size = ~0ULL;
|
aspace->i_size = ~0ULL;
|
||||||
aspace->i_private = NULL;
|
ip = GFS2_I(aspace);
|
||||||
|
clear_bit(GIF_USER, &ip->i_flags);
|
||||||
insert_inode_hash(aspace);
|
insert_inode_hash(aspace);
|
||||||
}
|
}
|
||||||
return aspace;
|
return aspace;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This copyrighted material is made available to anyone wishing to use,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* modify, copy, or redistribute it subject to the terms and conditions
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
@ -52,7 +52,7 @@ static int gfs2_write_inode(struct inode *inode, int sync)
|
|||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
|
|
||||||
/* Check this is a "normal" inode */
|
/* Check this is a "normal" inode */
|
||||||
if (inode->i_private) {
|
if (test_bit(GIF_USER, &ip->i_flags)) {
|
||||||
if (current->flags & PF_MEMALLOC)
|
if (current->flags & PF_MEMALLOC)
|
||||||
return 0;
|
return 0;
|
||||||
if (sync)
|
if (sync)
|
||||||
@ -297,8 +297,9 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
|
|||||||
*/
|
*/
|
||||||
static void gfs2_drop_inode(struct inode *inode)
|
static void gfs2_drop_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
if (inode->i_private && inode->i_nlink) {
|
|
||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
|
|
||||||
|
if (test_bit(GIF_USER, &ip->i_flags) && inode->i_nlink) {
|
||||||
struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
|
struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
|
||||||
if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
|
if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
|
||||||
clear_nlink(inode);
|
clear_nlink(inode);
|
||||||
@ -314,12 +315,13 @@ static void gfs2_drop_inode(struct inode *inode)
|
|||||||
|
|
||||||
static void gfs2_clear_inode(struct inode *inode)
|
static void gfs2_clear_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
|
|
||||||
/* This tells us its a "real" inode and not one which only
|
/* This tells us its a "real" inode and not one which only
|
||||||
* serves to contain an address space (see rgrp.c, meta_io.c)
|
* serves to contain an address space (see rgrp.c, meta_io.c)
|
||||||
* which therefore doesn't have its own glocks.
|
* which therefore doesn't have its own glocks.
|
||||||
*/
|
*/
|
||||||
if (inode->i_private) {
|
if (test_bit(GIF_USER, &ip->i_flags)) {
|
||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
|
||||||
ip->i_gl->gl_object = NULL;
|
ip->i_gl->gl_object = NULL;
|
||||||
gfs2_glock_schedule_for_reclaim(ip->i_gl);
|
gfs2_glock_schedule_for_reclaim(ip->i_gl);
|
||||||
gfs2_glock_put(ip->i_gl);
|
gfs2_glock_put(ip->i_gl);
|
||||||
@ -419,7 +421,7 @@ static void gfs2_delete_inode(struct inode *inode)
|
|||||||
struct gfs2_holder gh;
|
struct gfs2_holder gh;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!inode->i_private)
|
if (!test_bit(GIF_USER, &ip->i_flags))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||||
|
Loading…
Reference in New Issue
Block a user