diff options
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 111 |
1 files changed, 54 insertions, 57 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index d5e591fab475..6751e745bbc6 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -79,7 +79,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
79 | cFYI(1, "For %s", name->name); | 79 | cFYI(1, "For %s", name->name); |
80 | 80 | ||
81 | if (parent->d_op && parent->d_op->d_hash) | 81 | if (parent->d_op && parent->d_op->d_hash) |
82 | parent->d_op->d_hash(parent, name); | 82 | parent->d_op->d_hash(parent, parent->d_inode, name); |
83 | else | 83 | else |
84 | name->hash = full_name_hash(name->name, name->len); | 84 | name->hash = full_name_hash(name->name, name->len); |
85 | 85 | ||
@@ -102,11 +102,6 @@ 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) | ||
106 | dentry->d_op = &cifs_ci_dentry_ops; | ||
107 | else | ||
108 | dentry->d_op = &cifs_dentry_ops; | ||
109 | |||
110 | alias = d_materialise_unique(dentry, inode); | 105 | alias = d_materialise_unique(dentry, inode); |
111 | if (alias != NULL) { | 106 | if (alias != NULL) { |
112 | dput(dentry); | 107 | dput(dentry); |
@@ -160,6 +155,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, | |||
160 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); | 155 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); |
161 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 156 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
162 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 157 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
158 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
163 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 159 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
164 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); | 160 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
165 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | 161 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
@@ -171,7 +167,7 @@ static void | |||
171 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, | 167 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, |
172 | struct cifs_sb_info *cifs_sb) | 168 | struct cifs_sb_info *cifs_sb) |
173 | { | 169 | { |
174 | int offset = cifs_sb->tcon->ses->server->timeAdj; | 170 | int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj; |
175 | 171 | ||
176 | memset(fattr, 0, sizeof(*fattr)); | 172 | memset(fattr, 0, sizeof(*fattr)); |
177 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, | 173 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, |
@@ -199,7 +195,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
199 | int len; | 195 | int len; |
200 | int oplock = 0; | 196 | int oplock = 0; |
201 | int rc; | 197 | int rc; |
202 | struct cifsTconInfo *ptcon = cifs_sb->tcon; | 198 | struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb); |
203 | char *tmpbuffer; | 199 | char *tmpbuffer; |
204 | 200 | ||
205 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, | 201 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, |
@@ -223,34 +219,38 @@ 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) | 219 | static int initiate_cifs_search(const int xid, struct file *file) |
224 | { | 220 | { |
225 | int rc = 0; | 221 | int rc = 0; |
226 | char *full_path; | 222 | char *full_path = NULL; |
227 | struct cifsFileInfo *cifsFile; | 223 | struct cifsFileInfo *cifsFile; |
228 | struct cifs_sb_info *cifs_sb; | 224 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
229 | struct cifsTconInfo *pTcon; | 225 | struct tcon_link *tlink = NULL; |
226 | struct cifs_tcon *pTcon; | ||
230 | 227 | ||
231 | if (file->private_data == NULL) { | 228 | if (file->private_data == NULL) { |
232 | file->private_data = | 229 | tlink = cifs_sb_tlink(cifs_sb); |
233 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 230 | if (IS_ERR(tlink)) |
231 | return PTR_ERR(tlink); | ||
232 | |||
233 | cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
234 | if (cifsFile == NULL) { | ||
235 | rc = -ENOMEM; | ||
236 | goto error_exit; | ||
237 | } | ||
238 | file->private_data = cifsFile; | ||
239 | cifsFile->tlink = cifs_get_tlink(tlink); | ||
240 | pTcon = tlink_tcon(tlink); | ||
241 | } else { | ||
242 | cifsFile = file->private_data; | ||
243 | pTcon = tlink_tcon(cifsFile->tlink); | ||
234 | } | 244 | } |
235 | 245 | ||
236 | if (file->private_data == NULL) | ||
237 | return -ENOMEM; | ||
238 | 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 | ||
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 | |||
250 | full_path = build_path_from_dentry(file->f_path.dentry); | 249 | full_path = build_path_from_dentry(file->f_path.dentry); |
251 | 250 | if (full_path == NULL) { | |
252 | if (full_path == NULL) | 251 | rc = -ENOMEM; |
253 | return -ENOMEM; | 252 | goto error_exit; |
253 | } | ||
254 | 254 | ||
255 | cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); | 255 | cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); |
256 | 256 | ||
@@ -283,7 +283,9 @@ ffirst_retry: | |||
283 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | 283 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
284 | goto ffirst_retry; | 284 | goto ffirst_retry; |
285 | } | 285 | } |
286 | error_exit: | ||
286 | kfree(full_path); | 287 | kfree(full_path); |
288 | cifs_put_tlink(tlink); | ||
287 | return rc; | 289 | return rc; |
288 | } | 290 | } |
289 | 291 | ||
@@ -494,7 +496,7 @@ static int cifs_save_resume_key(const char *current_entry, | |||
494 | assume that they are located in the findfirst return buffer.*/ | 496 | assume that they are located in the findfirst return buffer.*/ |
495 | /* We start counting in the buffer with entry 2 and increment for every | 497 | /* We start counting in the buffer with entry 2 and increment for every |
496 | entry (do not increment for . or .. entry) */ | 498 | entry (do not increment for . or .. entry) */ |
497 | static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | 499 | static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, |
498 | struct file *file, char **ppCurrentEntry, int *num_to_ret) | 500 | struct file *file, char **ppCurrentEntry, int *num_to_ret) |
499 | { | 501 | { |
500 | int rc = 0; | 502 | int rc = 0; |
@@ -525,14 +527,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
525 | (index_to_find < first_entry_in_buffer)) { | 527 | (index_to_find < first_entry_in_buffer)) { |
526 | /* close and restart search */ | 528 | /* close and restart search */ |
527 | cFYI(1, "search backing up - close and restart search"); | 529 | cFYI(1, "search backing up - close and restart search"); |
528 | write_lock(&GlobalSMBSeslock); | 530 | spin_lock(&cifs_file_list_lock); |
529 | if (!cifsFile->srch_inf.endOfSearch && | 531 | if (!cifsFile->srch_inf.endOfSearch && |
530 | !cifsFile->invalidHandle) { | 532 | !cifsFile->invalidHandle) { |
531 | cifsFile->invalidHandle = true; | 533 | cifsFile->invalidHandle = true; |
532 | write_unlock(&GlobalSMBSeslock); | 534 | spin_unlock(&cifs_file_list_lock); |
533 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 535 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
534 | } else | 536 | } else |
535 | write_unlock(&GlobalSMBSeslock); | 537 | spin_unlock(&cifs_file_list_lock); |
536 | if (cifsFile->srch_inf.ntwrk_buf_start) { | 538 | if (cifsFile->srch_inf.ntwrk_buf_start) { |
537 | cFYI(1, "freeing SMB ff cache buf on search rewind"); | 539 | cFYI(1, "freeing SMB ff cache buf on search rewind"); |
538 | if (cifsFile->srch_inf.smallBuf) | 540 | if (cifsFile->srch_inf.smallBuf) |
@@ -738,24 +740,21 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
738 | cifs_autodisable_serverino(cifs_sb); | 740 | cifs_autodisable_serverino(cifs_sb); |
739 | } | 741 | } |
740 | 742 | ||
743 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && | ||
744 | CIFSCouldBeMFSymlink(&fattr)) | ||
745 | /* | ||
746 | * trying to get the type and mode can be slow, | ||
747 | * so just call those regular files for now, and mark | ||
748 | * for reval | ||
749 | */ | ||
750 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
751 | |||
741 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 752 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); |
742 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); | 753 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); |
743 | 754 | ||
744 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, | 755 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, |
745 | ino, fattr.cf_dtype); | 756 | ino, fattr.cf_dtype); |
746 | 757 | ||
747 | /* | ||
748 | * we can not return filldir errors to the caller since they are | ||
749 | * "normal" when the stat blocksize is too small - we return remapped | ||
750 | * error instead | ||
751 | * | ||
752 | * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above | ||
753 | * case already. Why should we be clobbering other errors from it? | ||
754 | */ | ||
755 | if (rc) { | ||
756 | cFYI(1, "filldir rc = %d", rc); | ||
757 | rc = -EOVERFLOW; | ||
758 | } | ||
759 | dput(tmp_dentry); | 758 | dput(tmp_dentry); |
760 | return rc; | 759 | return rc; |
761 | } | 760 | } |
@@ -765,8 +764,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
765 | { | 764 | { |
766 | int rc = 0; | 765 | int rc = 0; |
767 | int xid, i; | 766 | int xid, i; |
768 | struct cifs_sb_info *cifs_sb; | 767 | struct cifs_tcon *pTcon; |
769 | struct cifsTconInfo *pTcon; | ||
770 | struct cifsFileInfo *cifsFile = NULL; | 768 | struct cifsFileInfo *cifsFile = NULL; |
771 | char *current_entry; | 769 | char *current_entry; |
772 | int num_to_fill = 0; | 770 | int num_to_fill = 0; |
@@ -776,10 +774,16 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
776 | 774 | ||
777 | xid = GetXid(); | 775 | xid = GetXid(); |
778 | 776 | ||
779 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 777 | /* |
780 | pTcon = cifs_sb->tcon; | 778 | * Ensure FindFirst doesn't fail before doing filldir() for '.' and |
781 | if (pTcon == NULL) | 779 | * '..'. Otherwise we won't be able to notify VFS in case of failure. |
782 | return -EINVAL; | 780 | */ |
781 | if (file->private_data == NULL) { | ||
782 | rc = initiate_cifs_search(xid, file); | ||
783 | cFYI(1, "initiate cifs search rc %d", rc); | ||
784 | if (rc) | ||
785 | goto rddir2_exit; | ||
786 | } | ||
783 | 787 | ||
784 | switch ((int) file->f_pos) { | 788 | switch ((int) file->f_pos) { |
785 | case 0: | 789 | case 0: |
@@ -805,14 +809,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
805 | if after then keep searching till find it */ | 809 | if after then keep searching till find it */ |
806 | 810 | ||
807 | if (file->private_data == NULL) { | 811 | 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; | 812 | rc = -EINVAL; |
817 | FreeXid(xid); | 813 | FreeXid(xid); |
818 | return rc; | 814 | return rc; |
@@ -829,6 +825,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
829 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 825 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
830 | } */ | 826 | } */ |
831 | 827 | ||
828 | pTcon = tlink_tcon(cifsFile->tlink); | ||
832 | rc = find_cifs_entry(xid, pTcon, file, | 829 | rc = find_cifs_entry(xid, pTcon, file, |
833 | ¤t_entry, &num_to_fill); | 830 | ¤t_entry, &num_to_fill); |
834 | if (rc) { | 831 | if (rc) { |