Browse Source

[CIFS] Fix readdir caching when unlink removes file in current search
buffer, and this is followed by a rewind search to just before
the deleted entry.

Signed-off-by: Steve French (sfrench@us.ibm.com)

Steve French 20 years ago
parent
commit
eafe870121
3 changed files with 38 additions and 6 deletions
  1. 5 0
      fs/cifs/CHANGES
  2. 1 1
      fs/cifs/cifsfs.h
  3. 32 5
      fs/cifs/readdir.c

+ 5 - 0
fs/cifs/CHANGES

@@ -1,3 +1,8 @@
+Version 1.37
+------------
+Fix readdir caching when unlink removes file in current search buffer,
+and this is followed by a rewind search to just before the deleted entry.
+
 Version 1.36
 Version 1.36
 ------------
 ------------
 Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
 Add support for mounting to older pre-CIFS servers such as Windows9x and ME.

+ 1 - 1
fs/cifs/cifsfs.h

@@ -97,5 +97,5 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
 		       unsigned int command, unsigned long arg);
 		       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.36"
+#define CIFS_VERSION   "1.37"
 #endif				/* _CIFSFS_H */
 #endif				/* _CIFSFS_H */

+ 32 - 5
fs/cifs/readdir.c

@@ -396,7 +396,8 @@ ffirst_retry:
 
 
 	rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
 	rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
 		&cifsFile->netfid, &cifsFile->srch_inf,
 		&cifsFile->netfid, &cifsFile->srch_inf,
-		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+		cifs_sb->mnt_cifs_flags & 
+			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 	if(rc == 0)
 	if(rc == 0)
 		cifsFile->invalidHandle = FALSE;
 		cifsFile->invalidHandle = FALSE;
 	if((rc == -EOPNOTSUPP) && 
 	if((rc == -EOPNOTSUPP) && 
@@ -513,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
 	return rc;
 	return rc;
 }
 }
 
 
+/* Check if directory that we are searching has changed so we can decide
+   whether we can use the cached search results from the previous search */
+static int is_dir_changed(struct file * file)
+{
+	struct inode * inode;
+	struct cifsInodeInfo *cifsInfo;
+
+	if(file->f_dentry == NULL)
+		return 0;
+
+	inode = file->f_dentry->d_inode;
+
+	if(inode == NULL)
+		return 0;
+
+	cifsInfo = CIFS_I(inode);
+
+	if(cifsInfo->time == 0)
+		return 1; /* directory was changed, perhaps due to unlink */
+	else
+		return 0;
+
+}
+
 /* find the corresponding entry in the search */
 /* find the corresponding entry in the search */
 /* Note that the SMB server returns search entries for . and .. which
 /* Note that the SMB server returns search entries for . and .. which
    complicates logic here if we choose to parse for them and we do not
    complicates logic here if we choose to parse for them and we do not
@@ -529,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 	struct cifsFileInfo * cifsFile = file->private_data;
 	struct cifsFileInfo * cifsFile = file->private_data;
 	/* check if index in the buffer */
 	/* check if index in the buffer */
 	
 	
-	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL))
+	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || 
+	   (num_to_ret == NULL))
 		return -ENOENT;
 		return -ENOENT;
 	
 	
 	*ppCurrentEntry = NULL;
 	*ppCurrentEntry = NULL;
@@ -537,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 		cifsFile->srch_inf.index_of_last_entry - 
 		cifsFile->srch_inf.index_of_last_entry - 
 			cifsFile->srch_inf.entries_in_buffer;
 			cifsFile->srch_inf.entries_in_buffer;
 /*	dump_cifs_file_struct(file, "In fce ");*/
 /*	dump_cifs_file_struct(file, "In fce ");*/
-	if(index_to_find < first_entry_in_buffer) {
+	if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
+	     is_dir_changed(file)) || 
+	   (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
 		/* close and restart search */
 		cFYI(1,("search backing up - close and restart search"));
 		cFYI(1,("search backing up - close and restart search"));
 		cifsFile->invalidHandle = TRUE;
 		cifsFile->invalidHandle = TRUE;
@@ -604,7 +632,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 	}
 	}
 
 
 	if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
 	if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
-		cFYI(1,("can not return entries when pos_in_buf beyond last entry"));
+		cFYI(1,("can not return entries pos_in_buf beyond last entry"));
 		*num_to_ret = 0;
 		*num_to_ret = 0;
 	} else
 	} else
 		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
 		*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
@@ -833,7 +861,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 	if(pTcon == NULL)
 	if(pTcon == NULL)
 		return -EINVAL;
 		return -EINVAL;
 
 
-
 	switch ((int) file->f_pos) {
 	switch ((int) file->f_pos) {
 	case 0:
 	case 0:
 		/*if (filldir(direntry, ".", 1, file->f_pos,
 		/*if (filldir(direntry, ".", 1, file->f_pos,