| .. | .. |
|---|
| 31 | 31 | #include "nterr.h" |
|---|
| 32 | 32 | #include "cifs_unicode.h" |
|---|
| 33 | 33 | #include "smb2pdu.h" |
|---|
| 34 | +#include "cifsfs.h" |
|---|
| 35 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
|---|
| 36 | +#include "dns_resolve.h" |
|---|
| 37 | +#endif |
|---|
| 34 | 38 | |
|---|
| 35 | 39 | extern mempool_t *cifs_sm_req_poolp; |
|---|
| 36 | 40 | extern mempool_t *cifs_req_poolp; |
|---|
| .. | .. |
|---|
| 99 | 103 | kfree(buf_to_free->serverOS); |
|---|
| 100 | 104 | kfree(buf_to_free->serverDomain); |
|---|
| 101 | 105 | kfree(buf_to_free->serverNOS); |
|---|
| 102 | | - kzfree(buf_to_free->password); |
|---|
| 106 | + kfree_sensitive(buf_to_free->password); |
|---|
| 103 | 107 | kfree(buf_to_free->user_name); |
|---|
| 104 | 108 | kfree(buf_to_free->domainName); |
|---|
| 105 | | - kzfree(buf_to_free->auth_key.response); |
|---|
| 109 | + kfree_sensitive(buf_to_free->auth_key.response); |
|---|
| 106 | 110 | kfree(buf_to_free->iface_list); |
|---|
| 107 | | - kzfree(buf_to_free); |
|---|
| 111 | + kfree_sensitive(buf_to_free); |
|---|
| 108 | 112 | } |
|---|
| 109 | 113 | |
|---|
| 110 | 114 | struct cifs_tcon * |
|---|
| 111 | 115 | tconInfoAlloc(void) |
|---|
| 112 | 116 | { |
|---|
| 113 | 117 | struct cifs_tcon *ret_buf; |
|---|
| 114 | | - ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL); |
|---|
| 115 | | - if (ret_buf) { |
|---|
| 116 | | - atomic_inc(&tconInfoAllocCount); |
|---|
| 117 | | - ret_buf->tidStatus = CifsNew; |
|---|
| 118 | | - ++ret_buf->tc_count; |
|---|
| 119 | | - INIT_LIST_HEAD(&ret_buf->openFileList); |
|---|
| 120 | | - INIT_LIST_HEAD(&ret_buf->tcon_list); |
|---|
| 121 | | - spin_lock_init(&ret_buf->open_file_lock); |
|---|
| 122 | | - mutex_init(&ret_buf->crfid.fid_mutex); |
|---|
| 123 | | - ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid), |
|---|
| 124 | | - GFP_KERNEL); |
|---|
| 125 | | - spin_lock_init(&ret_buf->stat_lock); |
|---|
| 118 | + |
|---|
| 119 | + ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); |
|---|
| 120 | + if (!ret_buf) |
|---|
| 121 | + return NULL; |
|---|
| 122 | + ret_buf->crfid.fid = kzalloc(sizeof(*ret_buf->crfid.fid), GFP_KERNEL); |
|---|
| 123 | + if (!ret_buf->crfid.fid) { |
|---|
| 124 | + kfree(ret_buf); |
|---|
| 125 | + return NULL; |
|---|
| 126 | 126 | } |
|---|
| 127 | + |
|---|
| 128 | + atomic_inc(&tconInfoAllocCount); |
|---|
| 129 | + ret_buf->tidStatus = CifsNew; |
|---|
| 130 | + ++ret_buf->tc_count; |
|---|
| 131 | + INIT_LIST_HEAD(&ret_buf->openFileList); |
|---|
| 132 | + INIT_LIST_HEAD(&ret_buf->tcon_list); |
|---|
| 133 | + spin_lock_init(&ret_buf->open_file_lock); |
|---|
| 134 | + mutex_init(&ret_buf->crfid.fid_mutex); |
|---|
| 135 | + spin_lock_init(&ret_buf->stat_lock); |
|---|
| 136 | + atomic_set(&ret_buf->num_local_opens, 0); |
|---|
| 137 | + atomic_set(&ret_buf->num_remote_opens, 0); |
|---|
| 138 | + |
|---|
| 127 | 139 | return ret_buf; |
|---|
| 128 | 140 | } |
|---|
| 129 | 141 | |
|---|
| .. | .. |
|---|
| 136 | 148 | } |
|---|
| 137 | 149 | atomic_dec(&tconInfoAllocCount); |
|---|
| 138 | 150 | kfree(buf_to_free->nativeFileSystem); |
|---|
| 139 | | - kzfree(buf_to_free->password); |
|---|
| 151 | + kfree_sensitive(buf_to_free->password); |
|---|
| 140 | 152 | kfree(buf_to_free->crfid.fid); |
|---|
| 153 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
|---|
| 154 | + kfree(buf_to_free->dfs_path); |
|---|
| 155 | +#endif |
|---|
| 141 | 156 | kfree(buf_to_free); |
|---|
| 142 | 157 | } |
|---|
| 143 | 158 | |
|---|
| .. | .. |
|---|
| 409 | 424 | |
|---|
| 410 | 425 | if (data_offset > |
|---|
| 411 | 426 | len - sizeof(struct file_notify_information)) { |
|---|
| 412 | | - cifs_dbg(FYI, "invalid data_offset %u\n", |
|---|
| 427 | + cifs_dbg(FYI, "Invalid data_offset %u\n", |
|---|
| 413 | 428 | data_offset); |
|---|
| 414 | 429 | return true; |
|---|
| 415 | 430 | } |
|---|
| .. | .. |
|---|
| 437 | 452 | large dirty files cached on the client */ |
|---|
| 438 | 453 | if ((NT_STATUS_INVALID_HANDLE) == |
|---|
| 439 | 454 | le32_to_cpu(pSMB->hdr.Status.CifsError)) { |
|---|
| 440 | | - cifs_dbg(FYI, "invalid handle on oplock break\n"); |
|---|
| 455 | + cifs_dbg(FYI, "Invalid handle on oplock break\n"); |
|---|
| 441 | 456 | return true; |
|---|
| 442 | 457 | } else if (ERRbadfid == |
|---|
| 443 | 458 | le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { |
|---|
| .. | .. |
|---|
| 511 | 526 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) |
|---|
| 512 | 527 | { |
|---|
| 513 | 528 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
|---|
| 529 | + struct cifs_tcon *tcon = NULL; |
|---|
| 530 | + |
|---|
| 531 | + if (cifs_sb->master_tlink) |
|---|
| 532 | + tcon = cifs_sb_master_tcon(cifs_sb); |
|---|
| 533 | + |
|---|
| 514 | 534 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
|---|
| 515 | 535 | cifs_sb->mnt_cifs_serverino_autodisabled = true; |
|---|
| 516 | | - cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s. This server doesn't seem to support them properly. Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n", |
|---|
| 517 | | - cifs_sb_master_tcon(cifs_sb)->treeName); |
|---|
| 536 | + cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n", |
|---|
| 537 | + tcon ? tcon->treeName : "new server"); |
|---|
| 538 | + cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS)\n"); |
|---|
| 539 | + cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n"); |
|---|
| 540 | + |
|---|
| 518 | 541 | } |
|---|
| 519 | 542 | } |
|---|
| 520 | 543 | |
|---|
| .. | .. |
|---|
| 741 | 764 | goto parse_DFS_referrals_exit; |
|---|
| 742 | 765 | } |
|---|
| 743 | 766 | |
|---|
| 767 | + node->ttl = le32_to_cpu(ref->TimeToLive); |
|---|
| 768 | + |
|---|
| 744 | 769 | ref++; |
|---|
| 745 | 770 | } |
|---|
| 746 | 771 | |
|---|
| .. | .. |
|---|
| 758 | 783 | { |
|---|
| 759 | 784 | struct cifs_aio_ctx *ctx; |
|---|
| 760 | 785 | |
|---|
| 786 | + /* |
|---|
| 787 | + * Must use kzalloc to initialize ctx->bv to NULL and ctx->direct_io |
|---|
| 788 | + * to false so that we know when we have to unreference pages within |
|---|
| 789 | + * cifs_aio_ctx_release() |
|---|
| 790 | + */ |
|---|
| 761 | 791 | ctx = kzalloc(sizeof(struct cifs_aio_ctx), GFP_KERNEL); |
|---|
| 762 | 792 | if (!ctx) |
|---|
| 763 | 793 | return NULL; |
|---|
| .. | .. |
|---|
| 776 | 806 | struct cifs_aio_ctx, refcount); |
|---|
| 777 | 807 | |
|---|
| 778 | 808 | cifsFileInfo_put(ctx->cfile); |
|---|
| 779 | | - kvfree(ctx->bv); |
|---|
| 809 | + |
|---|
| 810 | + /* |
|---|
| 811 | + * ctx->bv is only set if setup_aio_ctx_iter() was call successfuly |
|---|
| 812 | + * which means that iov_iter_get_pages() was a success and thus that |
|---|
| 813 | + * we have taken reference on pages. |
|---|
| 814 | + */ |
|---|
| 815 | + if (ctx->bv) { |
|---|
| 816 | + unsigned i; |
|---|
| 817 | + |
|---|
| 818 | + for (i = 0; i < ctx->npages; i++) { |
|---|
| 819 | + if (ctx->should_dirty) |
|---|
| 820 | + set_page_dirty(ctx->bv[i].bv_page); |
|---|
| 821 | + put_page(ctx->bv[i].bv_page); |
|---|
| 822 | + } |
|---|
| 823 | + kvfree(ctx->bv); |
|---|
| 824 | + } |
|---|
| 825 | + |
|---|
| 780 | 826 | kfree(ctx); |
|---|
| 781 | 827 | } |
|---|
| 782 | 828 | |
|---|
| .. | .. |
|---|
| 797 | 843 | struct page **pages = NULL; |
|---|
| 798 | 844 | struct bio_vec *bv = NULL; |
|---|
| 799 | 845 | |
|---|
| 800 | | - if (iter->type & ITER_KVEC) { |
|---|
| 801 | | - memcpy(&ctx->iter, iter, sizeof(struct iov_iter)); |
|---|
| 846 | + if (iov_iter_is_kvec(iter)) { |
|---|
| 847 | + memcpy(&ctx->iter, iter, sizeof(*iter)); |
|---|
| 802 | 848 | ctx->len = count; |
|---|
| 803 | 849 | iov_iter_advance(iter, count); |
|---|
| 804 | 850 | return 0; |
|---|
| 805 | 851 | } |
|---|
| 806 | 852 | |
|---|
| 807 | | - if (max_pages * sizeof(struct bio_vec) <= CIFS_AIO_KMALLOC_LIMIT) |
|---|
| 808 | | - bv = kmalloc_array(max_pages, sizeof(struct bio_vec), |
|---|
| 809 | | - GFP_KERNEL); |
|---|
| 853 | + if (array_size(max_pages, sizeof(*bv)) <= CIFS_AIO_KMALLOC_LIMIT) |
|---|
| 854 | + bv = kmalloc_array(max_pages, sizeof(*bv), GFP_KERNEL); |
|---|
| 810 | 855 | |
|---|
| 811 | 856 | if (!bv) { |
|---|
| 812 | | - bv = vmalloc(array_size(max_pages, sizeof(struct bio_vec))); |
|---|
| 857 | + bv = vmalloc(array_size(max_pages, sizeof(*bv))); |
|---|
| 813 | 858 | if (!bv) |
|---|
| 814 | 859 | return -ENOMEM; |
|---|
| 815 | 860 | } |
|---|
| 816 | 861 | |
|---|
| 817 | | - if (max_pages * sizeof(struct page *) <= CIFS_AIO_KMALLOC_LIMIT) |
|---|
| 818 | | - pages = kmalloc_array(max_pages, sizeof(struct page *), |
|---|
| 819 | | - GFP_KERNEL); |
|---|
| 862 | + if (array_size(max_pages, sizeof(*pages)) <= CIFS_AIO_KMALLOC_LIMIT) |
|---|
| 863 | + pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL); |
|---|
| 820 | 864 | |
|---|
| 821 | 865 | if (!pages) { |
|---|
| 822 | | - pages = vmalloc(array_size(max_pages, sizeof(struct page *))); |
|---|
| 866 | + pages = vmalloc(array_size(max_pages, sizeof(*pages))); |
|---|
| 823 | 867 | if (!pages) { |
|---|
| 824 | 868 | kvfree(bv); |
|---|
| 825 | 869 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 831 | 875 | while (count && npages < max_pages) { |
|---|
| 832 | 876 | rc = iov_iter_get_pages(iter, pages, count, max_pages, &start); |
|---|
| 833 | 877 | if (rc < 0) { |
|---|
| 834 | | - cifs_dbg(VFS, "couldn't get user pages (rc=%zd)\n", rc); |
|---|
| 878 | + cifs_dbg(VFS, "Couldn't get user pages (rc=%zd)\n", rc); |
|---|
| 835 | 879 | break; |
|---|
| 836 | 880 | } |
|---|
| 837 | 881 | |
|---|
| .. | .. |
|---|
| 868 | 912 | ctx->bv = bv; |
|---|
| 869 | 913 | ctx->len = saved_len - count; |
|---|
| 870 | 914 | ctx->npages = npages; |
|---|
| 871 | | - iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len); |
|---|
| 915 | + iov_iter_bvec(&ctx->iter, rw, ctx->bv, npages, ctx->len); |
|---|
| 872 | 916 | return 0; |
|---|
| 873 | 917 | } |
|---|
| 874 | 918 | |
|---|
| .. | .. |
|---|
| 890 | 934 | |
|---|
| 891 | 935 | *shash = crypto_alloc_shash(name, 0, 0); |
|---|
| 892 | 936 | if (IS_ERR(*shash)) { |
|---|
| 893 | | - cifs_dbg(VFS, "could not allocate crypto %s\n", name); |
|---|
| 937 | + cifs_dbg(VFS, "Could not allocate crypto %s\n", name); |
|---|
| 894 | 938 | rc = PTR_ERR(*shash); |
|---|
| 895 | 939 | *shash = NULL; |
|---|
| 896 | 940 | *sdesc = NULL; |
|---|
| .. | .. |
|---|
| 907 | 951 | } |
|---|
| 908 | 952 | |
|---|
| 909 | 953 | (*sdesc)->shash.tfm = *shash; |
|---|
| 910 | | - (*sdesc)->shash.flags = 0x0; |
|---|
| 911 | 954 | return 0; |
|---|
| 912 | 955 | } |
|---|
| 913 | 956 | |
|---|
| .. | .. |
|---|
| 931 | 974 | * Input: rqst - a smb_rqst, page - a page index for rqst |
|---|
| 932 | 975 | * Output: *len - the length for this page, *offset - the offset for this page |
|---|
| 933 | 976 | */ |
|---|
| 934 | | -void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, |
|---|
| 935 | | - unsigned int *len, unsigned int *offset) |
|---|
| 977 | +void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page, |
|---|
| 978 | + unsigned int *len, unsigned int *offset) |
|---|
| 936 | 979 | { |
|---|
| 937 | 980 | *len = rqst->rq_pagesz; |
|---|
| 938 | 981 | *offset = (page == 0) ? rqst->rq_offset : 0; |
|---|
| .. | .. |
|---|
| 942 | 985 | else if (page == 0) |
|---|
| 943 | 986 | *len = rqst->rq_pagesz - rqst->rq_offset; |
|---|
| 944 | 987 | } |
|---|
| 988 | + |
|---|
| 989 | +void extract_unc_hostname(const char *unc, const char **h, size_t *len) |
|---|
| 990 | +{ |
|---|
| 991 | + const char *end; |
|---|
| 992 | + |
|---|
| 993 | + /* skip initial slashes */ |
|---|
| 994 | + while (*unc && (*unc == '\\' || *unc == '/')) |
|---|
| 995 | + unc++; |
|---|
| 996 | + |
|---|
| 997 | + end = unc; |
|---|
| 998 | + |
|---|
| 999 | + while (*end && !(*end == '\\' || *end == '/')) |
|---|
| 1000 | + end++; |
|---|
| 1001 | + |
|---|
| 1002 | + *h = unc; |
|---|
| 1003 | + *len = end - unc; |
|---|
| 1004 | +} |
|---|
| 1005 | + |
|---|
| 1006 | +/** |
|---|
| 1007 | + * copy_path_name - copy src path to dst, possibly truncating |
|---|
| 1008 | + * |
|---|
| 1009 | + * returns number of bytes written (including trailing nul) |
|---|
| 1010 | + */ |
|---|
| 1011 | +int copy_path_name(char *dst, const char *src) |
|---|
| 1012 | +{ |
|---|
| 1013 | + int name_len; |
|---|
| 1014 | + |
|---|
| 1015 | + /* |
|---|
| 1016 | + * PATH_MAX includes nul, so if strlen(src) >= PATH_MAX it |
|---|
| 1017 | + * will truncate and strlen(dst) will be PATH_MAX-1 |
|---|
| 1018 | + */ |
|---|
| 1019 | + name_len = strscpy(dst, src, PATH_MAX); |
|---|
| 1020 | + if (WARN_ON_ONCE(name_len < 0)) |
|---|
| 1021 | + name_len = PATH_MAX-1; |
|---|
| 1022 | + |
|---|
| 1023 | + /* we count the trailing nul */ |
|---|
| 1024 | + name_len++; |
|---|
| 1025 | + return name_len; |
|---|
| 1026 | +} |
|---|
| 1027 | + |
|---|
| 1028 | +struct super_cb_data { |
|---|
| 1029 | + void *data; |
|---|
| 1030 | + struct super_block *sb; |
|---|
| 1031 | +}; |
|---|
| 1032 | + |
|---|
| 1033 | +static void tcp_super_cb(struct super_block *sb, void *arg) |
|---|
| 1034 | +{ |
|---|
| 1035 | + struct super_cb_data *sd = arg; |
|---|
| 1036 | + struct TCP_Server_Info *server = sd->data; |
|---|
| 1037 | + struct cifs_sb_info *cifs_sb; |
|---|
| 1038 | + struct cifs_tcon *tcon; |
|---|
| 1039 | + |
|---|
| 1040 | + if (sd->sb) |
|---|
| 1041 | + return; |
|---|
| 1042 | + |
|---|
| 1043 | + cifs_sb = CIFS_SB(sb); |
|---|
| 1044 | + tcon = cifs_sb_master_tcon(cifs_sb); |
|---|
| 1045 | + if (tcon->ses->server == server) |
|---|
| 1046 | + sd->sb = sb; |
|---|
| 1047 | +} |
|---|
| 1048 | + |
|---|
| 1049 | +static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void *), |
|---|
| 1050 | + void *data) |
|---|
| 1051 | +{ |
|---|
| 1052 | + struct super_cb_data sd = { |
|---|
| 1053 | + .data = data, |
|---|
| 1054 | + .sb = NULL, |
|---|
| 1055 | + }; |
|---|
| 1056 | + struct file_system_type **fs_type = (struct file_system_type *[]) { |
|---|
| 1057 | + &cifs_fs_type, &smb3_fs_type, NULL, |
|---|
| 1058 | + }; |
|---|
| 1059 | + |
|---|
| 1060 | + for (; *fs_type; fs_type++) { |
|---|
| 1061 | + iterate_supers_type(*fs_type, f, &sd); |
|---|
| 1062 | + if (sd.sb) { |
|---|
| 1063 | + /* |
|---|
| 1064 | + * Grab an active reference in order to prevent automounts (DFS links) |
|---|
| 1065 | + * of expiring and then freeing up our cifs superblock pointer while |
|---|
| 1066 | + * we're doing failover. |
|---|
| 1067 | + */ |
|---|
| 1068 | + cifs_sb_active(sd.sb); |
|---|
| 1069 | + return sd.sb; |
|---|
| 1070 | + } |
|---|
| 1071 | + } |
|---|
| 1072 | + return ERR_PTR(-EINVAL); |
|---|
| 1073 | +} |
|---|
| 1074 | + |
|---|
| 1075 | +static void __cifs_put_super(struct super_block *sb) |
|---|
| 1076 | +{ |
|---|
| 1077 | + if (!IS_ERR_OR_NULL(sb)) |
|---|
| 1078 | + cifs_sb_deactive(sb); |
|---|
| 1079 | +} |
|---|
| 1080 | + |
|---|
| 1081 | +struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server) |
|---|
| 1082 | +{ |
|---|
| 1083 | + return __cifs_get_super(tcp_super_cb, server); |
|---|
| 1084 | +} |
|---|
| 1085 | + |
|---|
| 1086 | +void cifs_put_tcp_super(struct super_block *sb) |
|---|
| 1087 | +{ |
|---|
| 1088 | + __cifs_put_super(sb); |
|---|
| 1089 | +} |
|---|
| 1090 | + |
|---|
| 1091 | +#ifdef CONFIG_CIFS_DFS_UPCALL |
|---|
| 1092 | +int match_target_ip(struct TCP_Server_Info *server, |
|---|
| 1093 | + const char *share, size_t share_len, |
|---|
| 1094 | + bool *result) |
|---|
| 1095 | +{ |
|---|
| 1096 | + int rc; |
|---|
| 1097 | + char *target, *tip = NULL; |
|---|
| 1098 | + struct sockaddr tipaddr; |
|---|
| 1099 | + |
|---|
| 1100 | + *result = false; |
|---|
| 1101 | + |
|---|
| 1102 | + target = kzalloc(share_len + 3, GFP_KERNEL); |
|---|
| 1103 | + if (!target) { |
|---|
| 1104 | + rc = -ENOMEM; |
|---|
| 1105 | + goto out; |
|---|
| 1106 | + } |
|---|
| 1107 | + |
|---|
| 1108 | + scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share); |
|---|
| 1109 | + |
|---|
| 1110 | + cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2); |
|---|
| 1111 | + |
|---|
| 1112 | + rc = dns_resolve_server_name_to_ip(target, &tip); |
|---|
| 1113 | + if (rc < 0) |
|---|
| 1114 | + goto out; |
|---|
| 1115 | + |
|---|
| 1116 | + cifs_dbg(FYI, "%s: target ip: %s\n", __func__, tip); |
|---|
| 1117 | + |
|---|
| 1118 | + if (!cifs_convert_address(&tipaddr, tip, strlen(tip))) { |
|---|
| 1119 | + cifs_dbg(VFS, "%s: failed to convert target ip address\n", |
|---|
| 1120 | + __func__); |
|---|
| 1121 | + rc = -EINVAL; |
|---|
| 1122 | + goto out; |
|---|
| 1123 | + } |
|---|
| 1124 | + |
|---|
| 1125 | + *result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, |
|---|
| 1126 | + &tipaddr); |
|---|
| 1127 | + cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result); |
|---|
| 1128 | + rc = 0; |
|---|
| 1129 | + |
|---|
| 1130 | +out: |
|---|
| 1131 | + kfree(target); |
|---|
| 1132 | + kfree(tip); |
|---|
| 1133 | + |
|---|
| 1134 | + return rc; |
|---|
| 1135 | +} |
|---|
| 1136 | + |
|---|
| 1137 | +static void tcon_super_cb(struct super_block *sb, void *arg) |
|---|
| 1138 | +{ |
|---|
| 1139 | + struct super_cb_data *sd = arg; |
|---|
| 1140 | + struct cifs_tcon *tcon = sd->data; |
|---|
| 1141 | + struct cifs_sb_info *cifs_sb; |
|---|
| 1142 | + |
|---|
| 1143 | + if (sd->sb) |
|---|
| 1144 | + return; |
|---|
| 1145 | + |
|---|
| 1146 | + cifs_sb = CIFS_SB(sb); |
|---|
| 1147 | + if (tcon->dfs_path && cifs_sb->origin_fullpath && |
|---|
| 1148 | + !strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath)) |
|---|
| 1149 | + sd->sb = sb; |
|---|
| 1150 | +} |
|---|
| 1151 | + |
|---|
| 1152 | +static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon) |
|---|
| 1153 | +{ |
|---|
| 1154 | + return __cifs_get_super(tcon_super_cb, tcon); |
|---|
| 1155 | +} |
|---|
| 1156 | + |
|---|
| 1157 | +static inline void cifs_put_tcon_super(struct super_block *sb) |
|---|
| 1158 | +{ |
|---|
| 1159 | + __cifs_put_super(sb); |
|---|
| 1160 | +} |
|---|
| 1161 | +#else |
|---|
| 1162 | +static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon) |
|---|
| 1163 | +{ |
|---|
| 1164 | + return ERR_PTR(-EOPNOTSUPP); |
|---|
| 1165 | +} |
|---|
| 1166 | + |
|---|
| 1167 | +static inline void cifs_put_tcon_super(struct super_block *sb) |
|---|
| 1168 | +{ |
|---|
| 1169 | +} |
|---|
| 1170 | +#endif |
|---|
| 1171 | + |
|---|
| 1172 | +int update_super_prepath(struct cifs_tcon *tcon, char *prefix) |
|---|
| 1173 | +{ |
|---|
| 1174 | + struct super_block *sb; |
|---|
| 1175 | + struct cifs_sb_info *cifs_sb; |
|---|
| 1176 | + int rc = 0; |
|---|
| 1177 | + |
|---|
| 1178 | + sb = cifs_get_tcon_super(tcon); |
|---|
| 1179 | + if (IS_ERR(sb)) |
|---|
| 1180 | + return PTR_ERR(sb); |
|---|
| 1181 | + |
|---|
| 1182 | + cifs_sb = CIFS_SB(sb); |
|---|
| 1183 | + |
|---|
| 1184 | + kfree(cifs_sb->prepath); |
|---|
| 1185 | + |
|---|
| 1186 | + if (prefix && *prefix) { |
|---|
| 1187 | + cifs_sb->prepath = kstrndup(prefix, strlen(prefix), GFP_ATOMIC); |
|---|
| 1188 | + if (!cifs_sb->prepath) { |
|---|
| 1189 | + rc = -ENOMEM; |
|---|
| 1190 | + goto out; |
|---|
| 1191 | + } |
|---|
| 1192 | + |
|---|
| 1193 | + convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); |
|---|
| 1194 | + } else |
|---|
| 1195 | + cifs_sb->prepath = NULL; |
|---|
| 1196 | + |
|---|
| 1197 | + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
|---|
| 1198 | + |
|---|
| 1199 | +out: |
|---|
| 1200 | + cifs_put_tcon_super(sb); |
|---|
| 1201 | + return rc; |
|---|
| 1202 | +} |
|---|