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) { |
