@@ -840,9 +840,109 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
840840 return rc ;
841841}
842842
843+ static bool emit_cached_dirents (struct cached_dirents * cde ,
844+ struct dir_context * ctx )
845+ {
846+ struct cached_dirent * dirent ;
847+ int rc ;
848+
849+ list_for_each_entry (dirent , & cde -> entries , entry ) {
850+ if (ctx -> pos >= dirent -> pos )
851+ continue ;
852+ ctx -> pos = dirent -> pos ;
853+ rc = dir_emit (ctx , dirent -> name , dirent -> namelen ,
854+ dirent -> fattr .cf_uniqueid ,
855+ dirent -> fattr .cf_dtype );
856+ if (!rc )
857+ return rc ;
858+ }
859+ return true;
860+ }
861+
862+ static void update_cached_dirents_count (struct cached_dirents * cde ,
863+ struct dir_context * ctx )
864+ {
865+ if (cde -> ctx != ctx )
866+ return ;
867+ if (cde -> is_valid || cde -> is_failed )
868+ return ;
869+
870+ cde -> pos ++ ;
871+ }
872+
873+ static void finished_cached_dirents_count (struct cached_dirents * cde ,
874+ struct dir_context * ctx )
875+ {
876+ if (cde -> ctx != ctx )
877+ return ;
878+ if (cde -> is_valid || cde -> is_failed )
879+ return ;
880+ if (ctx -> pos != cde -> pos )
881+ return ;
882+
883+ cde -> is_valid = 1 ;
884+ }
885+
886+ static void add_cached_dirent (struct cached_dirents * cde ,
887+ struct dir_context * ctx ,
888+ const char * name , int namelen ,
889+ struct cifs_fattr * fattr )
890+ {
891+ struct cached_dirent * de ;
892+
893+ if (cde -> ctx != ctx )
894+ return ;
895+ if (cde -> is_valid || cde -> is_failed )
896+ return ;
897+ if (ctx -> pos != cde -> pos ) {
898+ cde -> is_failed = 1 ;
899+ return ;
900+ }
901+ de = kzalloc (sizeof (* de ), GFP_ATOMIC );
902+ if (de == NULL ) {
903+ cde -> is_failed = 1 ;
904+ return ;
905+ }
906+ de -> namelen = namelen ;
907+ de -> name = kstrndup (name , namelen , GFP_ATOMIC );
908+ if (de -> name == NULL ) {
909+ kfree (de );
910+ cde -> is_failed = 1 ;
911+ return ;
912+ }
913+ de -> pos = ctx -> pos ;
914+
915+ memcpy (& de -> fattr , fattr , sizeof (struct cifs_fattr ));
916+
917+ list_add_tail (& de -> entry , & cde -> entries );
918+ }
919+
920+ static bool cifs_dir_emit (struct dir_context * ctx ,
921+ const char * name , int namelen ,
922+ struct cifs_fattr * fattr ,
923+ struct cached_fid * cfid )
924+ {
925+ bool rc ;
926+ ino_t ino = cifs_uniqueid_to_ino_t (fattr -> cf_uniqueid );
927+
928+ rc = dir_emit (ctx , name , namelen , ino , fattr -> cf_dtype );
929+ if (!rc )
930+ return rc ;
931+
932+ if (cfid ) {
933+ mutex_lock (& cfid -> dirents .de_mutex );
934+ add_cached_dirent (& cfid -> dirents , ctx , name , namelen ,
935+ fattr );
936+ mutex_unlock (& cfid -> dirents .de_mutex );
937+ }
938+
939+ return rc ;
940+ }
941+
843942static int cifs_filldir (char * find_entry , struct file * file ,
844- struct dir_context * ctx ,
845- char * scratch_buf , unsigned int max_len )
943+ struct dir_context * ctx ,
944+ char * scratch_buf , unsigned int max_len ,
945+ struct cached_fid * cfid )
846946{
847947 struct cifsFileInfo * file_info = file -> private_data ;
848948 struct super_block * sb = file_inode (file )-> i_sb ;
@@ -851,7 +951,6 @@ static int cifs_filldir(char *find_entry, struct file *file,
851951 struct cifs_fattr fattr ;
852952 struct qstr name ;
853953 int rc = 0 ;
854- ino_t ino ;
855954
856955 rc = cifs_fill_dirent (& de , find_entry , file_info -> srch_inf .info_level ,
857956 file_info -> srch_inf .unicode );
@@ -931,8 +1030,8 @@ static int cifs_filldir(char *find_entry, struct file *file,
9311030
9321031 cifs_prime_dcache (file_dentry (file ), & name , & fattr );
9331032
934- ino = cifs_uniqueid_to_ino_t ( fattr . cf_uniqueid );
935- return ! dir_emit ( ctx , name . name , name . len , ino , fattr . cf_dtype );
1033+ return ! cifs_dir_emit ( ctx , name . name , name . len ,
1034+ & fattr , cfid );
9361035}
9371036
9381037
@@ -941,15 +1040,18 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
9411040 int rc = 0 ;
9421041 unsigned int xid ;
9431042 int i ;
1043+ struct tcon_link * tlink = NULL ;
9441044 struct cifs_tcon * tcon ;
945- struct cifsFileInfo * cifsFile = NULL ;
1045+ struct cifsFileInfo * cifsFile ;
9461046 char * current_entry ;
9471047 int num_to_fill = 0 ;
9481048 char * tmp_buf = NULL ;
9491049 char * end_of_smb ;
9501050 unsigned int max_len ;
9511051 const char * full_path ;
9521052 void * page = alloc_dentry_path ();
1053+ struct cached_fid * cfid = NULL ;
1054+ struct cifs_sb_info * cifs_sb = CIFS_FILE_SB (file );
9531055
9541056 xid = get_xid ();
9551057
@@ -959,6 +1061,56 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
9591061 goto rddir2_exit ;
9601062 }
9611063
1064+ if (file -> private_data == NULL ) {
1065+ tlink = cifs_sb_tlink (cifs_sb );
1066+ if (IS_ERR (tlink ))
1067+ goto cache_not_found ;
1068+ tcon = tlink_tcon (tlink );
1069+ } else {
1070+ cifsFile = file -> private_data ;
1071+ tcon = tlink_tcon (cifsFile -> tlink );
1072+ }
1073+
1074+ rc = open_cached_dir (xid , tcon , full_path , cifs_sb , & cfid );
1075+ cifs_put_tlink (tlink );
1076+ if (rc )
1077+ goto cache_not_found ;
1078+
1079+ mutex_lock (& cfid -> dirents .de_mutex );
1080+ /*
1081+ * If this was reading from the start of the directory
1082+ * we need to initialize scanning and storing the
1083+ * directory content.
1084+ */
1085+ if (ctx -> pos == 0 && cfid -> dirents .ctx == NULL ) {
1086+ cfid -> dirents .ctx = ctx ;
1087+ cfid -> dirents .pos = 2 ;
1088+ }
1089+ /*
1090+ * If we already have the entire directory cached then
1091+ * we can just serve the cache.
1092+ */
1093+ if (cfid -> dirents .is_valid ) {
1094+ if (!dir_emit_dots (file , ctx )) {
1095+ mutex_unlock (& cfid -> dirents .de_mutex );
1096+ goto rddir2_exit ;
1097+ }
1098+ emit_cached_dirents (& cfid -> dirents , ctx );
1099+ mutex_unlock (& cfid -> dirents .de_mutex );
1100+ goto rddir2_exit ;
1101+ }
1102+ mutex_unlock (& cfid -> dirents .de_mutex );
1103+
1104+ /* Drop the cache while calling initiate_cifs_search and
1105+ * find_cifs_entry in case there will be reconnects during
1106+ * query_directory.
1107+ */
1108+ if (cfid ) {
1109+ close_cached_dir (cfid );
1110+ cfid = NULL ;
1111+ }
1112+
1113+ cache_not_found :
9621114 /*
9631115 * Ensure FindFirst doesn't fail before doing filldir() for '.' and
9641116 * '..'. Otherwise we won't be able to notify VFS in case of failure.
@@ -977,7 +1129,6 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
9771129 is in current search buffer?
9781130 if it before then restart search
9791131 if after then keep searching till find it */
980-
9811132 cifsFile = file -> private_data ;
9821133 if (cifsFile -> srch_inf .endOfSearch ) {
9831134 if (cifsFile -> srch_inf .emptyDir ) {
@@ -993,12 +1144,18 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
9931144 tcon = tlink_tcon (cifsFile -> tlink );
9941145 rc = find_cifs_entry (xid , tcon , ctx -> pos , file , full_path ,
9951146 & current_entry , & num_to_fill );
1147+ open_cached_dir (xid , tcon , full_path , cifs_sb , & cfid );
9961148 if (rc ) {
9971149 cifs_dbg (FYI , "fce error %d\n" , rc );
9981150 goto rddir2_exit ;
9991151 } else if (current_entry != NULL ) {
10001152 cifs_dbg (FYI , "entry %lld found\n" , ctx -> pos );
10011153 } else {
1154+ if (cfid ) {
1155+ mutex_lock (& cfid -> dirents .de_mutex );
1156+ finished_cached_dirents_count (& cfid -> dirents , ctx );
1157+ mutex_unlock (& cfid -> dirents .de_mutex );
1158+ }
10021159 cifs_dbg (FYI , "Could not find entry\n" );
10031160 goto rddir2_exit ;
10041161 }
@@ -1028,14 +1185,20 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
10281185 */
10291186 * tmp_buf = 0 ;
10301187 rc = cifs_filldir (current_entry , file , ctx ,
1031- tmp_buf , max_len );
1188+ tmp_buf , max_len , cfid );
10321189 if (rc ) {
10331190 if (rc > 0 )
10341191 rc = 0 ;
10351192 break ;
10361193 }
10371194
10381195 ctx -> pos ++ ;
1196+ if (cfid ) {
1197+ mutex_lock (& cfid -> dirents .de_mutex );
1198+ update_cached_dirents_count (& cfid -> dirents , ctx );
1199+ mutex_unlock (& cfid -> dirents .de_mutex );
1200+ }
1201+
10391202 if (ctx -> pos ==
10401203 cifsFile -> srch_inf .index_of_last_entry ) {
10411204 cifs_dbg (FYI , "last entry in buf at pos %lld %s\n" ,
@@ -1050,6 +1213,8 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
10501213 kfree (tmp_buf );
10511214
10521215rddir2_exit :
1216+ if (cfid )
1217+ close_cached_dir (cfid );
10531218 free_dentry_path (page );
10541219 free_xid (xid );
10551220 return rc ;
0 commit comments