Commit | Line | Data |
---|---|---|
abdb1742 PA |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
3 | * Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de> | |
4 | */ | |
5 | ||
6 | #ifndef _CIFS_DFS_H | |
7 | #define _CIFS_DFS_H | |
8 | ||
9 | #include "cifsglob.h" | |
062a7f0f | 10 | #include "cifsproto.h" |
abdb1742 | 11 | #include "fs_context.h" |
062a7f0f | 12 | #include "dfs_cache.h" |
a1c0d005 | 13 | #include "cifs_unicode.h" |
ce04127c PA |
14 | #include <linux/namei.h> |
15 | ||
16 | #define DFS_INTERLINK(v) \ | |
17 | (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) | |
18 | ||
19 | struct dfs_ref { | |
20 | char *path; | |
21 | char *full_path; | |
22 | struct dfs_cache_tgt_list tl; | |
23 | struct dfs_cache_tgt_iterator *tit; | |
24 | }; | |
25 | ||
26 | struct dfs_ref_walk { | |
27 | struct dfs_ref *ref; | |
28 | struct dfs_ref refs[MAX_NESTED_LINKS]; | |
29 | }; | |
30 | ||
31 | #define ref_walk_start(w) ((w)->refs) | |
32 | #define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1]) | |
33 | #define ref_walk_cur(w) ((w)->ref) | |
34 | #define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w)) | |
35 | ||
36 | #define ref_walk_tit(w) (ref_walk_cur(w)->tit) | |
37 | #define ref_walk_empty(w) (!ref_walk_tit(w)) | |
38 | #define ref_walk_path(w) (ref_walk_cur(w)->path) | |
39 | #define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) | |
40 | #define ref_walk_tl(w) (&ref_walk_cur(w)->tl) | |
41 | ||
42 | static inline struct dfs_ref_walk *ref_walk_alloc(void) | |
43 | { | |
44 | struct dfs_ref_walk *rw; | |
45 | ||
46 | rw = kmalloc(sizeof(*rw), GFP_KERNEL); | |
47 | if (!rw) | |
48 | return ERR_PTR(-ENOMEM); | |
49 | return rw; | |
50 | } | |
51 | ||
52 | static inline void ref_walk_init(struct dfs_ref_walk *rw) | |
53 | { | |
54 | memset(rw, 0, sizeof(*rw)); | |
55 | ref_walk_cur(rw) = ref_walk_start(rw); | |
56 | } | |
57 | ||
58 | static inline void __ref_walk_free(struct dfs_ref *ref) | |
59 | { | |
60 | kfree(ref->path); | |
61 | kfree(ref->full_path); | |
62 | dfs_cache_free_tgts(&ref->tl); | |
63 | memset(ref, 0, sizeof(*ref)); | |
64 | } | |
65 | ||
66 | static inline void ref_walk_free(struct dfs_ref_walk *rw) | |
67 | { | |
68 | struct dfs_ref *ref = ref_walk_start(rw); | |
69 | ||
70 | for (; ref <= ref_walk_end(rw); ref++) | |
71 | __ref_walk_free(ref); | |
72 | kfree(rw); | |
73 | } | |
74 | ||
75 | static inline int ref_walk_advance(struct dfs_ref_walk *rw) | |
76 | { | |
77 | struct dfs_ref *ref = ref_walk_cur(rw) + 1; | |
78 | ||
79 | if (ref > ref_walk_end(rw)) | |
80 | return -ELOOP; | |
81 | __ref_walk_free(ref); | |
82 | ref_walk_cur(rw) = ref; | |
83 | return 0; | |
84 | } | |
85 | ||
86 | static inline struct dfs_cache_tgt_iterator * | |
87 | ref_walk_next_tgt(struct dfs_ref_walk *rw) | |
88 | { | |
89 | struct dfs_cache_tgt_iterator *tit; | |
90 | struct dfs_ref *ref = ref_walk_cur(rw); | |
91 | ||
92 | if (!ref->tit) | |
93 | tit = dfs_cache_get_tgt_iterator(&ref->tl); | |
94 | else | |
95 | tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit); | |
96 | ref->tit = tit; | |
97 | return tit; | |
98 | } | |
99 | ||
100 | static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw, | |
101 | struct dfs_info3_param *tgt) | |
102 | { | |
103 | zfree_dfs_info_param(tgt); | |
104 | return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1, | |
105 | ref_walk_tit(rw), tgt); | |
106 | } | |
107 | ||
108 | static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw) | |
109 | { | |
110 | return dfs_cache_get_nr_tgts(ref_walk_tl(rw)); | |
111 | } | |
112 | ||
113 | static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) | |
114 | { | |
115 | dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1, | |
116 | ref_walk_tit(rw)); | |
117 | } | |
abdb1742 PA |
118 | |
119 | int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref, | |
120 | struct smb3_fs_context *ctx); | |
a1c0d005 | 121 | int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs); |
abdb1742 | 122 | |
a1c0d005 PA |
123 | static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path) |
124 | { | |
125 | return dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb)); | |
126 | } | |
127 | ||
128 | static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path, | |
129 | struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl) | |
130 | { | |
b56bce50 | 131 | struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; |
a1c0d005 | 132 | struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; |
062a7f0f | 133 | struct cifs_ses *rses = ctx->dfs_root_ses ?: mnt_ctx->ses; |
a1c0d005 | 134 | |
062a7f0f | 135 | return dfs_cache_find(mnt_ctx->xid, rses, cifs_sb->local_nls, |
a1c0d005 PA |
136 | cifs_remap(cifs_sb), path, ref, tl); |
137 | } | |
abdb1742 | 138 | |
062a7f0f PA |
139 | /* |
140 | * cifs_get_smb_ses() already guarantees an active reference of | |
141 | * @ses->dfs_root_ses when a new session is created, so we need to put extra | |
142 | * references of all DFS root sessions that were used across the mount process | |
143 | * in dfs_mount_share(). | |
144 | */ | |
145 | static inline void dfs_put_root_smb_sessions(struct cifs_mount_ctx *mnt_ctx) | |
396935de | 146 | { |
062a7f0f PA |
147 | const struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; |
148 | struct cifs_ses *ses = ctx->dfs_root_ses; | |
149 | struct cifs_ses *cur; | |
150 | ||
151 | if (!ses) | |
152 | return; | |
396935de | 153 | |
062a7f0f PA |
154 | for (cur = ses; cur; cur = cur->dfs_root_ses) { |
155 | if (cur->dfs_root_ses) | |
156 | cifs_put_smb_ses(cur->dfs_root_ses); | |
396935de | 157 | } |
062a7f0f | 158 | cifs_put_smb_ses(ses); |
396935de PA |
159 | } |
160 | ||
abdb1742 | 161 | #endif /* _CIFS_DFS_H */ |