aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
authorSteve French <smfrench@austin.rr.com>2005-04-29 01:41:08 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-29 01:41:08 -0400
commit966ca9234754ece58870075972ef103e354de075 (patch)
tree491cf960229a066196d1efb3f5687912b8b44fee /fs/cifs/readdir.c
parent433dc24f24b409fb130f638aa85470a0eb666206 (diff)
[PATCH] cifs: Fix caching problem
pointed out by Dave Stahl and Vince Negri in which cifs can update the last modify time on a server modified file without invalidating the local cached data due to an intervening readdir. Signed-off-by: Steve French (sfrench@us.ibm.com) Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r--fs/cifs/readdir.c70
1 files changed, 57 insertions, 13 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 7ca876b6f2ab..39170cffcad8 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Directory search handling 4 * Directory search handling
5 * 5 *
6 * Copyright (C) International Business Machines Corp., 2004 6 * Copyright (C) International Business Machines Corp., 2004, 2005
7 * Author(s): Steve French (sfrench@us.ibm.com) 7 * Author(s): Steve French (sfrench@us.ibm.com)
8 * 8 *
9 * This library is free software; you can redistribute it and/or modify 9 * This library is free software; you can redistribute it and/or modify
@@ -65,14 +65,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
65 struct cifsTconInfo *pTcon; 65 struct cifsTconInfo *pTcon;
66 int rc = 0; 66 int rc = 0;
67 67
68 cFYI(1, ("For %s ", qstring->name)); 68 cFYI(1, ("For %s", qstring->name));
69 cifs_sb = CIFS_SB(file->f_dentry->d_sb); 69 cifs_sb = CIFS_SB(file->f_dentry->d_sb);
70 pTcon = cifs_sb->tcon; 70 pTcon = cifs_sb->tcon;
71 71
72 qstring->hash = full_name_hash(qstring->name, qstring->len); 72 qstring->hash = full_name_hash(qstring->name, qstring->len);
73 tmp_dentry = d_lookup(file->f_dentry, qstring); 73 tmp_dentry = d_lookup(file->f_dentry, qstring);
74 if (tmp_dentry) { 74 if (tmp_dentry) {
75 cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); 75 cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
76 *ptmp_inode = tmp_dentry->d_inode; 76 *ptmp_inode = tmp_dentry->d_inode;
77/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/ 77/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
78 if(*ptmp_inode == NULL) { 78 if(*ptmp_inode == NULL) {
@@ -105,8 +105,11 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
105} 105}
106 106
107static void fill_in_inode(struct inode *tmp_inode, 107static void fill_in_inode(struct inode *tmp_inode,
108 FILE_DIRECTORY_INFO *pfindData, int *pobject_type) 108 FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
109{ 109{
110 loff_t local_size;
111 struct timespec local_mtime;
112
110 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 113 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
111 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 114 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
112 __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); 115 __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
@@ -116,6 +119,10 @@ static void fill_in_inode(struct inode *tmp_inode,
116 cifsInfo->cifsAttrs = attr; 119 cifsInfo->cifsAttrs = attr;
117 cifsInfo->time = jiffies; 120 cifsInfo->time = jiffies;
118 121
122 /* save mtime and size */
123 local_mtime = tmp_inode->i_mtime;
124 local_size = tmp_inode->i_size;
125
119 /* Linux can not store file creation time unfortunately so ignore it */ 126 /* Linux can not store file creation time unfortunately so ignore it */
120 tmp_inode->i_atime = 127 tmp_inode->i_atime =
121 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 128 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
@@ -134,7 +141,6 @@ static void fill_in_inode(struct inode *tmp_inode,
134 tmp_inode->i_mode = cifs_sb->mnt_file_mode; 141 tmp_inode->i_mode = cifs_sb->mnt_file_mode;
135 } 142 }
136 143
137 cFYI(0,("CIFS FFIRST: Attributes came in as 0x%x",attr));
138 if (attr & ATTR_DIRECTORY) { 144 if (attr & ATTR_DIRECTORY) {
139 *pobject_type = DT_DIR; 145 *pobject_type = DT_DIR;
140 /* override default perms since we do not lock dirs */ 146 /* override default perms since we do not lock dirs */
@@ -175,30 +181,46 @@ static void fill_in_inode(struct inode *tmp_inode,
175 (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks, 181 (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
176 tmp_inode->i_blksize)); 182 tmp_inode->i_blksize));
177 if (S_ISREG(tmp_inode->i_mode)) { 183 if (S_ISREG(tmp_inode->i_mode)) {
178 cFYI(1, (" File inode ")); 184 cFYI(1, ("File inode"));
179 tmp_inode->i_op = &cifs_file_inode_ops; 185 tmp_inode->i_op = &cifs_file_inode_ops;
180 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) 186 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
181 tmp_inode->i_fop = &cifs_file_direct_ops; 187 tmp_inode->i_fop = &cifs_file_direct_ops;
182 else 188 else
183 tmp_inode->i_fop = &cifs_file_ops; 189 tmp_inode->i_fop = &cifs_file_ops;
184 tmp_inode->i_data.a_ops = &cifs_addr_ops; 190 tmp_inode->i_data.a_ops = &cifs_addr_ops;
191
192 if(isNewInode)
193 return; /* No sense invalidating pages for new inode since we
194 have not started caching readahead file data yet */
195
196 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
197 (local_size == tmp_inode->i_size)) {
198 cFYI(1, ("inode exists but unchanged"));
199 } else {
200 /* file may have changed on server */
201 cFYI(1, ("invalidate inode, readdir detected change"));
202 invalidate_remote_inode(tmp_inode);
203 }
185 } else if (S_ISDIR(tmp_inode->i_mode)) { 204 } else if (S_ISDIR(tmp_inode->i_mode)) {
186 cFYI(1, (" Directory inode")); 205 cFYI(1, ("Directory inode"));
187 tmp_inode->i_op = &cifs_dir_inode_ops; 206 tmp_inode->i_op = &cifs_dir_inode_ops;
188 tmp_inode->i_fop = &cifs_dir_ops; 207 tmp_inode->i_fop = &cifs_dir_ops;
189 } else if (S_ISLNK(tmp_inode->i_mode)) { 208 } else if (S_ISLNK(tmp_inode->i_mode)) {
190 cFYI(1, (" Symbolic Link inode ")); 209 cFYI(1, ("Symbolic Link inode"));
191 tmp_inode->i_op = &cifs_symlink_inode_ops; 210 tmp_inode->i_op = &cifs_symlink_inode_ops;
192 } else { 211 } else {
193 cFYI(1, (" Init special inode ")); 212 cFYI(1, ("Init special inode"));
194 init_special_inode(tmp_inode, tmp_inode->i_mode, 213 init_special_inode(tmp_inode, tmp_inode->i_mode,
195 tmp_inode->i_rdev); 214 tmp_inode->i_rdev);
196 } 215 }
197} 216}
198 217
199static void unix_fill_in_inode(struct inode *tmp_inode, 218static void unix_fill_in_inode(struct inode *tmp_inode,
200 FILE_UNIX_INFO *pfindData, int *pobject_type) 219 FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode)
201{ 220{
221 loff_t local_size;
222 struct timespec local_mtime;
223
202 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); 224 struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
203 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); 225 struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
204 226
@@ -208,6 +230,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
208 cifsInfo->time = jiffies; 230 cifsInfo->time = jiffies;
209 atomic_inc(&cifsInfo->inUse); 231 atomic_inc(&cifsInfo->inUse);
210 232
233 /* save mtime and size */
234 local_mtime = tmp_inode->i_mtime;
235 local_size = tmp_inode->i_size;
236
211 tmp_inode->i_atime = 237 tmp_inode->i_atime =
212 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 238 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
213 tmp_inode->i_mtime = 239 tmp_inode->i_mtime =
@@ -265,6 +291,19 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
265 else 291 else
266 tmp_inode->i_fop = &cifs_file_ops; 292 tmp_inode->i_fop = &cifs_file_ops;
267 tmp_inode->i_data.a_ops = &cifs_addr_ops; 293 tmp_inode->i_data.a_ops = &cifs_addr_ops;
294
295 if(isNewInode)
296 return; /* No sense invalidating pages for new inode since we
297 have not started caching readahead file data yet */
298
299 if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
300 (local_size == tmp_inode->i_size)) {
301 cFYI(1, ("inode exists but unchanged"));
302 } else {
303 /* file may have changed on server */
304 cFYI(1, ("invalidate inode, readdir detected change"));
305 invalidate_remote_inode(tmp_inode);
306 }
268 } else if (S_ISDIR(tmp_inode->i_mode)) { 307 } else if (S_ISDIR(tmp_inode->i_mode)) {
269 cFYI(1, ("Directory inode")); 308 cFYI(1, ("Directory inode"));
270 tmp_inode->i_op = &cifs_dir_inode_ops; 309 tmp_inode->i_op = &cifs_dir_inode_ops;
@@ -321,7 +360,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
321 return -ENOMEM; 360 return -ENOMEM;
322 } 361 }
323 362
324 cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); 363 cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));
325 364
326ffirst_retry: 365ffirst_retry:
327 /* test for Unix extensions */ 366 /* test for Unix extensions */
@@ -666,10 +705,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
666 insert_inode_hash(tmp_inode); 705 insert_inode_hash(tmp_inode);
667 } 706 }
668 707
708 /* we pass in rc below, indicating whether it is a new inode,
709 so we can figure out whether to invalidate the inode cached
710 data if the file has changed */
669 if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { 711 if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
670 unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type); 712 unix_fill_in_inode(tmp_inode,
713 (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc);
671 } else { 714 } else {
672 fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type); 715 fill_in_inode(tmp_inode,
716 (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
673 } 717 }
674 718
675 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); 719 rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);