2006-01-16 16:50:04 +00:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2006-05-18 15:09:15 -04:00
* Copyright ( C ) 2004 - 2006 Red Hat , Inc . All rights reserved .
2006-01-16 16:50:04 +00:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2006-09-01 11:05:15 -04:00
* of the GNU General Public License version 2.
2006-01-16 16:50:04 +00:00
*/
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
2006-02-27 17:23:27 -05:00
# include <linux/gfs2_ondisk.h>
2006-03-28 14:14:04 -05:00
# include <linux/crc32.h>
2006-01-16 16:50:04 +00:00
# include "gfs2.h"
2006-02-27 17:23:27 -05:00
# include "incore.h"
2006-01-16 16:50:04 +00:00
# include "dir.h"
# include "glock.h"
2008-10-14 16:05:55 +01:00
# include "super.h"
2006-02-27 17:23:27 -05:00
# include "util.h"
2007-05-15 15:37:50 +01:00
# include "inode.h"
2006-01-16 16:50:04 +00:00
/**
* gfs2_drevalidate - Check directory lookup consistency
* @ dentry : the mapping to check
* @ nd :
*
* Check to make sure the lookup necessary to arrive at this inode from its
* parent is still good .
*
* Returns : 1 if the dentry is ok , 0 if it isn ' t
*/
static int gfs2_drevalidate ( struct dentry * dentry , struct nameidata * nd )
{
struct dentry * parent = dget_parent ( dentry ) ;
2006-06-14 15:32:57 -04:00
struct gfs2_sbd * sdp = GFS2_SB ( parent - > d_inode ) ;
struct gfs2_inode * dip = GFS2_I ( parent - > d_inode ) ;
2006-03-20 12:30:04 -05:00
struct inode * inode = dentry - > d_inode ;
2006-01-16 16:50:04 +00:00
struct gfs2_holder d_gh ;
2007-05-15 15:37:50 +01:00
struct gfs2_inode * ip = NULL ;
2006-01-16 16:50:04 +00:00
int error ;
2008-02-22 16:07:18 +00:00
int had_lock = 0 ;
2006-01-16 16:50:04 +00:00
2007-05-15 15:37:50 +01:00
if ( inode ) {
if ( is_bad_inode ( inode ) )
goto invalid ;
ip = GFS2_I ( inode ) ;
}
2006-01-16 16:50:04 +00:00
2006-03-20 12:30:04 -05:00
if ( sdp - > sd_args . ar_localcaching )
goto valid ;
2008-02-22 16:07:18 +00:00
had_lock = ( gfs2_glock_is_locked_by_me ( dip - > i_gl ) ! = NULL ) ;
2007-02-06 03:52:16 -05:00
if ( ! had_lock ) {
error = gfs2_glock_nq_init ( dip - > i_gl , LM_ST_SHARED , 0 , & d_gh ) ;
if ( error )
goto fail ;
}
2006-01-16 16:50:04 +00:00
2007-05-15 15:37:50 +01:00
error = gfs2_dir_check ( parent - > d_inode , & dentry - > d_name , ip ) ;
2006-01-16 16:50:04 +00:00
switch ( error ) {
case 0 :
if ( ! inode )
goto invalid_gunlock ;
break ;
case - ENOENT :
if ( ! inode )
goto valid_gunlock ;
goto invalid_gunlock ;
default :
goto fail_gunlock ;
}
2006-09-04 12:04:26 -04:00
valid_gunlock :
2007-02-06 03:52:16 -05:00
if ( ! had_lock )
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-09-04 12:04:26 -04:00
valid :
2006-01-16 16:50:04 +00:00
dput ( parent ) ;
return 1 ;
2006-09-04 12:04:26 -04:00
invalid_gunlock :
2007-02-06 03:52:16 -05:00
if ( ! had_lock )
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-09-04 12:04:26 -04:00
invalid :
2006-01-16 16:50:04 +00:00
if ( inode & & S_ISDIR ( inode - > i_mode ) ) {
if ( have_submounts ( dentry ) )
goto valid ;
shrink_dcache_parent ( dentry ) ;
}
d_drop ( dentry ) ;
dput ( parent ) ;
return 0 ;
2006-09-04 12:04:26 -04:00
fail_gunlock :
2006-01-16 16:50:04 +00:00
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-09-04 12:04:26 -04:00
fail :
2006-01-16 16:50:04 +00:00
dput ( parent ) ;
return 0 ;
}
2006-03-20 12:30:04 -05:00
static int gfs2_dhash ( struct dentry * dentry , struct qstr * str )
{
str - > hash = gfs2_disk_hash ( str - > name , str - > len ) ;
return 0 ;
}
2009-02-20 06:00:05 +00:00
const struct dentry_operations gfs2_dops = {
2006-01-16 16:50:04 +00:00
. d_revalidate = gfs2_drevalidate ,
2006-03-20 12:30:04 -05:00
. d_hash = gfs2_dhash ,
2006-01-16 16:50:04 +00:00
} ;