diff options
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 120 |
1 files changed, 86 insertions, 34 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index f8bea395ec9e..22557716f9af 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; |
@@ -314,15 +353,16 @@ static int initiate_cifs_search(const int xid, struct file *file) | |||
314 | return -EINVAL; | 353 | return -EINVAL; |
315 | 354 | ||
316 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); | 355 | down(&file->f_dentry->d_sb->s_vfs_rename_sem); |
317 | full_path = build_wildcard_path_from_dentry(file->f_dentry); | 356 | full_path = build_path_from_dentry(file->f_dentry); |
318 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); | 357 | up(&file->f_dentry->d_sb->s_vfs_rename_sem); |
319 | 358 | ||
320 | if(full_path == NULL) { | 359 | if(full_path == NULL) { |
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 | ||
365 | ffirst_retry: | ||
326 | /* test for Unix extensions */ | 366 | /* test for Unix extensions */ |
327 | if (pTcon->ses->capabilities & CAP_UNIX) { | 367 | if (pTcon->ses->capabilities & CAP_UNIX) { |
328 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; | 368 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; |
@@ -332,10 +372,16 @@ static int initiate_cifs_search(const int xid, struct file *file) | |||
332 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; | 372 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; |
333 | } | 373 | } |
334 | 374 | ||
335 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | 375 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, |
336 | &cifsFile->netfid, &cifsFile->srch_inf); | 376 | &cifsFile->netfid, &cifsFile->srch_inf, |
377 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
337 | if(rc == 0) | 378 | if(rc == 0) |
338 | cifsFile->invalidHandle = FALSE; | 379 | cifsFile->invalidHandle = FALSE; |
380 | if((rc == -EOPNOTSUPP) && | ||
381 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { | ||
382 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | ||
383 | goto ffirst_retry; | ||
384 | } | ||
339 | kfree(full_path); | 385 | kfree(full_path); |
340 | return rc; | 386 | return rc; |
341 | } | 387 | } |
@@ -363,10 +409,15 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) | |||
363 | cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); | 409 | cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); |
364 | /* validate that new_entry is not past end of SMB */ | 410 | /* validate that new_entry is not past end of SMB */ |
365 | if(new_entry >= end_of_smb) { | 411 | if(new_entry >= end_of_smb) { |
366 | cFYI(1,("search entry %p began after end of SMB %p old entry %p", | 412 | cERROR(1, |
367 | new_entry,end_of_smb,old_entry)); | 413 | ("search entry %p began after end of SMB %p old entry %p", |
414 | new_entry, end_of_smb, old_entry)); | ||
368 | return NULL; | 415 | return NULL; |
369 | } else | 416 | } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { |
417 | cERROR(1,("search entry %p extends after end of SMB %p", | ||
418 | new_entry, end_of_smb)); | ||
419 | return NULL; | ||
420 | } else | ||
370 | return new_entry; | 421 | return new_entry; |
371 | 422 | ||
372 | } | 423 | } |
@@ -594,7 +645,12 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
594 | if(unicode) { | 645 | if(unicode) { |
595 | /* BB fixme - test with long names */ | 646 | /* BB fixme - test with long names */ |
596 | /* Note converted filename can be longer than in unicode */ | 647 | /* Note converted filename can be longer than in unicode */ |
597 | pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt); | 648 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
649 | pqst->len = cifs_convertUCSpath((char *)pqst->name, | ||
650 | (__le16 *)filename, len/2, nlt); | ||
651 | else | ||
652 | pqst->len = cifs_strfromUCS_le((char *)pqst->name, | ||
653 | (wchar_t *)filename,len/2,nlt); | ||
598 | } else { | 654 | } else { |
599 | pqst->name = filename; | 655 | pqst->name = filename; |
600 | pqst->len = len; | 656 | pqst->len = len; |
@@ -654,10 +710,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
654 | insert_inode_hash(tmp_inode); | 710 | insert_inode_hash(tmp_inode); |
655 | } | 711 | } |
656 | 712 | ||
713 | /* we pass in rc below, indicating whether it is a new inode, | ||
714 | so we can figure out whether to invalidate the inode cached | ||
715 | data if the file has changed */ | ||
657 | if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { | 716 | if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { |
658 | unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type); | 717 | unix_fill_in_inode(tmp_inode, |
718 | (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); | ||
659 | } else { | 719 | } else { |
660 | fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type); | 720 | fill_in_inode(tmp_inode, |
721 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); | ||
661 | } | 722 | } |
662 | 723 | ||
663 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); | 724 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); |
@@ -823,7 +884,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
823 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 884 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + |
824 | smbCalcSize((struct smb_hdr *) | 885 | smbCalcSize((struct smb_hdr *) |
825 | cifsFile->srch_inf.ntwrk_buf_start); | 886 | cifsFile->srch_inf.ntwrk_buf_start); |
826 | tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL); | 887 | /* To be safe - for UCS to UTF-8 with strings loaded |
888 | with the rare long characters alloc more to account for | ||
889 | such multibyte target UTF-8 characters. cifs_unicode.c, | ||
890 | which actually does the conversion, has the same limit */ | ||
891 | tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); | ||
827 | for(i=0;(i<num_to_fill) && (rc == 0);i++) { | 892 | for(i=0;(i<num_to_fill) && (rc == 0);i++) { |
828 | if(current_entry == NULL) { | 893 | if(current_entry == NULL) { |
829 | /* evaluate whether this case is an error */ | 894 | /* evaluate whether this case is an error */ |
@@ -832,19 +897,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
832 | break; | 897 | break; |
833 | } | 898 | } |
834 | 899 | ||
835 | /* BB FIXME - need to enable the below code BB */ | ||
836 | |||
837 | /* if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || | ||
838 | (cifsFile->srch_inf.info_level != | ||
839 | something that supports server inodes)) { | ||
840 | create dentry | ||
841 | create inode | ||
842 | fill in inode new_inode (getting local i_ino) | ||
843 | } | ||
844 | also create local inode for performance reasons (so we | ||
845 | have a cache of inode metadata) unless this new mount | ||
846 | parm says otherwise */ | ||
847 | |||
848 | rc = cifs_filldir(current_entry, file, | 900 | rc = cifs_filldir(current_entry, file, |
849 | filldir, direntry,tmp_buf); | 901 | filldir, direntry,tmp_buf); |
850 | file->f_pos++; | 902 | file->f_pos++; |