aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/cifs/AUTHORS24
-rw-r--r--fs/cifs/CHANGES8
-rw-r--r--fs/cifs/cifsfs.h4
-rw-r--r--fs/cifs/cifssmb.c2
-rw-r--r--fs/cifs/readdir.c70
5 files changed, 83 insertions, 25 deletions
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index acce36e25d2e..72fdc10dfdd7 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -4,13 +4,16 @@ Steve French (sfrench@samba.org)
4 4
5The author wishes to express his appreciation and thanks to: 5The author wishes to express his appreciation and thanks to:
6Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS 6Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
7improvements. Thanks to IBM for allowing me the time and test resources to pursue 7improvements. Thanks to IBM for allowing me time and test resources to pursue
8this project. Jim McDonough from IBM (and the Samba Team) for his help. 8this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
9The IBM Linux JFS team for explaining many esoteric Linux filesystem features. 9the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
10Jeremy Allison of the Samba team has done invaluable work in adding the server
11side of the original CIFS Unix extensions and reviewing and implementing
12portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank
10Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) 13Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
11for proving years ago that a very good smb/cifs client could be done on a Unix like 14for proving years ago that very good smb/cifs clients could be done on Unix-like
12operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin 15operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John
13and others for their work on the Linux smbfs module over the years. Thanks to 16Newbigin and others for their work on the Linux smbfs module. Thanks to
14the other members of the Storage Network Industry Association CIFS Technical 17the other members of the Storage Network Industry Association CIFS Technical
15Workgroup for their work specifying this highly complex protocol and finally 18Workgroup for their work specifying this highly complex protocol and finally
16thanks to the Samba team for their technical advice and encouragement. 19thanks to the Samba team for their technical advice and encouragement.
@@ -24,9 +27,11 @@ Shobhit Dayal
24Sergey Vlasov 27Sergey Vlasov
25Richard Hughes 28Richard Hughes
26Yury Umanets 29Yury Umanets
27Mark Hamzy 30Mark Hamzy (for some of the early cifs IPv6 work)
28Domen Puncer 31Domen Puncer
29Jesper Juhl 32Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
33Vince Negri and Dave Stahl (for finding an important caching bug)
34Adrian Bunk (kcalloc cleanups)
30 35
31Test case and Bug Report contributors 36Test case and Bug Report contributors
32------------------------------------- 37-------------------------------------
@@ -36,7 +41,8 @@ Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
36Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, 41Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
37Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special 42Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special
38mention to the Stanford Checker (SWAT) which pointed out many minor 43mention to the Stanford Checker (SWAT) which pointed out many minor
39bugs in error paths. 44bugs in error paths. Valuable suggestions also have come from Al Viro
45and Dave Miller.
40 46
41And thanks to the IBM LTC and Power test teams and SuSE testers for 47And thanks to the IBM LTC and Power test teams and SuSE testers for
42finding multiple bugs during excellent stress test runs. 48finding multiple bugs during excellent stress test runs.
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index be3a57509e60..0414eb325468 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,11 @@
1Version 1.33
2------------
3Fix caching problem, in which readdir of directory containing a file
4which was cached could cause the file's time stamp to be updated
5without invalidating the readahead data (so we could get stale
6file data on the client for that file even as the server copy changed).
7
8
1Version 1.32 9Version 1.32
2------------ 10------------
3Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one 11Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index e0e46f4bff97..8f742796a627 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * fs/cifs/cifsfs.h 2 * fs/cifs/cifsfs.h
3 * 3 *
4 * Copyright (c) International Business Machines Corp., 2002 4 * Copyright (c) International Business Machines Corp., 2002, 2005
5 * Author(s): Steve French (sfrench@us.ibm.com) 5 * Author(s): Steve French (sfrench@us.ibm.com)
6 * 6 *
7 * This library is free software; you can redistribute it and/or modify 7 * This library is free software; you can redistribute it and/or modify
@@ -96,5 +96,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
96extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); 96extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
97extern int cifs_ioctl (struct inode * inode, struct file * filep, 97extern int cifs_ioctl (struct inode * inode, struct file * filep,
98 unsigned int command, unsigned long arg); 98 unsigned int command, unsigned long arg);
99#define CIFS_VERSION "1.32" 99#define CIFS_VERSION "1.33"
100#endif /* _CIFSFS_H */ 100#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f7c4914c3dd9..b102ddb977ca 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -464,7 +464,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
464 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, 464 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
465 &length, 0); 465 &length, 0);
466 if (rc) 466 if (rc)
467 cFYI(1, (" Tree disconnect failed %d", rc)); 467 cFYI(1, ("Tree disconnect failed %d", rc));
468 468
469 if (smb_buffer) 469 if (smb_buffer)
470 cifs_small_buf_release(smb_buffer); 470 cifs_small_buf_release(smb_buffer);
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);