aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-05-27 09:34:43 -0400
committerPavel Shilovsky <pshilovsky@samba.org>2012-07-24 13:55:07 -0400
commit1208ef1f76540b621f80e6130c4fb7bed8ece360 (patch)
tree65edaf646b06ba93ffe2a0ee4a98e7b9378bb59f /fs/cifs
parent2503a0dba989486c59523a947a1dcb50ad90fee9 (diff)
CIFS: Move query inode info 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')
-rw-r--r--fs/cifs/cifsglob.h9
-rw-r--r--fs/cifs/cifsproto.h14
-rw-r--r--fs/cifs/cifssmb.c11
-rw-r--r--fs/cifs/inode.c93
-rw-r--r--fs/cifs/smb1ops.c50
5 files changed, 107 insertions, 70 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index f711d666e3d..2b1234599e7 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -163,6 +163,7 @@ struct cifsFileInfo;
163struct cifs_ses; 163struct cifs_ses;
164struct cifs_tcon; 164struct cifs_tcon;
165struct dfs_info3_param; 165struct dfs_info3_param;
166struct cifs_fattr;
166 167
167struct smb_version_operations { 168struct 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
223struct smb_version_values { 232struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b9967adeaa9..8e93de01c79 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
140extern int cifs_get_file_info(struct file *filp); 140extern int cifs_get_file_info(struct file *filp);
141extern int cifs_get_inode_info(struct inode **pinode, 141extern 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);
146extern int cifs_get_file_info_unix(struct file *filp); 144extern int cifs_get_file_info_unix(struct file *filp);
147extern int cifs_get_inode_info_unix(struct inode **pinode, 145extern 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);
378extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, 376extern 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
383extern int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, 381extern 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 84a53380e12..fe30bb5dd2d 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
4560int 4560int
4561CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, 4561CIFSGetSrvInodeNumber(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 af902864ac0..df071fb2567 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
603int cifs_get_inode_info(struct inode **pinode, 603int
604 const unsigned char *full_path, FILE_ALL_INFO *pfindData, 604cifs_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
743cgii_exit: 724cgii_exit:
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 43f3881ad3b..fa210010358 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
444static int
445cifs_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
470static int
471cifs_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
444struct smb_version_operations smb1_operations = { 492struct 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
473struct smb_version_values smb1_values = { 523struct smb_version_values smb1_values = {