this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve DPREFIX performance on NFS mounts

+93 -70
+93 -70
src/libdyld/VirtualPrefix.cpp
··· 24 24 #include <list> 25 25 #include <cassert> 26 26 #include <unistd.h> 27 + #include <sys/stat.h> 27 28 #include <iostream> 28 29 #include <cstdio> 29 30 #include <dirent.h> ··· 304 305 305 306 path += '/'; 306 307 307 - real_path.replace(g_prefix.size(), std::string::npos, path); 308 - 309 - if (!had_failure) // check if there is any sense in using opendir again 308 + if (!had_failure) // check if there is any sense in using opendir() or lstat() again 310 309 { 311 310 DIR* dir; 312 311 struct dirent* ent; 312 + struct stat st; 313 + bool isLink = false; 314 + bool is_system_root; 313 315 314 - // std::cout << "*** opendir: " << real_path << std::endl; 315 - dir = opendir(real_path.c_str()); 316 - 317 - if (dir != nullptr) 316 + real_path.replace(g_prefix.size(), std::string::npos, path); 317 + real_path += comp; 318 + 319 + // Do NOT perform symlink resolution on /system-root, 320 + // because that should look like a bind mount rather than 321 + // a symlink from inside the DPREFIX 322 + is_system_root = (it == path_components.begin()) 323 + && (comp == (SYSTEM_ROOT+1)); 324 + 325 + // We try an lstat() first as an optimization, 326 + // because the opendir() path below is VERY slow on NFS mounts. 327 + if (lstat(real_path.c_str(), &st) == 0) 328 + { 329 + isLink = S_ISLNK(st.st_mode); 330 + } 331 + else 318 332 { 319 - std::string best_match; 320 - unsigned char best_match_type; 333 + // std::cout << "*** opendir: " << real_path << std::endl; 334 + real_path.resize(real_path.length() - comp.length()); 321 335 322 - while ((ent = readdir(dir)) != nullptr) 336 + dir = opendir(real_path.c_str()); 337 + 338 + if (dir != nullptr) 323 339 { 324 - if (comp == ent->d_name) 325 - break; 326 - else if (strcasecmp(comp.c_str(), ent->d_name) == 0) 340 + std::string best_match; 341 + unsigned char best_match_type; 342 + 343 + while ((ent = readdir(dir)) != nullptr) 327 344 { 328 - best_match = ent->d_name; 329 - best_match_type = ent->d_type; 345 + // Commented out: replaced with lstat() above 346 + /* if (comp == ent->d_name) 347 + break; 348 + else*/ if (strcasecmp(comp.c_str(), ent->d_name) == 0) 349 + { 350 + best_match = ent->d_name; 351 + best_match_type = ent->d_type; 352 + } 330 353 } 331 - } 332 354 333 - if (ent != nullptr || !best_match.empty()) 334 - { 335 - bool is_system_root; 336 - if (ent == nullptr) 337 - { 338 - // correct the case 339 - comp = best_match; 340 - } 341 - else 342 - best_match_type = ent->d_type; 343 - 344 - // Perform symlink resolution 345 - // 346 - // Do NOT perform symlink resolution on /system-root, 347 - // because that should look like a bind mount rather than 348 - // a symlink from inside the DPREFIX 349 - is_system_root = (it == path_components.begin()) 350 - && (comp == (SYSTEM_ROOT+1)); 351 - 352 - if (best_match_type == DT_LNK && !is_system_root) 355 + if (ent != nullptr || !best_match.empty()) 353 356 { 354 - char link[256]; 355 - int len; 356 - 357 - real_path += comp; 358 - 359 - // std::cout << "*** readlink: " << real_path << std::endl; 360 - len = readlink(real_path.c_str(), link, sizeof(link)-1); 361 - 362 - if (len > 0) 357 + if (ent == nullptr) 358 + { 359 + // correct the case 360 + comp = best_match; 361 + } 362 + else 363 + best_match_type = ent->d_type; 364 + 365 + if (best_match_type == DT_LNK && !is_system_root) 363 366 { 364 - std::list<std::string> link_components; 365 - 366 - link[len] = '\0'; 367 - 368 - link_components = explode_path(link); 369 - 370 - if (link[0] == '/') 371 - { 372 - it++; 373 - it = path_components.erase(path_components.begin(), it); 374 - } 375 - else 376 - { 377 - it = path_components.erase(it); 378 - } 379 - 380 - path_components.insert(it, 381 - link_components.begin(), 382 - link_components.end()); 383 - 384 - closedir(dir); 385 - goto restart_process; 367 + isLink = true; 368 + real_path += comp; 386 369 } 387 370 } 371 + else 372 + had_failure = true; 373 + 374 + closedir(dir); 388 375 } 389 376 else 390 377 had_failure = true; 378 + } 379 + 380 + // Perform symlink resolution 381 + if (isLink && !is_system_root) 382 + { 383 + char link[256]; 384 + int len; 391 385 392 - closedir(dir); 386 + // std::cout << "*** readlink: " << real_path << std::endl; 387 + len = readlink(real_path.c_str(), link, sizeof(link)-1); 388 + 389 + if (len > 0) 390 + { 391 + std::list<std::string> link_components; 392 + 393 + link[len] = '\0'; 394 + 395 + link_components = explode_path(link); 396 + 397 + if (link[0] == '/') 398 + { 399 + // absolute symlink 400 + it++; 401 + it = path_components.erase(path_components.begin(), it); 402 + } 403 + else 404 + { 405 + // relative symlink 406 + it = path_components.erase(it); 407 + } 408 + 409 + path_components.insert(it, 410 + link_components.begin(), 411 + link_components.end()); 412 + 413 + // We always restart the process 414 + // 1) For absolute symlinks, because we're moving to a completely different path 415 + // 2) For relative symlinks, because they may contain '..' 416 + goto restart_process; 417 + } 393 418 } 394 - else 395 - had_failure = true; 396 419 } 397 420 398 421 path += comp;