aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r--fs/cifs/readdir.c120
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
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;
@@ -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
365ffirst_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++;