diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 9 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 14 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 11 | ||||
-rw-r--r-- | fs/cifs/inode.c | 93 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 50 |
5 files changed, 107 insertions, 70 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f711d666e3db..2b1234599e72 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -163,6 +163,7 @@ struct cifsFileInfo; | |||
163 | struct cifs_ses; | 163 | struct cifs_ses; |
164 | struct cifs_tcon; | 164 | struct cifs_tcon; |
165 | struct dfs_info3_param; | 165 | struct dfs_info3_param; |
166 | struct cifs_fattr; | ||
166 | 167 | ||
167 | struct smb_version_operations { | 168 | struct smb_version_operations { |
168 | int (*send_cancel)(struct TCP_Server_Info *, void *, | 169 | int (*send_cancel)(struct TCP_Server_Info *, void *, |
@@ -218,6 +219,14 @@ struct smb_version_operations { | |||
218 | /* check if a path is accessible or not */ | 219 | /* check if a path is accessible or not */ |
219 | int (*is_path_accessible)(const unsigned int, struct cifs_tcon *, | 220 | int (*is_path_accessible)(const unsigned int, struct cifs_tcon *, |
220 | struct cifs_sb_info *, const char *); | 221 | struct cifs_sb_info *, const char *); |
222 | /* query path data from the server */ | ||
223 | int (*query_path_info)(const unsigned int, struct cifs_tcon *, | ||
224 | struct cifs_sb_info *, const char *, | ||
225 | FILE_ALL_INFO *, bool *); | ||
226 | /* get server index number */ | ||
227 | int (*get_srv_inum)(const unsigned int, struct cifs_tcon *, | ||
228 | struct cifs_sb_info *, const char *, | ||
229 | u64 *uniqueid, FILE_ALL_INFO *); | ||
221 | }; | 230 | }; |
222 | 231 | ||
223 | struct smb_version_values { | 232 | struct smb_version_values { |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b9967adeaa9e..8e93de01c79d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -138,11 +138,9 @@ extern struct inode *cifs_iget(struct super_block *sb, | |||
138 | struct cifs_fattr *fattr); | 138 | struct cifs_fattr *fattr); |
139 | 139 | ||
140 | extern int cifs_get_file_info(struct file *filp); | 140 | extern int cifs_get_file_info(struct file *filp); |
141 | extern int cifs_get_inode_info(struct inode **pinode, | 141 | extern int cifs_get_inode_info(struct inode **inode, const char *full_path, |
142 | const unsigned char *search_path, | 142 | FILE_ALL_INFO *data, struct super_block *sb, |
143 | FILE_ALL_INFO *pfile_info, | 143 | int xid, const __u16 *fid); |
144 | struct super_block *sb, unsigned int xid, | ||
145 | const __u16 *pfid); | ||
146 | extern int cifs_get_file_info_unix(struct file *filp); | 144 | extern int cifs_get_file_info_unix(struct file *filp); |
147 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 145 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
148 | const unsigned char *search_path, | 146 | const unsigned char *search_path, |
@@ -376,9 +374,9 @@ extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
376 | unsigned int *nbytes, struct kvec *iov, const int nvec, | 374 | unsigned int *nbytes, struct kvec *iov, const int nvec, |
377 | const int long_op); | 375 | const int long_op); |
378 | extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, | 376 | extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, |
379 | const unsigned char *searchName, __u64 *inode_number, | 377 | const char *search_name, __u64 *inode_number, |
380 | const struct nls_table *nls_codepage, | 378 | const struct nls_table *nls_codepage, |
381 | int remap_special_chars); | 379 | int remap); |
382 | 380 | ||
383 | extern int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, | 381 | extern int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, |
384 | const __u16 netfid, const __u8 lock_type, | 382 | const __u16 netfid, const __u8 lock_type, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 84a53380e124..fe30bb5dd2d8 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -4559,8 +4559,7 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon, | |||
4559 | 4559 | ||
4560 | int | 4560 | int |
4561 | CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, | 4561 | CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, |
4562 | const unsigned char *searchName, | 4562 | const char *search_name, __u64 *inode_number, |
4563 | __u64 *inode_number, | ||
4564 | const struct nls_table *nls_codepage, int remap) | 4563 | const struct nls_table *nls_codepage, int remap) |
4565 | { | 4564 | { |
4566 | int rc = 0; | 4565 | int rc = 0; |
@@ -4569,7 +4568,7 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, | |||
4569 | int name_len, bytes_returned; | 4568 | int name_len, bytes_returned; |
4570 | __u16 params, byte_count; | 4569 | __u16 params, byte_count; |
4571 | 4570 | ||
4572 | cFYI(1, "In GetSrvInodeNum for %s", searchName); | 4571 | cFYI(1, "In GetSrvInodeNum for %s", search_name); |
4573 | if (tcon == NULL) | 4572 | if (tcon == NULL) |
4574 | return -ENODEV; | 4573 | return -ENODEV; |
4575 | 4574 | ||
@@ -4582,14 +4581,14 @@ GetInodeNumberRetry: | |||
4582 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 4581 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
4583 | name_len = | 4582 | name_len = |
4584 | cifsConvertToUTF16((__le16 *) pSMB->FileName, | 4583 | cifsConvertToUTF16((__le16 *) pSMB->FileName, |
4585 | searchName, PATH_MAX, nls_codepage, | 4584 | search_name, PATH_MAX, nls_codepage, |
4586 | remap); | 4585 | remap); |
4587 | name_len++; /* trailing null */ | 4586 | name_len++; /* trailing null */ |
4588 | name_len *= 2; | 4587 | name_len *= 2; |
4589 | } else { /* BB improve the check for buffer overruns BB */ | 4588 | } else { /* BB improve the check for buffer overruns BB */ |
4590 | name_len = strnlen(searchName, PATH_MAX); | 4589 | name_len = strnlen(search_name, PATH_MAX); |
4591 | name_len++; /* trailing null */ | 4590 | name_len++; /* trailing null */ |
4592 | strncpy(pSMB->FileName, searchName, name_len); | 4591 | strncpy(pSMB->FileName, search_name, name_len); |
4593 | } | 4592 | } |
4594 | 4593 | ||
4595 | params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; | 4594 | params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index af902864ac03..df071fb2567f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -600,61 +600,54 @@ cgfi_exit: | |||
600 | return rc; | 600 | return rc; |
601 | } | 601 | } |
602 | 602 | ||
603 | int cifs_get_inode_info(struct inode **pinode, | 603 | int |
604 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, | 604 | cifs_get_inode_info(struct inode **inode, const char *full_path, |
605 | struct super_block *sb, unsigned int xid, const __u16 *pfid) | 605 | FILE_ALL_INFO *data, struct super_block *sb, int xid, |
606 | const __u16 *fid) | ||
606 | { | 607 | { |
607 | int rc = 0, tmprc; | 608 | int rc = 0, tmprc; |
608 | struct cifs_tcon *pTcon; | 609 | struct cifs_tcon *tcon; |
610 | struct TCP_Server_Info *server; | ||
609 | struct tcon_link *tlink; | 611 | struct tcon_link *tlink; |
610 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 612 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
611 | char *buf = NULL; | 613 | char *buf = NULL; |
612 | bool adjustTZ = false; | 614 | bool adjust_tz = false; |
613 | struct cifs_fattr fattr; | 615 | struct cifs_fattr fattr; |
614 | 616 | ||
615 | tlink = cifs_sb_tlink(cifs_sb); | 617 | tlink = cifs_sb_tlink(cifs_sb); |
616 | if (IS_ERR(tlink)) | 618 | if (IS_ERR(tlink)) |
617 | return PTR_ERR(tlink); | 619 | return PTR_ERR(tlink); |
618 | pTcon = tlink_tcon(tlink); | 620 | tcon = tlink_tcon(tlink); |
621 | server = tcon->ses->server; | ||
619 | 622 | ||
620 | cFYI(1, "Getting info on %s", full_path); | 623 | cFYI(1, "Getting info on %s", full_path); |
621 | 624 | ||
622 | if ((pfindData == NULL) && (*pinode != NULL)) { | 625 | if ((data == NULL) && (*inode != NULL)) { |
623 | if (CIFS_I(*pinode)->clientCanCacheRead) { | 626 | if (CIFS_I(*inode)->clientCanCacheRead) { |
624 | cFYI(1, "No need to revalidate cached inode sizes"); | 627 | cFYI(1, "No need to revalidate cached inode sizes"); |
625 | goto cgii_exit; | 628 | goto cgii_exit; |
626 | } | 629 | } |
627 | } | 630 | } |
628 | 631 | ||
629 | /* if file info not passed in then get it from server */ | 632 | /* if inode info is not passed, get it from server */ |
630 | if (pfindData == NULL) { | 633 | if (data == NULL) { |
634 | if (!server->ops->query_path_info) { | ||
635 | rc = -ENOSYS; | ||
636 | goto cgii_exit; | ||
637 | } | ||
631 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 638 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
632 | if (buf == NULL) { | 639 | if (buf == NULL) { |
633 | rc = -ENOMEM; | 640 | rc = -ENOMEM; |
634 | goto cgii_exit; | 641 | goto cgii_exit; |
635 | } | 642 | } |
636 | pfindData = (FILE_ALL_INFO *)buf; | 643 | data = (FILE_ALL_INFO *)buf; |
637 | 644 | rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, | |
638 | /* could do find first instead but this returns more info */ | 645 | data, &adjust_tz); |
639 | rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, | ||
640 | 0 /* not legacy */, | ||
641 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
642 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
643 | /* BB optimize code so we do not make the above call | ||
644 | when server claims no NT SMB support and the above call | ||
645 | failed at least once - set flag in tcon or mount */ | ||
646 | if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { | ||
647 | rc = SMBQueryInformation(xid, pTcon, full_path, | ||
648 | pfindData, cifs_sb->local_nls, | ||
649 | cifs_sb->mnt_cifs_flags & | ||
650 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
651 | adjustTZ = true; | ||
652 | } | ||
653 | } | 646 | } |
654 | 647 | ||
655 | if (!rc) { | 648 | if (!rc) { |
656 | cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData, | 649 | cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb, |
657 | cifs_sb, adjustTZ); | 650 | adjust_tz); |
658 | } else if (rc == -EREMOTE) { | 651 | } else if (rc == -EREMOTE) { |
659 | cifs_create_dfs_fattr(&fattr, sb); | 652 | cifs_create_dfs_fattr(&fattr, sb); |
660 | rc = 0; | 653 | rc = 0; |
@@ -668,28 +661,17 @@ int cifs_get_inode_info(struct inode **pinode, | |||
668 | * Is an i_ino of zero legal? Can we use that to check if the server | 661 | * Is an i_ino of zero legal? Can we use that to check if the server |
669 | * supports returning inode numbers? Are there other sanity checks we | 662 | * supports returning inode numbers? Are there other sanity checks we |
670 | * can use to ensure that the server is really filling in that field? | 663 | * can use to ensure that the server is really filling in that field? |
671 | * | ||
672 | * We can not use the IndexNumber field by default from Windows or | ||
673 | * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA | ||
674 | * CIFS spec claims that this value is unique within the scope of a | ||
675 | * share, and the windows docs hint that it's actually unique | ||
676 | * per-machine. | ||
677 | * | ||
678 | * There may be higher info levels that work but are there Windows | ||
679 | * server or network appliances for which IndexNumber field is not | ||
680 | * guaranteed unique? | ||
681 | */ | 664 | */ |
682 | if (*pinode == NULL) { | 665 | if (*inode == NULL) { |
683 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 666 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
684 | int rc1 = 0; | 667 | if (server->ops->get_srv_inum) |
685 | 668 | tmprc = server->ops->get_srv_inum(xid, tcon, | |
686 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 669 | cifs_sb, full_path, &fattr.cf_uniqueid, |
687 | full_path, &fattr.cf_uniqueid, | 670 | data); |
688 | cifs_sb->local_nls, | 671 | else |
689 | cifs_sb->mnt_cifs_flags & | 672 | tmprc = -ENOSYS; |
690 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 673 | if (tmprc || !fattr.cf_uniqueid) { |
691 | if (rc1 || !fattr.cf_uniqueid) { | 674 | cFYI(1, "GetSrvInodeNum rc %d", tmprc); |
692 | cFYI(1, "GetSrvInodeNum rc %d", rc1); | ||
693 | fattr.cf_uniqueid = iunique(sb, ROOT_I); | 675 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
694 | cifs_autodisable_serverino(cifs_sb); | 676 | cifs_autodisable_serverino(cifs_sb); |
695 | } | 677 | } |
@@ -697,7 +679,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
697 | fattr.cf_uniqueid = iunique(sb, ROOT_I); | 679 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
698 | } | 680 | } |
699 | } else { | 681 | } else { |
700 | fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid; | 682 | fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; |
701 | } | 683 | } |
702 | 684 | ||
703 | /* query for SFU type info if supported and needed */ | 685 | /* query for SFU type info if supported and needed */ |
@@ -711,8 +693,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
711 | #ifdef CONFIG_CIFS_ACL | 693 | #ifdef CONFIG_CIFS_ACL |
712 | /* fill in 0777 bits from ACL */ | 694 | /* fill in 0777 bits from ACL */ |
713 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 695 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
714 | rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, | 696 | rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid); |
715 | pfid); | ||
716 | if (rc) { | 697 | if (rc) { |
717 | cFYI(1, "%s: Getting ACL failed with error: %d", | 698 | cFYI(1, "%s: Getting ACL failed with error: %d", |
718 | __func__, rc); | 699 | __func__, rc); |
@@ -732,12 +713,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
732 | cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); | 713 | cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); |
733 | } | 714 | } |
734 | 715 | ||
735 | if (!*pinode) { | 716 | if (!*inode) { |
736 | *pinode = cifs_iget(sb, &fattr); | 717 | *inode = cifs_iget(sb, &fattr); |
737 | if (!*pinode) | 718 | if (!*inode) |
738 | rc = -ENOMEM; | 719 | rc = -ENOMEM; |
739 | } else { | 720 | } else { |
740 | cifs_fattr_to_inode(*pinode, &fattr); | 721 | cifs_fattr_to_inode(*inode, &fattr); |
741 | } | 722 | } |
742 | 723 | ||
743 | cgii_exit: | 724 | cgii_exit: |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 43f3881ad3b8..fa210010358d 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -441,6 +441,54 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, | |||
441 | return rc; | 441 | return rc; |
442 | } | 442 | } |
443 | 443 | ||
444 | static int | ||
445 | cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | ||
446 | struct cifs_sb_info *cifs_sb, const char *full_path, | ||
447 | FILE_ALL_INFO *data, bool *adjustTZ) | ||
448 | { | ||
449 | int rc; | ||
450 | |||
451 | /* could do find first instead but this returns more info */ | ||
452 | rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */, | ||
453 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
454 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
455 | /* | ||
456 | * BB optimize code so we do not make the above call when server claims | ||
457 | * no NT SMB support and the above call failed at least once - set flag | ||
458 | * in tcon or mount. | ||
459 | */ | ||
460 | if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { | ||
461 | rc = SMBQueryInformation(xid, tcon, full_path, data, | ||
462 | cifs_sb->local_nls, | ||
463 | cifs_sb->mnt_cifs_flags & | ||
464 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
465 | *adjustTZ = true; | ||
466 | } | ||
467 | return rc; | ||
468 | } | ||
469 | |||
470 | static int | ||
471 | cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon, | ||
472 | struct cifs_sb_info *cifs_sb, const char *full_path, | ||
473 | u64 *uniqueid, FILE_ALL_INFO *data) | ||
474 | { | ||
475 | /* | ||
476 | * We can not use the IndexNumber field by default from Windows or | ||
477 | * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA | ||
478 | * CIFS spec claims that this value is unique within the scope of a | ||
479 | * share, and the windows docs hint that it's actually unique | ||
480 | * per-machine. | ||
481 | * | ||
482 | * There may be higher info levels that work but are there Windows | ||
483 | * server or network appliances for which IndexNumber field is not | ||
484 | * guaranteed unique? | ||
485 | */ | ||
486 | return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid, | ||
487 | cifs_sb->local_nls, | ||
488 | cifs_sb->mnt_cifs_flags & | ||
489 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
490 | } | ||
491 | |||
444 | struct smb_version_operations smb1_operations = { | 492 | struct smb_version_operations smb1_operations = { |
445 | .send_cancel = send_nt_cancel, | 493 | .send_cancel = send_nt_cancel, |
446 | .compare_fids = cifs_compare_fids, | 494 | .compare_fids = cifs_compare_fids, |
@@ -468,6 +516,8 @@ struct smb_version_operations smb1_operations = { | |||
468 | .get_dfs_refer = CIFSGetDFSRefer, | 516 | .get_dfs_refer = CIFSGetDFSRefer, |
469 | .qfs_tcon = cifs_qfs_tcon, | 517 | .qfs_tcon = cifs_qfs_tcon, |
470 | .is_path_accessible = cifs_is_path_accessible, | 518 | .is_path_accessible = cifs_is_path_accessible, |
519 | .query_path_info = cifs_query_path_info, | ||
520 | .get_srv_inum = cifs_get_srv_inum, | ||
471 | }; | 521 | }; |
472 | 522 | ||
473 | struct smb_version_values smb1_values = { | 523 | struct smb_version_values smb1_values = { |