FILE
dfs.h
File preview with syntax highlighting.
linux-6.19.14/fs/smb/client/dfs.h
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" 10#include "cifsproto.h" 11#include "fs_context.h" 12#include "dfs_cache.h" 13#include "cifs_unicode.h" 14#include <linux/namei.h> 15#include <linux/errno.h> 16 17#define DFS_INTERLINK(v) \ 18 (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) 19 20struct dfs_ref { 21 char *path; 22 char *full_path; 23 struct cifs_ses *ses; 24 struct dfs_cache_tgt_list tl; 25 struct dfs_cache_tgt_iterator *tit; 26}; 27 28struct dfs_ref_walk { 29 struct cifs_mount_ctx *mnt_ctx; 30 struct dfs_ref *ref; 31 struct dfs_ref refs[MAX_NESTED_LINKS]; 32}; 33 34#define ref_walk_start(w) ((w)->refs) 35#define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1]) 36#define ref_walk_cur(w) ((w)->ref) 37#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w)) 38 39#define ref_walk_tit(w) (ref_walk_cur(w)->tit) 40#define ref_walk_path(w) (ref_walk_cur(w)->path) 41#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) 42#define ref_walk_tl(w) (&ref_walk_cur(w)->tl) 43#define ref_walk_ses(w) (ref_walk_cur(w)->ses) 44 45static inline struct dfs_ref_walk *ref_walk_alloc(void) 46{ 47 struct dfs_ref_walk *rw; 48 49 rw = kmalloc(sizeof(*rw), GFP_KERNEL); 50 if (!rw) 51 return ERR_PTR(-ENOMEM); 52 return rw; 53} 54 55static inline void ref_walk_init(struct dfs_ref_walk *rw, 56 struct cifs_mount_ctx *mnt_ctx) 57{ 58 memset(rw, 0, sizeof(*rw)); 59 rw->mnt_ctx = mnt_ctx; 60 ref_walk_cur(rw) = ref_walk_start(rw); 61} 62 63static inline void __ref_walk_free(struct dfs_ref *ref) 64{ 65 kfree(ref->path); 66 kfree(ref->full_path); 67 dfs_cache_free_tgts(&ref->tl); 68 if (ref->ses) 69 cifs_put_smb_ses(ref->ses); 70 memset(ref, 0, sizeof(*ref)); 71} 72 73static inline void ref_walk_free(struct dfs_ref_walk *rw) 74{ 75 struct dfs_ref *ref; 76 77 if (!rw) 78 return; 79 80 for (ref = ref_walk_start(rw); ref <= ref_walk_end(rw); ref++) 81 __ref_walk_free(ref); 82 kfree(rw); 83} 84 85static inline int ref_walk_advance(struct dfs_ref_walk *rw) 86{ 87 struct dfs_ref *ref = ref_walk_cur(rw) + 1; 88 89 if (ref > ref_walk_end(rw)) 90 return -ELOOP; 91 __ref_walk_free(ref); 92 ref_walk_cur(rw) = ref; 93 return 0; 94} 95 96static inline struct dfs_cache_tgt_iterator * 97ref_walk_next_tgt(struct dfs_ref_walk *rw) 98{ 99 struct dfs_ref *ref = ref_walk_cur(rw); 100 struct dfs_cache_tgt_iterator *tit; 101 102 if (IS_ERR(ref->tit)) 103 return NULL; 104 105 if (!ref->tit) 106 tit = dfs_cache_get_tgt_iterator(&ref->tl); 107 else 108 tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit); 109 110 if (!tit) { 111 ref->tit = ERR_PTR(-ENOENT); 112 return NULL; 113 } 114 ref->tit = tit; 115 return ref->tit; 116} 117 118static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw, 119 struct dfs_info3_param *tgt) 120{ 121 zfree_dfs_info_param(tgt); 122 return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1, 123 ref_walk_tit(rw), tgt); 124} 125 126static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) 127{ 128 dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1, 129 ref_walk_tit(rw)); 130} 131 132static inline void ref_walk_set_tcon(struct dfs_ref_walk *rw, 133 struct cifs_tcon *tcon) 134{ 135 struct dfs_ref *ref = ref_walk_start(rw); 136 137 for (; ref <= ref_walk_cur(rw); ref++) { 138 if (WARN_ON_ONCE(!ref->ses)) 139 continue; 140 list_add(&ref->ses->dlist, &tcon->dfs_ses_list); 141 ref->ses = NULL; 142 } 143} 144 145static inline void ref_walk_mark_end(struct dfs_ref_walk *rw) 146{ 147 struct dfs_ref *ref = ref_walk_cur(rw) - 1; 148 149 WARN_ON_ONCE(ref < ref_walk_start(rw)); 150 dfs_cache_noreq_update_tgthint(ref->path + 1, ref->tit); 151 ref->tit = ERR_PTR(-ENOENT); /* end marker */ 152} 153 154int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref, 155 struct smb3_fs_context *ctx); 156int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx); 157 158static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path) 159{ 160 return dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb)); 161} 162 163static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, 164 const char *path, 165 struct dfs_cache_tgt_list *tl) 166{ 167 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 168 struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 169 struct cifs_ses *rses = ctx->dfs_root_ses ?: mnt_ctx->ses; 170 171 return dfs_cache_find(mnt_ctx->xid, rses, cifs_sb->local_nls, 172 cifs_remap(cifs_sb), path, NULL, tl); 173} 174 175/* 176 * cifs_get_smb_ses() already guarantees an active reference of 177 * @ses->dfs_root_ses when a new session is created, so we need to put extra 178 * references of all DFS root sessions that were used across the mount process 179 * in dfs_mount_share(). 180 */ 181static inline void dfs_put_root_smb_sessions(struct list_head *head) 182{ 183 struct cifs_ses *ses, *n; 184 185 list_for_each_entry_safe(ses, n, head, dlist) { 186 list_del_init(&ses->dlist); 187 cifs_put_smb_ses(ses); 188 } 189} 190 191static inline const char *dfs_ses_refpath(struct cifs_ses *ses) 192{ 193 const char *path = ses->server->leaf_fullpath; 194 195 return path ? path + 1 : ERR_PTR(-ENOENT); 196} 197 198#endif /* _CIFS_DFS_H */
~/
Read-only file preview.