diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2012-09-18 19:20:32 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:29 -0400 |
commit | 92fc65a74a2be1388d774f7dbf82c9adea1745cf (patch) | |
tree | 262ccb0fcb9edbf09cd2480facaa9135ec511088 /fs/cifs/readdir.c | |
parent | 1feeaac753e0a9b3864740556b7840643642abdb (diff) |
CIFS: Move readdir code to ops struct
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 165 |
1 files changed, 90 insertions, 75 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9e76e3b3289b..b0f4a428398d 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -220,7 +220,8 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
220 | } | 220 | } |
221 | */ | 221 | */ |
222 | 222 | ||
223 | static int initiate_cifs_search(const unsigned int xid, struct file *file) | 223 | static int |
224 | initiate_cifs_search(const unsigned int xid, struct file *file) | ||
224 | { | 225 | { |
225 | __u16 search_flags; | 226 | __u16 search_flags; |
226 | int rc = 0; | 227 | int rc = 0; |
@@ -229,6 +230,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) | |||
229 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 230 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
230 | struct tcon_link *tlink = NULL; | 231 | struct tcon_link *tlink = NULL; |
231 | struct cifs_tcon *tcon; | 232 | struct cifs_tcon *tcon; |
233 | struct TCP_Server_Info *server; | ||
232 | 234 | ||
233 | if (file->private_data == NULL) { | 235 | if (file->private_data == NULL) { |
234 | tlink = cifs_sb_tlink(cifs_sb); | 236 | tlink = cifs_sb_tlink(cifs_sb); |
@@ -248,6 +250,13 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file) | |||
248 | tcon = tlink_tcon(cifsFile->tlink); | 250 | tcon = tlink_tcon(cifsFile->tlink); |
249 | } | 251 | } |
250 | 252 | ||
253 | server = tcon->ses->server; | ||
254 | |||
255 | if (!server->ops->query_dir_first) { | ||
256 | rc = -ENOSYS; | ||
257 | goto error_exit; | ||
258 | } | ||
259 | |||
251 | cifsFile->invalidHandle = true; | 260 | cifsFile->invalidHandle = true; |
252 | cifsFile->srch_inf.endOfSearch = false; | 261 | cifsFile->srch_inf.endOfSearch = false; |
253 | 262 | ||
@@ -278,10 +287,10 @@ ffirst_retry: | |||
278 | if (backup_cred(cifs_sb)) | 287 | if (backup_cred(cifs_sb)) |
279 | search_flags |= CIFS_SEARCH_BACKUP_SEARCH; | 288 | search_flags |= CIFS_SEARCH_BACKUP_SEARCH; |
280 | 289 | ||
281 | rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls, | 290 | rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb, |
282 | &cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf, | 291 | &cifsFile->fid, search_flags, |
283 | cifs_sb->mnt_cifs_flags & | 292 | &cifsFile->srch_inf); |
284 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | 293 | |
285 | if (rc == 0) | 294 | if (rc == 0) |
286 | cifsFile->invalidHandle = false; | 295 | cifsFile->invalidHandle = false; |
287 | /* BB add following call to handle readdir on new NTFS symlink errors | 296 | /* BB add following call to handle readdir on new NTFS symlink errors |
@@ -501,62 +510,67 @@ static int cifs_save_resume_key(const char *current_entry, | |||
501 | return rc; | 510 | return rc; |
502 | } | 511 | } |
503 | 512 | ||
504 | /* find the corresponding entry in the search */ | 513 | /* |
505 | /* Note that the SMB server returns search entries for . and .. which | 514 | * Find the corresponding entry in the search. Note that the SMB server returns |
506 | complicates logic here if we choose to parse for them and we do not | 515 | * search entries for . and .. which complicates logic here if we choose to |
507 | assume that they are located in the findfirst return buffer.*/ | 516 | * parse for them and we do not assume that they are located in the findfirst |
508 | /* We start counting in the buffer with entry 2 and increment for every | 517 | * return buffer. We start counting in the buffer with entry 2 and increment for |
509 | entry (do not increment for . or .. entry) */ | 518 | * every entry (do not increment for . or .. entry). |
510 | static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon, | 519 | */ |
511 | struct file *file, char **ppCurrentEntry, int *num_to_ret) | 520 | static int |
521 | find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, | ||
522 | struct file *file, char **current_entry, int *num_to_ret) | ||
512 | { | 523 | { |
513 | __u16 search_flags; | 524 | __u16 search_flags; |
514 | int rc = 0; | 525 | int rc = 0; |
515 | int pos_in_buf = 0; | 526 | int pos_in_buf = 0; |
516 | loff_t first_entry_in_buffer; | 527 | loff_t first_entry_in_buffer; |
517 | loff_t index_to_find = file->f_pos; | 528 | loff_t index_to_find = file->f_pos; |
518 | struct cifsFileInfo *cifsFile = file->private_data; | 529 | struct cifsFileInfo *cfile = file->private_data; |
519 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 530 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
531 | struct TCP_Server_Info *server = tcon->ses->server; | ||
520 | /* check if index in the buffer */ | 532 | /* check if index in the buffer */ |
521 | 533 | ||
522 | if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || | 534 | if (!server->ops->query_dir_first || !server->ops->query_dir_next) |
523 | (num_to_ret == NULL)) | 535 | return -ENOSYS; |
536 | |||
537 | if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL)) | ||
524 | return -ENOENT; | 538 | return -ENOENT; |
525 | 539 | ||
526 | *ppCurrentEntry = NULL; | 540 | *current_entry = NULL; |
527 | first_entry_in_buffer = | 541 | first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - |
528 | cifsFile->srch_inf.index_of_last_entry - | 542 | cfile->srch_inf.entries_in_buffer; |
529 | cifsFile->srch_inf.entries_in_buffer; | ||
530 | 543 | ||
531 | /* if first entry in buf is zero then is first buffer | 544 | /* |
532 | in search response data which means it is likely . and .. | 545 | * If first entry in buf is zero then is first buffer |
533 | will be in this buffer, although some servers do not return | 546 | * in search response data which means it is likely . and .. |
534 | . and .. for the root of a drive and for those we need | 547 | * will be in this buffer, although some servers do not return |
535 | to start two entries earlier */ | 548 | * . and .. for the root of a drive and for those we need |
549 | * to start two entries earlier. | ||
550 | */ | ||
536 | 551 | ||
537 | dump_cifs_file_struct(file, "In fce "); | 552 | dump_cifs_file_struct(file, "In fce "); |
538 | if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) && | 553 | if (((index_to_find < cfile->srch_inf.index_of_last_entry) && |
539 | is_dir_changed(file)) || | 554 | is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { |
540 | (index_to_find < first_entry_in_buffer)) { | ||
541 | /* close and restart search */ | 555 | /* close and restart search */ |
542 | cFYI(1, "search backing up - close and restart search"); | 556 | cFYI(1, "search backing up - close and restart search"); |
543 | spin_lock(&cifs_file_list_lock); | 557 | spin_lock(&cifs_file_list_lock); |
544 | if (!cifsFile->srch_inf.endOfSearch && | 558 | if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { |
545 | !cifsFile->invalidHandle) { | 559 | cfile->invalidHandle = true; |
546 | cifsFile->invalidHandle = true; | ||
547 | spin_unlock(&cifs_file_list_lock); | 560 | spin_unlock(&cifs_file_list_lock); |
548 | CIFSFindClose(xid, pTcon, cifsFile->fid.netfid); | 561 | if (server->ops->close) |
562 | server->ops->close(xid, tcon, &cfile->fid); | ||
549 | } else | 563 | } else |
550 | spin_unlock(&cifs_file_list_lock); | 564 | spin_unlock(&cifs_file_list_lock); |
551 | if (cifsFile->srch_inf.ntwrk_buf_start) { | 565 | if (cfile->srch_inf.ntwrk_buf_start) { |
552 | cFYI(1, "freeing SMB ff cache buf on search rewind"); | 566 | cFYI(1, "freeing SMB ff cache buf on search rewind"); |
553 | if (cifsFile->srch_inf.smallBuf) | 567 | if (cfile->srch_inf.smallBuf) |
554 | cifs_small_buf_release(cifsFile->srch_inf. | 568 | cifs_small_buf_release(cfile->srch_inf. |
555 | ntwrk_buf_start); | 569 | ntwrk_buf_start); |
556 | else | 570 | else |
557 | cifs_buf_release(cifsFile->srch_inf. | 571 | cifs_buf_release(cfile->srch_inf. |
558 | ntwrk_buf_start); | 572 | ntwrk_buf_start); |
559 | cifsFile->srch_inf.ntwrk_buf_start = NULL; | 573 | cfile->srch_inf.ntwrk_buf_start = NULL; |
560 | } | 574 | } |
561 | rc = initiate_cifs_search(xid, file); | 575 | rc = initiate_cifs_search(xid, file); |
562 | if (rc) { | 576 | if (rc) { |
@@ -565,65 +579,64 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon, | |||
565 | return rc; | 579 | return rc; |
566 | } | 580 | } |
567 | /* FindFirst/Next set last_entry to NULL on malformed reply */ | 581 | /* FindFirst/Next set last_entry to NULL on malformed reply */ |
568 | if (cifsFile->srch_inf.last_entry) | 582 | if (cfile->srch_inf.last_entry) |
569 | cifs_save_resume_key(cifsFile->srch_inf.last_entry, | 583 | cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); |
570 | cifsFile); | ||
571 | } | 584 | } |
572 | 585 | ||
573 | search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; | 586 | search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; |
574 | if (backup_cred(cifs_sb)) | 587 | if (backup_cred(cifs_sb)) |
575 | search_flags |= CIFS_SEARCH_BACKUP_SEARCH; | 588 | search_flags |= CIFS_SEARCH_BACKUP_SEARCH; |
576 | 589 | ||
577 | while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 590 | while ((index_to_find >= cfile->srch_inf.index_of_last_entry) && |
578 | (rc == 0) && !cifsFile->srch_inf.endOfSearch) { | 591 | (rc == 0) && !cfile->srch_inf.endOfSearch) { |
579 | cFYI(1, "calling findnext2"); | 592 | cFYI(1, "calling findnext2"); |
580 | rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid, | 593 | rc = server->ops->query_dir_next(xid, tcon, &cfile->fid, |
581 | search_flags, &cifsFile->srch_inf); | 594 | search_flags, |
595 | &cfile->srch_inf); | ||
582 | /* FindFirst/Next set last_entry to NULL on malformed reply */ | 596 | /* FindFirst/Next set last_entry to NULL on malformed reply */ |
583 | if (cifsFile->srch_inf.last_entry) | 597 | if (cfile->srch_inf.last_entry) |
584 | cifs_save_resume_key(cifsFile->srch_inf.last_entry, | 598 | cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); |
585 | cifsFile); | ||
586 | if (rc) | 599 | if (rc) |
587 | return -ENOENT; | 600 | return -ENOENT; |
588 | } | 601 | } |
589 | if (index_to_find < cifsFile->srch_inf.index_of_last_entry) { | 602 | if (index_to_find < cfile->srch_inf.index_of_last_entry) { |
590 | /* we found the buffer that contains the entry */ | 603 | /* we found the buffer that contains the entry */ |
591 | /* scan and find it */ | 604 | /* scan and find it */ |
592 | int i; | 605 | int i; |
593 | char *current_entry; | 606 | char *cur_ent; |
594 | char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 607 | char *end_of_smb = cfile->srch_inf.ntwrk_buf_start + |
595 | smbCalcSize((struct smb_hdr *) | 608 | server->ops->calc_smb_size( |
596 | cifsFile->srch_inf.ntwrk_buf_start); | 609 | cfile->srch_inf.ntwrk_buf_start); |
597 | 610 | ||
598 | current_entry = cifsFile->srch_inf.srch_entries_start; | 611 | cur_ent = cfile->srch_inf.srch_entries_start; |
599 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 612 | first_entry_in_buffer = cfile->srch_inf.index_of_last_entry |
600 | - cifsFile->srch_inf.entries_in_buffer; | 613 | - cfile->srch_inf.entries_in_buffer; |
601 | pos_in_buf = index_to_find - first_entry_in_buffer; | 614 | pos_in_buf = index_to_find - first_entry_in_buffer; |
602 | cFYI(1, "found entry - pos_in_buf %d", pos_in_buf); | 615 | cFYI(1, "found entry - pos_in_buf %d", pos_in_buf); |
603 | 616 | ||
604 | for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) { | 617 | for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) { |
605 | /* go entry by entry figuring out which is first */ | 618 | /* go entry by entry figuring out which is first */ |
606 | current_entry = nxt_dir_entry(current_entry, end_of_smb, | 619 | cur_ent = nxt_dir_entry(cur_ent, end_of_smb, |
607 | cifsFile->srch_inf.info_level); | 620 | cfile->srch_inf.info_level); |
608 | } | 621 | } |
609 | if ((current_entry == NULL) && (i < pos_in_buf)) { | 622 | if ((cur_ent == NULL) && (i < pos_in_buf)) { |
610 | /* BB fixme - check if we should flag this error */ | 623 | /* BB fixme - check if we should flag this error */ |
611 | cERROR(1, "reached end of buf searching for pos in buf" | 624 | cERROR(1, "reached end of buf searching for pos in buf" |
612 | " %d index to find %lld rc %d", | 625 | " %d index to find %lld rc %d", pos_in_buf, |
613 | pos_in_buf, index_to_find, rc); | 626 | index_to_find, rc); |
614 | } | 627 | } |
615 | rc = 0; | 628 | rc = 0; |
616 | *ppCurrentEntry = current_entry; | 629 | *current_entry = cur_ent; |
617 | } else { | 630 | } else { |
618 | cFYI(1, "index not in buffer - could not findnext into it"); | 631 | cFYI(1, "index not in buffer - could not findnext into it"); |
619 | return 0; | 632 | return 0; |
620 | } | 633 | } |
621 | 634 | ||
622 | if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { | 635 | if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) { |
623 | cFYI(1, "can not return entries pos_in_buf beyond last"); | 636 | cFYI(1, "can not return entries pos_in_buf beyond last"); |
624 | *num_to_ret = 0; | 637 | *num_to_ret = 0; |
625 | } else | 638 | } else |
626 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; | 639 | *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf; |
627 | 640 | ||
628 | return rc; | 641 | return rc; |
629 | } | 642 | } |
@@ -723,7 +736,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
723 | int rc = 0; | 736 | int rc = 0; |
724 | unsigned int xid; | 737 | unsigned int xid; |
725 | int i; | 738 | int i; |
726 | struct cifs_tcon *pTcon; | 739 | struct cifs_tcon *tcon; |
727 | struct cifsFileInfo *cifsFile = NULL; | 740 | struct cifsFileInfo *cifsFile = NULL; |
728 | char *current_entry; | 741 | char *current_entry; |
729 | int num_to_fill = 0; | 742 | int num_to_fill = 0; |
@@ -781,12 +794,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
781 | } | 794 | } |
782 | } /* else { | 795 | } /* else { |
783 | cifsFile->invalidHandle = true; | 796 | cifsFile->invalidHandle = true; |
784 | CIFSFindClose(xid, pTcon, cifsFile->fid.netfid); | 797 | tcon->ses->server->close(xid, tcon, &cifsFile->fid); |
785 | } */ | 798 | } */ |
786 | 799 | ||
787 | pTcon = tlink_tcon(cifsFile->tlink); | 800 | tcon = tlink_tcon(cifsFile->tlink); |
788 | rc = find_cifs_entry(xid, pTcon, file, | 801 | rc = find_cifs_entry(xid, tcon, file, ¤t_entry, |
789 | ¤t_entry, &num_to_fill); | 802 | &num_to_fill); |
790 | if (rc) { | 803 | if (rc) { |
791 | cFYI(1, "fce error %d", rc); | 804 | cFYI(1, "fce error %d", rc); |
792 | goto rddir2_exit; | 805 | goto rddir2_exit; |
@@ -798,7 +811,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
798 | } | 811 | } |
799 | cFYI(1, "loop through %d times filling dir for net buf %p", | 812 | cFYI(1, "loop through %d times filling dir for net buf %p", |
800 | num_to_fill, cifsFile->srch_inf.ntwrk_buf_start); | 813 | num_to_fill, cifsFile->srch_inf.ntwrk_buf_start); |
801 | max_len = smbCalcSize((struct smb_hdr *) | 814 | max_len = tcon->ses->server->ops->calc_smb_size( |
802 | cifsFile->srch_inf.ntwrk_buf_start); | 815 | cifsFile->srch_inf.ntwrk_buf_start); |
803 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 816 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; |
804 | 817 | ||
@@ -815,10 +828,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
815 | num_to_fill, i); | 828 | num_to_fill, i); |
816 | break; | 829 | break; |
817 | } | 830 | } |
818 | /* if buggy server returns . and .. late do | 831 | /* |
819 | we want to check for that here? */ | 832 | * if buggy server returns . and .. late do we want to |
820 | rc = cifs_filldir(current_entry, file, | 833 | * check for that here? |
821 | filldir, direntry, tmp_buf, max_len); | 834 | */ |
835 | rc = cifs_filldir(current_entry, file, filldir, | ||
836 | direntry, tmp_buf, max_len); | ||
822 | if (rc == -EOVERFLOW) { | 837 | if (rc == -EOVERFLOW) { |
823 | rc = 0; | 838 | rc = 0; |
824 | break; | 839 | break; |