@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = {
static struct nfs_open_dir_context * alloc_nfs_open_dir_context ( struct inode * dir , struct rpc_cred * cred )
{
struct nfs_inode * nfsi = NFS_I ( dir ) ;
struct nfs_open_dir_context * ctx ;
ctx = kmalloc ( sizeof ( * ctx ) , GFP_KERNEL ) ;
if ( ctx ! = NULL ) {
ctx - > duped = 0 ;
ctx - > attr_gencount = NFS_I ( dir ) - > attr_gencount ;
ctx - > attr_gencount = nfsi - > attr_gencount ;
ctx - > dir_cookie = 0 ;
ctx - > dup_cookie = 0 ;
ctx - > cred = get_rpccred ( cred ) ;
spin_lock ( & dir - > i_lock ) ;
list_add ( & ctx - > list , & nfsi - > open_files ) ;
spin_unlock ( & dir - > i_lock ) ;
return ctx ;
}
return ERR_PTR ( - ENOMEM ) ;
}
static void put_nfs_open_dir_context ( struct nfs_open_dir_context * ctx )
static void put_nfs_open_dir_context ( struct inode * dir , struct nfs_open_dir_context * ctx )
{
spin_lock ( & dir - > i_lock ) ;
list_del ( & ctx - > list ) ;
spin_unlock ( & dir - > i_lock ) ;
put_rpccred ( ctx - > cred ) ;
kfree ( ctx ) ;
}
@ -126,7 +133,7 @@ out:
static int
nfs_closedir ( struct inode * inode , struct file * filp )
{
put_nfs_open_dir_context ( filp - > private_data ) ;
put_nfs_open_dir_context ( filp - > f_path . dentry - > d_inode , filp - > private_data ) ;
return 0 ;
}
@ -437,6 +444,22 @@ void nfs_advise_use_readdirplus(struct inode *dir)
set_bit ( NFS_INO_ADVISE_RDPLUS , & NFS_I ( dir ) - > flags ) ;
}
/*
* This function is mainly for use by nfs_getattr ( ) .
*
* If this is an ' ls - l ' , we want to force use of readdirplus .
* Do this by checking if there is an active file descriptor
* and calling nfs_advise_use_readdirplus , then forcing a
* cache flush .
*/
void nfs_force_use_readdirplus ( struct inode * dir )
{
if ( ! list_empty ( & NFS_I ( dir ) - > open_files ) ) {
nfs_advise_use_readdirplus ( dir ) ;
nfs_zap_mapping ( dir , dir - > i_mapping ) ;
}
}
static
void nfs_prime_dcache ( struct dentry * parent , struct nfs_entry * entry )
{
@ -815,6 +838,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
goto out ;
}
static bool nfs_dir_mapping_need_revalidate ( struct inode * dir )
{
struct nfs_inode * nfsi = NFS_I ( dir ) ;
if ( nfs_attribute_cache_expired ( dir ) )
return true ;
if ( nfsi - > cache_validity & NFS_INO_INVALID_DATA )
return true ;
return false ;
}
/* The file offset position represents the dirent entry number. A
last cookie cache takes care of the common case of reading the
whole directory .
@ -847,7 +881,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
desc - > plus = nfs_use_readdirplus ( inode , ctx ) ? 1 : 0 ;
nfs_block_sillyrename ( dentry ) ;
if ( ctx - > pos = = 0 | | nfs_attribute_cache_expired ( inode ) )
if ( ctx - > pos = = 0 | | nfs_dir_mapping_need_revalidate ( inode ) )
res = nfs_revalidate_mapping ( inode , file - > f_mapping ) ;
if ( res < 0 )
goto out ;