Skip to content

Commit 15d5a7f

Browse files
committed
Read ldcache at construction instead of on each locate call
This change udpates the ldcache locator to read the ldcache at construction and use these contents to perform future lookups against. Each of the cache entries are resolved and lookups return the resolved target. Assuming a symlink chain: libcuda.so -> libcuda.so.1 -> libcuda.so.VERSION, this means that libcuda.so.VERION will be returned for any of the following inputs: libcuda.so, libcuda.so.1, libcudal.so.*. Signed-off-by: Evan Lezar <[email protected]>
1 parent 64f73ae commit 15d5a7f

File tree

7 files changed

+182
-147
lines changed

7 files changed

+182
-147
lines changed

cmd/nvidia-ctk/system/print-ldcache/print-ldcache.go

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ package createdevicenodes
1818

1919
import (
2020
"fmt"
21+
"strings"
2122

2223
"github.com/urfave/cli/v2"
2324

24-
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache"
2525
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
26+
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
2627
)
2728

2829
type command struct {
@@ -74,27 +75,24 @@ func (m command) validateFlags(r *cli.Context, opts *options) error {
7475
}
7576

7677
func (m command) run(c *cli.Context, opts *options) error {
77-
cache, err := ldcache.New(m.logger, opts.driverRoot)
78-
if err != nil {
79-
return fmt.Errorf("failed to create ldcache: %v", err)
80-
}
78+
l := lookup.NewLdcacheLocator(
79+
lookup.WithLogger(m.logger),
80+
lookup.WithRoot(opts.driverRoot),
81+
)
8182

82-
lib32, lib64 := cache.List()
83+
libs64, _ := l.Locate("*")
8384

84-
if len(lib32) == 0 {
85-
m.logger.Info("No 32-bit libraries found")
86-
} else {
87-
m.logger.Infof("%d 32-bit libraries found", len(lib32))
88-
for _, lib := range lib32 {
89-
m.logger.Infof("%v", lib)
90-
}
91-
}
92-
if len(lib64) == 0 {
85+
if len(libs64) == 0 {
9386
m.logger.Info("No 64-bit libraries found")
9487
} else {
95-
m.logger.Infof("%d 64-bit libraries found", len(lib64))
96-
for _, lib := range lib64 {
97-
m.logger.Infof("%v", lib)
88+
chain := lookup.NewSymlinkChainLocator()
89+
m.logger.Infof("%d 64-bit libraries found", len(libs64))
90+
for _, lib := range libs64 {
91+
links, err := chain.Locate(lib)
92+
if err != nil {
93+
m.logger.Errorf("falied to locate %s: %v", lib, err)
94+
}
95+
fmt.Println(strings.Join(append([]string{lib}, links[1:]...), " => "))
9896
}
9997
}
10098

internal/ldcache/ldcache.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,7 @@ func New(logger logger.Interface, root string) (LDCache, error) {
105105

106106
logger.Debugf("Opening ld.conf at %v", path)
107107
f, err := os.Open(path)
108-
if os.IsNotExist(err) {
109-
logger.Warningf("Could not find ld.so.cache at %v; creating empty cache", path)
110-
e := &empty{
111-
logger: logger,
112-
path: path,
113-
}
114-
return e, nil
115-
} else if err != nil {
108+
if err != nil {
116109
return nil, err
117110
}
118111
defer f.Close()
@@ -248,7 +241,20 @@ func (c *ldcache) getEntries(selected func(string) bool) []entry {
248241
func (c *ldcache) List() ([]string, []string) {
249242
all := func(s string) bool { return true }
250243

251-
return c.resolveSelected(all)
244+
paths := make(map[int][]string)
245+
processed := make(map[string]bool)
246+
247+
entries := c.getEntries(all)
248+
for _, e := range entries {
249+
path := filepath.Join(c.root, e.value)
250+
if processed[path] {
251+
continue
252+
}
253+
paths[e.bits] = append(paths[e.bits], path)
254+
processed[path] = true
255+
}
256+
257+
return paths[32], paths[64]
252258
}
253259

254260
// Lookup searches the ldcache for the specified prefixes.
@@ -275,7 +281,8 @@ func (c *ldcache) resolveSelected(selected func(string) bool) ([]string, []strin
275281
paths := make(map[int][]string)
276282
processed := make(map[string]bool)
277283

278-
for _, e := range c.getEntries(selected) {
284+
entries := c.getEntries(selected)
285+
for _, e := range entries {
279286
path, err := c.resolve(e.value)
280287
if err != nil {
281288
c.logger.Debugf("Could not resolve entry: %v", err)

internal/lookup/library-ldcache.go

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,98 @@
1-
/**
2-
# Copyright 2024 NVIDIA CORPORATION
3-
#
4-
# Licensed under the Apache License, Version 2.0 (the "License");
5-
# you may not use this file except in compliance with the License.
6-
# You may obtain a copy of the License at
7-
#
8-
# http://www.apache.org/licenses/LICENSE-2.0
9-
#
10-
# Unless required by applicable law or agreed to in writing, software
11-
# distributed under the License is distributed on an "AS IS" BASIS,
12-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
# See the License for the specific language governing permissions and
14-
# limitations under the License.
15-
**/
16-
171
package lookup
182

193
import (
20-
"fmt"
4+
"path/filepath"
5+
"slices"
216

227
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache"
238
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
249
)
2510

2611
type ldcacheLocator struct {
27-
logger logger.Interface
28-
cache ldcache.LDCache
12+
logger logger.Interface
13+
resolvesTo map[string]string
2914
}
3015

3116
var _ Locator = (*ldcacheLocator)(nil)
3217

33-
func newLdcacheLocator(opts ...Option) Locator {
18+
func NewLdcacheLocator(opts ...Option) Locator {
3419
b := newBuilder(opts...)
3520

3621
cache, err := ldcache.New(b.logger, b.root)
3722
if err != nil {
38-
// If we failed to open the LDCache, we default to a symlink locator.
3923
b.logger.Warningf("Failed to load ldcache: %v", err)
40-
return nil
24+
if b.isOptional {
25+
return &null{}
26+
}
27+
return &notFound{}
28+
}
29+
30+
chain := NewSymlinkChainLocator(WithOptional(true))
31+
32+
resolvesTo := make(map[string]string)
33+
_, libs64 := cache.List()
34+
for _, library := range libs64 {
35+
if _, processed := resolvesTo[library]; processed {
36+
continue
37+
}
38+
candidates, err := chain.Locate(library)
39+
if err != nil {
40+
b.logger.Errorf("error processing library %s from ldcache: %v", library, err)
41+
continue
42+
}
43+
44+
if len(candidates) == 0 {
45+
resolvesTo[library] = library
46+
continue
47+
}
48+
49+
// candidates represents a symlink chain.
50+
// The first element represents the start of the chain and the last
51+
// element the final target.
52+
target := candidates[len(candidates)-1]
53+
for _, candidate := range candidates {
54+
resolvesTo[candidate] = target
55+
}
4156
}
4257

4358
return &ldcacheLocator{
44-
logger: b.logger,
45-
cache: cache,
59+
logger: b.logger,
60+
resolvesTo: resolvesTo,
4661
}
4762
}
4863

4964
// Locate finds the specified libraryname.
5065
// If the input is a library name, the ldcache is searched otherwise the
5166
// provided path is resolved as a symlink.
5267
func (l ldcacheLocator) Locate(libname string) ([]string, error) {
53-
paths32, paths64 := l.cache.Lookup(libname)
54-
if len(paths32) > 0 {
55-
l.logger.Warningf("Ignoring 32-bit libraries for %v: %v", libname, paths32)
68+
var matcher func(string, string) bool
69+
70+
if filepath.IsAbs(libname) {
71+
matcher = func(p string, c string) bool {
72+
m, _ := filepath.Match(p, c)
73+
return m
74+
}
75+
} else {
76+
matcher = func(p string, c string) bool {
77+
m, _ := filepath.Match(p, filepath.Base(c))
78+
return m
79+
}
5680
}
5781

58-
if len(paths64) == 0 {
59-
return nil, fmt.Errorf("64-bit library %v: %w", libname, ErrNotFound)
82+
var matches []string
83+
seen := make(map[string]bool)
84+
for name, target := range l.resolvesTo {
85+
if !matcher(libname, name) {
86+
continue
87+
}
88+
if seen[target] {
89+
continue
90+
}
91+
seen[target] = true
92+
matches = append(matches, target)
6093
}
6194

62-
return paths64, nil
95+
slices.Sort(matches)
96+
97+
return matches, nil
6398
}

internal/lookup/library-ldcache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func TestLDCacheLookup(t *testing.T) {
4343
for _, input := range tc.inputs {
4444
t.Run(tc.rootFs+input, func(t *testing.T) {
4545
rootfs := filepath.Join(moduleRoot, "testdata", "lookup", tc.rootFs)
46-
l := newLdcacheLocator(
46+
l := NewLdcacheLocator(
4747
WithLogger(logger),
4848
WithRoot(rootfs),
4949
)

internal/lookup/library.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewLibraryLocator(opts ...Option) Locator {
4949

5050
l := First(
5151
symlinkLocator,
52-
newLdcacheLocator(opts...),
52+
NewLdcacheLocator(opts...),
5353
)
5454
return l
5555
}

0 commit comments

Comments
 (0)