2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2006-05-18 23:09:15 +04:00
* Copyright ( C ) 2004 - 2006 Red Hat , Inc . All rights reserved .
2006-01-16 19:50:04 +03: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 19:05:15 +04:00
* of the GNU General Public License version 2.
2006-01-16 19:50:04 +03:00
*/
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-03-28 23:14:04 +04:00
# include <linux/crc32.h>
2006-09-19 09:56:29 +04:00
# include <linux/lm_interface.h>
2006-01-16 19:50:04 +03:00
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "dir.h"
# include "glock.h"
2008-10-14 19:05:55 +04:00
# include "super.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2007-05-15 18:37:50 +04:00
# include "inode.h"
2006-01-16 19:50:04 +03: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 23: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 20:30:04 +03:00
struct inode * inode = dentry - > d_inode ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder d_gh ;
2007-05-15 18:37:50 +04:00
struct gfs2_inode * ip = NULL ;
2006-01-16 19:50:04 +03:00
int error ;
2008-02-22 19:07:18 +03:00
int had_lock = 0 ;
2006-01-16 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
if ( inode ) {
if ( is_bad_inode ( inode ) )
goto invalid ;
ip = GFS2_I ( inode ) ;
}
2006-01-16 19:50:04 +03:00
2006-03-20 20:30:04 +03:00
if ( sdp - > sd_args . ar_localcaching )
goto valid ;
2008-02-22 19:07:18 +03:00
had_lock = ( gfs2_glock_is_locked_by_me ( dip - > i_gl ) ! = NULL ) ;
2007-02-06 11:52:16 +03: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 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
error = gfs2_dir_check ( parent - > d_inode , & dentry - > d_name , ip ) ;
2006-01-16 19:50:04 +03: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 20:04:26 +04:00
valid_gunlock :
2007-02-06 11:52:16 +03:00
if ( ! had_lock )
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-09-04 20:04:26 +04:00
valid :
2006-01-16 19:50:04 +03:00
dput ( parent ) ;
return 1 ;
2006-09-04 20:04:26 +04:00
invalid_gunlock :
2007-02-06 11:52:16 +03:00
if ( ! had_lock )
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-09-04 20:04:26 +04:00
invalid :
2006-01-16 19:50:04 +03: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 20:04:26 +04:00
fail_gunlock :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-09-04 20:04:26 +04:00
fail :
2006-01-16 19:50:04 +03:00
dput ( parent ) ;
return 0 ;
}
2006-03-20 20:30:04 +03:00
static int gfs2_dhash ( struct dentry * dentry , struct qstr * str )
{
str - > hash = gfs2_disk_hash ( str - > name , str - > len ) ;
return 0 ;
}
2006-01-16 19:50:04 +03:00
struct dentry_operations gfs2_dops = {
. d_revalidate = gfs2_drevalidate ,
2006-03-20 20:30:04 +03:00
. d_hash = gfs2_dhash ,
2006-01-16 19:50:04 +03:00
} ;