77// ===----------------------------------------------------------------------===//
88
99#include " lustre_fid2path.hpp"
10+ #include " lustre_link_selection.hpp"
1011#include " lustre_types.hpp"
1112#include " mdt_scanner.hpp"
1213
@@ -25,6 +26,14 @@ namespace lustre {
2526static const LustreFID ROOT_FID = {0x200000007ULL , 1 , 0 };
2627static constexpr idx_t MAX_PATH_DEPTH = 4096 ;
2728
29+ static const LinkEntry *SelectParentTraversalLink (const LustreFID &fid, const LustreLMV &lmv,
30+ const vector<LinkEntry> &links) {
31+ if (lmv.IsSlave ()) {
32+ return SelectStripedSlaveParentLink (links, fid, lmv.lmv_master_mdt_index );
33+ }
34+ return SelectDirectoryParentLink (links);
35+ }
36+
2837// ===----------------------------------------------------------------------===//
2938// Bind Data - stores device paths (shared across threads)
3039// ===----------------------------------------------------------------------===//
@@ -122,7 +131,9 @@ static unique_ptr<FunctionLocalState> Fid2PathInitLocal(ExpressionState &state,
122131
123132static bool BuildPathFromLink (Fid2PathLocalState &lstate, const string &name, LustreFID parent_fid, string &path_out) {
124133 vector<string> components;
125- components.push_back (name);
134+ if (!name.empty ()) {
135+ components.push_back (name);
136+ }
126137
127138 LustreFID current_fid = parent_fid;
128139 idx_t depth = 0 ;
@@ -144,9 +155,20 @@ static bool BuildPathFromLink(Fid2PathLocalState &lstate, const string &name, Lu
144155 return false ;
145156 }
146157
147- // Directories cannot have hardlinks on Linux, so first entry is sufficient
148- components.push_back (links[0 ].name );
149- current_fid = links[0 ].parent_fid ;
158+ LustreLMV lmv;
159+ lstate.scanners [scanner_idx]->ReadInodeLMV (ino, lmv);
160+
161+ auto *parent_link = SelectParentTraversalLink (current_fid, lmv, links);
162+ if (!parent_link) {
163+ return false ;
164+ }
165+
166+ // Slave stripes are implementation details. Follow their master link but
167+ // do not expose the synthetic shard name as a path component.
168+ if (!lmv.IsSlave ()) {
169+ components.push_back (parent_link->name );
170+ }
171+ current_fid = parent_link->parent_fid ;
150172 }
151173
152174 // Build path: reverse components and join with /
@@ -213,13 +235,27 @@ static void Fid2PathExecute(DataChunk &args, ExpressionState &state, Vector &res
213235 continue ;
214236 }
215237
238+ LustreLMV lmv;
239+ lstate.scanners [scanner_idx]->ReadInodeLMV (ino, lmv);
240+
216241 // Build a path for each link entry (hardlink)
217242 bool any_success = false ;
218- for (auto &link : links) {
219- string path;
220- if (BuildPathFromLink (lstate, link.name , link.parent_fid , path)) {
221- all_paths[i].push_back (std::move (path));
222- any_success = true ;
243+ if (lmv.IsSlave ()) {
244+ auto *parent_link = SelectParentTraversalLink (current_fid, lmv, links);
245+ if (parent_link) {
246+ string path;
247+ if (BuildPathFromLink (lstate, string (), parent_link->parent_fid , path)) {
248+ all_paths[i].push_back (std::move (path));
249+ any_success = true ;
250+ }
251+ }
252+ } else {
253+ for (auto &link : links) {
254+ string path;
255+ if (BuildPathFromLink (lstate, link.name , link.parent_fid , path)) {
256+ all_paths[i].push_back (std::move (path));
257+ any_success = true ;
258+ }
223259 }
224260 }
225261
0 commit comments