diff options
author | Steve French <smfrench@austin.rr.com> | 2005-04-29 01:41:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-29 01:41:08 -0400 |
commit | 966ca9234754ece58870075972ef103e354de075 (patch) | |
tree | 491cf960229a066196d1efb3f5687912b8b44fee /fs | |
parent | 433dc24f24b409fb130f638aa85470a0eb666206 (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/AUTHORS | 24 | ||||
-rw-r--r-- | fs/cifs/CHANGES | 8 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 2 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 70 |
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 | ||
5 | The author wishes to express his appreciation and thanks to: | 5 | The author wishes to express his appreciation and thanks to: |
6 | Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS | 6 | Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS |
7 | improvements. Thanks to IBM for allowing me the time and test resources to pursue | 7 | improvements. Thanks to IBM for allowing me time and test resources to pursue |
8 | this project. Jim McDonough from IBM (and the Samba Team) for his help. | 8 | this project, to Jim McDonough from IBM (and the Samba Team) for his help, to |
9 | The IBM Linux JFS team for explaining many esoteric Linux filesystem features. | 9 | the IBM Linux JFS team for explaining many esoteric Linux filesystem features. |
10 | Jeremy Allison of the Samba team has done invaluable work in adding the server | ||
11 | side of the original CIFS Unix extensions and reviewing and implementing | ||
12 | portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank | ||
10 | Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) | 13 | Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) |
11 | for proving years ago that a very good smb/cifs client could be done on a Unix like | 14 | for proving years ago that very good smb/cifs clients could be done on Unix-like |
12 | operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin | 15 | operating systems. Volker Lendecke, Andrew Tridgell, Urban Widmark, John |
13 | and others for their work on the Linux smbfs module over the years. Thanks to | 16 | Newbigin and others for their work on the Linux smbfs module. Thanks to |
14 | the other members of the Storage Network Industry Association CIFS Technical | 17 | the other members of the Storage Network Industry Association CIFS Technical |
15 | Workgroup for their work specifying this highly complex protocol and finally | 18 | Workgroup for their work specifying this highly complex protocol and finally |
16 | thanks to the Samba team for their technical advice and encouragement. | 19 | thanks to the Samba team for their technical advice and encouragement. |
@@ -24,9 +27,11 @@ Shobhit Dayal | |||
24 | Sergey Vlasov | 27 | Sergey Vlasov |
25 | Richard Hughes | 28 | Richard Hughes |
26 | Yury Umanets | 29 | Yury Umanets |
27 | Mark Hamzy | 30 | Mark Hamzy (for some of the early cifs IPv6 work) |
28 | Domen Puncer | 31 | Domen Puncer |
29 | Jesper Juhl | 32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) |
33 | Vince Negri and Dave Stahl (for finding an important caching bug) | ||
34 | Adrian Bunk (kcalloc cleanups) | ||
30 | 35 | ||
31 | Test case and Bug Report contributors | 36 | Test case and Bug Report contributors |
32 | ------------------------------------- | 37 | ------------------------------------- |
@@ -36,7 +41,8 @@ Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, | |||
36 | Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, | 41 | Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, |
37 | Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special | 42 | Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special |
38 | mention to the Stanford Checker (SWAT) which pointed out many minor | 43 | mention to the Stanford Checker (SWAT) which pointed out many minor |
39 | bugs in error paths. | 44 | bugs in error paths. Valuable suggestions also have come from Al Viro |
45 | and Dave Miller. | ||
40 | 46 | ||
41 | And thanks to the IBM LTC and Power test teams and SuSE testers for | 47 | And thanks to the IBM LTC and Power test teams and SuSE testers for |
42 | finding multiple bugs during excellent stress test runs. | 48 | finding 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 @@ | |||
1 | Version 1.33 | ||
2 | ------------ | ||
3 | Fix caching problem, in which readdir of directory containing a file | ||
4 | which was cached could cause the file's time stamp to be updated | ||
5 | without invalidating the readahead data (so we could get stale | ||
6 | file data on the client for that file even as the server copy changed). | ||
7 | |||
8 | |||
1 | Version 1.32 | 9 | Version 1.32 |
2 | ------------ | 10 | ------------ |
3 | Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one | 11 | Fix 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); | |||
96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
97 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 97 | extern 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 | ||
107 | static void fill_in_inode(struct inode *tmp_inode, | 107 | static 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 | ||
199 | static void unix_fill_in_inode(struct inode *tmp_inode, | 218 | static 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 | ||
326 | ffirst_retry: | 365 | ffirst_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); |