diff options
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index d5e591fab475..ef7bb7b50f58 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
102 | return NULL; | 102 | return NULL; |
103 | } | 103 | } |
104 | 104 | ||
105 | if (CIFS_SB(sb)->tcon->nocase) | 105 | if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase) |
106 | dentry->d_op = &cifs_ci_dentry_ops; | 106 | dentry->d_op = &cifs_ci_dentry_ops; |
107 | else | 107 | else |
108 | dentry->d_op = &cifs_dentry_ops; | 108 | dentry->d_op = &cifs_dentry_ops; |
@@ -171,7 +171,7 @@ static void | |||
171 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, | 171 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, |
172 | struct cifs_sb_info *cifs_sb) | 172 | struct cifs_sb_info *cifs_sb) |
173 | { | 173 | { |
174 | int offset = cifs_sb->tcon->ses->server->timeAdj; | 174 | int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj; |
175 | 175 | ||
176 | memset(fattr, 0, sizeof(*fattr)); | 176 | memset(fattr, 0, sizeof(*fattr)); |
177 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, | 177 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, |
@@ -199,7 +199,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
199 | int len; | 199 | int len; |
200 | int oplock = 0; | 200 | int oplock = 0; |
201 | int rc; | 201 | int rc; |
202 | struct cifsTconInfo *ptcon = cifs_sb->tcon; | 202 | struct cifsTconInfo *ptcon = cifs_sb_tcon(cifs_sb); |
203 | char *tmpbuffer; | 203 | char *tmpbuffer; |
204 | 204 | ||
205 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, | 205 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, |
@@ -223,34 +223,35 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
223 | static int initiate_cifs_search(const int xid, struct file *file) | 223 | static int initiate_cifs_search(const int xid, struct file *file) |
224 | { | 224 | { |
225 | int rc = 0; | 225 | int rc = 0; |
226 | char *full_path; | 226 | char *full_path = NULL; |
227 | struct cifsFileInfo *cifsFile; | 227 | struct cifsFileInfo *cifsFile; |
228 | struct cifs_sb_info *cifs_sb; | 228 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
229 | struct tcon_link *tlink; | ||
229 | struct cifsTconInfo *pTcon; | 230 | struct cifsTconInfo *pTcon; |
230 | 231 | ||
231 | if (file->private_data == NULL) { | 232 | tlink = cifs_sb_tlink(cifs_sb); |
233 | if (IS_ERR(tlink)) | ||
234 | return PTR_ERR(tlink); | ||
235 | pTcon = tlink_tcon(tlink); | ||
236 | |||
237 | if (file->private_data == NULL) | ||
232 | file->private_data = | 238 | file->private_data = |
233 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 239 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
240 | if (file->private_data == NULL) { | ||
241 | rc = -ENOMEM; | ||
242 | goto error_exit; | ||
234 | } | 243 | } |
235 | 244 | ||
236 | if (file->private_data == NULL) | ||
237 | return -ENOMEM; | ||
238 | cifsFile = file->private_data; | 245 | cifsFile = file->private_data; |
239 | cifsFile->invalidHandle = true; | 246 | cifsFile->invalidHandle = true; |
240 | cifsFile->srch_inf.endOfSearch = false; | 247 | cifsFile->srch_inf.endOfSearch = false; |
241 | 248 | cifsFile->tlink = cifs_get_tlink(tlink); | |
242 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
243 | if (cifs_sb == NULL) | ||
244 | return -EINVAL; | ||
245 | |||
246 | pTcon = cifs_sb->tcon; | ||
247 | if (pTcon == NULL) | ||
248 | return -EINVAL; | ||
249 | 249 | ||
250 | full_path = build_path_from_dentry(file->f_path.dentry); | 250 | full_path = build_path_from_dentry(file->f_path.dentry); |
251 | 251 | if (full_path == NULL) { | |
252 | if (full_path == NULL) | 252 | rc = -ENOMEM; |
253 | return -ENOMEM; | 253 | goto error_exit; |
254 | } | ||
254 | 255 | ||
255 | cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); | 256 | cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); |
256 | 257 | ||
@@ -283,7 +284,9 @@ ffirst_retry: | |||
283 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | 284 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
284 | goto ffirst_retry; | 285 | goto ffirst_retry; |
285 | } | 286 | } |
287 | error_exit: | ||
286 | kfree(full_path); | 288 | kfree(full_path); |
289 | cifs_put_tlink(tlink); | ||
287 | return rc; | 290 | return rc; |
288 | } | 291 | } |
289 | 292 | ||
@@ -525,14 +528,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
525 | (index_to_find < first_entry_in_buffer)) { | 528 | (index_to_find < first_entry_in_buffer)) { |
526 | /* close and restart search */ | 529 | /* close and restart search */ |
527 | cFYI(1, "search backing up - close and restart search"); | 530 | cFYI(1, "search backing up - close and restart search"); |
528 | write_lock(&GlobalSMBSeslock); | 531 | spin_lock(&cifs_file_list_lock); |
529 | if (!cifsFile->srch_inf.endOfSearch && | 532 | if (!cifsFile->srch_inf.endOfSearch && |
530 | !cifsFile->invalidHandle) { | 533 | !cifsFile->invalidHandle) { |
531 | cifsFile->invalidHandle = true; | 534 | cifsFile->invalidHandle = true; |
532 | write_unlock(&GlobalSMBSeslock); | 535 | spin_unlock(&cifs_file_list_lock); |
533 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 536 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
534 | } else | 537 | } else |
535 | write_unlock(&GlobalSMBSeslock); | 538 | spin_unlock(&cifs_file_list_lock); |
536 | if (cifsFile->srch_inf.ntwrk_buf_start) { | 539 | if (cifsFile->srch_inf.ntwrk_buf_start) { |
537 | cFYI(1, "freeing SMB ff cache buf on search rewind"); | 540 | cFYI(1, "freeing SMB ff cache buf on search rewind"); |
538 | if (cifsFile->srch_inf.smallBuf) | 541 | if (cifsFile->srch_inf.smallBuf) |
@@ -738,6 +741,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
738 | cifs_autodisable_serverino(cifs_sb); | 741 | cifs_autodisable_serverino(cifs_sb); |
739 | } | 742 | } |
740 | 743 | ||
744 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && | ||
745 | CIFSCouldBeMFSymlink(&fattr)) | ||
746 | /* | ||
747 | * trying to get the type and mode can be slow, | ||
748 | * so just call those regular files for now, and mark | ||
749 | * for reval | ||
750 | */ | ||
751 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
752 | |||
741 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 753 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); |
742 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); | 754 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); |
743 | 755 | ||
@@ -777,9 +789,17 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
777 | xid = GetXid(); | 789 | xid = GetXid(); |
778 | 790 | ||
779 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 791 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
780 | pTcon = cifs_sb->tcon; | 792 | |
781 | if (pTcon == NULL) | 793 | /* |
782 | return -EINVAL; | 794 | * Ensure FindFirst doesn't fail before doing filldir() for '.' and |
795 | * '..'. Otherwise we won't be able to notify VFS in case of failure. | ||
796 | */ | ||
797 | if (file->private_data == NULL) { | ||
798 | rc = initiate_cifs_search(xid, file); | ||
799 | cFYI(1, "initiate cifs search rc %d", rc); | ||
800 | if (rc) | ||
801 | goto rddir2_exit; | ||
802 | } | ||
783 | 803 | ||
784 | switch ((int) file->f_pos) { | 804 | switch ((int) file->f_pos) { |
785 | case 0: | 805 | case 0: |
@@ -805,14 +825,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
805 | if after then keep searching till find it */ | 825 | if after then keep searching till find it */ |
806 | 826 | ||
807 | if (file->private_data == NULL) { | 827 | if (file->private_data == NULL) { |
808 | rc = initiate_cifs_search(xid, file); | ||
809 | cFYI(1, "initiate cifs search rc %d", rc); | ||
810 | if (rc) { | ||
811 | FreeXid(xid); | ||
812 | return rc; | ||
813 | } | ||
814 | } | ||
815 | if (file->private_data == NULL) { | ||
816 | rc = -EINVAL; | 828 | rc = -EINVAL; |
817 | FreeXid(xid); | 829 | FreeXid(xid); |
818 | return rc; | 830 | return rc; |
@@ -829,6 +841,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
829 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 841 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
830 | } */ | 842 | } */ |
831 | 843 | ||
844 | pTcon = tlink_tcon(cifsFile->tlink); | ||
832 | rc = find_cifs_entry(xid, pTcon, file, | 845 | rc = find_cifs_entry(xid, pTcon, file, |
833 | ¤t_entry, &num_to_fill); | 846 | ¤t_entry, &num_to_fill); |
834 | if (rc) { | 847 | if (rc) { |