2015-07-17 17:38:12 +03:00
/*
* ( C ) 2001 Clemson University and The University of Chicago
*
* See COPYING in top - level directory .
*/
/*
* Implementation of dentry ( directory cache ) functions .
*/
# include "protocol.h"
2015-12-04 20:56:14 +03:00
# include "orangefs-kernel.h"
2015-07-17 17:38:12 +03:00
/* Returns 1 if dentry can still be trusted, else 0. */
2015-11-24 23:12:14 +03:00
static int orangefs_revalidate_lookup ( struct dentry * dentry )
2015-07-17 17:38:12 +03:00
{
struct dentry * parent_dentry = dget_parent ( dentry ) ;
struct inode * parent_inode = parent_dentry - > d_inode ;
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * parent = ORANGEFS_I ( parent_inode ) ;
2015-07-17 17:38:12 +03:00
struct inode * inode = dentry - > d_inode ;
2015-11-24 23:12:14 +03:00
struct orangefs_kernel_op_s * new_op ;
2015-07-17 17:38:12 +03:00
int ret = 0 ;
int err = 0 ;
gossip_debug ( GOSSIP_DCACHE_DEBUG , " %s: attempting lookup. \n " , __func__ ) ;
2015-11-24 23:12:14 +03:00
new_op = op_alloc ( ORANGEFS_VFS_OP_LOOKUP ) ;
2015-07-17 17:38:12 +03:00
if ( ! new_op )
goto out_put_parent ;
2015-11-24 23:12:14 +03:00
new_op - > upcall . req . lookup . sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW ;
2015-07-17 17:38:12 +03:00
new_op - > upcall . req . lookup . parent_refn = parent - > refn ;
strncpy ( new_op - > upcall . req . lookup . d_name ,
dentry - > d_name . name ,
2016-02-20 22:22:40 +03:00
ORANGEFS_NAME_MAX ) ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_DCACHE_DEBUG ,
" %s:%s:%d interrupt flag [%d] \n " ,
__FILE__ ,
__func__ ,
__LINE__ ,
get_interruptible_flag ( parent_inode ) ) ;
2015-11-24 23:12:14 +03:00
err = service_operation ( new_op , " orangefs_lookup " ,
2015-07-17 17:38:12 +03:00
get_interruptible_flag ( parent_inode ) ) ;
2016-01-28 18:19:40 +03:00
/* Positive dentry: reject if error or not the same inode. */
if ( inode ) {
if ( err ) {
gossip_debug ( GOSSIP_DCACHE_DEBUG ,
" %s:%s:%d lookup failure. \n " ,
__FILE__ , __func__ , __LINE__ ) ;
goto out_drop ;
}
if ( ! match_handle ( new_op - > downcall . resp . lookup . refn . khandle ,
inode ) ) {
gossip_debug ( GOSSIP_DCACHE_DEBUG ,
" %s:%s:%d no match. \n " ,
__FILE__ , __func__ , __LINE__ ) ;
goto out_drop ;
}
/* Negative dentry: reject if success or error other than ENOENT. */
} else {
gossip_debug ( GOSSIP_DCACHE_DEBUG , " %s: negative dentry. \n " ,
__func__ ) ;
if ( ! err | | err ! = - ENOENT ) {
if ( new_op - > downcall . status ! = 0 )
gossip_debug ( GOSSIP_DCACHE_DEBUG ,
" %s:%s:%d lookup failure. \n " ,
__FILE__ , __func__ , __LINE__ ) ;
goto out_drop ;
}
2015-07-17 17:38:12 +03:00
}
ret = 1 ;
out_release_op :
op_release ( new_op ) ;
out_put_parent :
dput ( parent_dentry ) ;
return ret ;
out_drop :
2016-01-28 18:19:40 +03:00
gossip_debug ( GOSSIP_DCACHE_DEBUG , " %s:%s:%d revalidate failed \n " ,
__FILE__ , __func__ , __LINE__ ) ;
2015-07-17 17:38:12 +03:00
goto out_release_op ;
}
/*
* Verify that dentry is valid .
*
2015-12-30 21:04:28 +03:00
* Should return 1 if dentry can still be trusted , else 0.
2015-07-17 17:38:12 +03:00
*/
2015-11-24 23:12:14 +03:00
static int orangefs_d_revalidate ( struct dentry * dentry , unsigned int flags )
2015-07-17 17:38:12 +03:00
{
2016-01-28 18:19:40 +03:00
int ret ;
2015-07-17 17:38:12 +03:00
if ( flags & LOOKUP_RCU )
return - ECHILD ;
gossip_debug ( GOSSIP_DCACHE_DEBUG , " %s: called on dentry %p. \n " ,
__func__ , dentry ) ;
2016-01-28 18:19:40 +03:00
/* skip root handle lookups. */
if ( dentry - > d_inode & & is_root_handle ( dentry - > d_inode ) )
return 1 ;
/*
* If this passes , the positive dentry still exists or the negative
* dentry still does not exist .
*/
2016-02-20 21:10:47 +03:00
if ( ! orangefs_revalidate_lookup ( dentry ) )
2016-01-28 18:19:40 +03:00
return 0 ;
2015-07-17 17:38:12 +03:00
2016-01-28 18:19:40 +03:00
/* We do not need to continue with negative dentries. */
if ( ! dentry - > d_inode )
2015-12-30 21:04:28 +03:00
goto out ;
2015-07-17 17:38:12 +03:00
2016-01-28 18:19:40 +03:00
/* Now we must perform a getattr to validate the inode contents. */
2016-01-30 21:46:54 +03:00
2016-03-17 22:15:16 +03:00
ret = orangefs_inode_check_changed ( dentry - > d_inode ) ;
2016-01-28 18:19:40 +03:00
if ( ret < 0 ) {
gossip_debug ( GOSSIP_DCACHE_DEBUG , " %s:%s:%d getattr failure. \n " ,
__FILE__ , __func__ , __LINE__ ) ;
return 0 ;
}
2016-02-20 21:10:47 +03:00
if ( ret = = 0 )
2016-01-28 18:19:40 +03:00
return 0 ;
2015-12-30 21:04:28 +03:00
out :
2016-01-28 18:19:40 +03:00
gossip_debug ( GOSSIP_DCACHE_DEBUG ,
" %s: negative dentry or positive dentry and inode valid. \n " ,
__func__ ) ;
return 1 ;
2015-07-17 17:38:12 +03:00
}
2015-11-24 23:12:14 +03:00
const struct dentry_operations orangefs_dentry_operations = {
. d_revalidate = orangefs_d_revalidate ,
2015-07-17 17:38:12 +03:00
} ;