1 // systemtap cache manager
2 // Copyright (C) 2006-2009 Red Hat Inc.
4 // This file is part of systemtap, and is free software. You can
5 // redistribute it and/or modify it under the terms of the GNU General
6 // Public License (GPL); either version 2, or (at your option) any
19 #include <sys/types.h>
28 #define SYSTEMTAP_CACHE_MAX_FILENAME "cache_mb_limit"
29 #define SYSTEMTAP_CACHE_DEFAULT_MB 64
31 struct cache_ent_info
{
35 long weight
; //lower == removed earlier
37 cache_ent_info(const string
& path
, bool is_module
);
38 bool operator<(const struct cache_ent_info
& other
) const
39 { return weight
< other
.weight
; }
43 static void clean_cache(systemtap_session
& s
);
47 add_to_cache(systemtap_session
& s
)
49 string stapconf_src_path
= s
.tmpdir
+ "/" + s
.stapconf_name
;
51 clog
<< "Copying " << stapconf_src_path
<< " to " << s
.stapconf_path
<< endl
;
52 if (copy_file(stapconf_src_path
.c_str(), s
.stapconf_path
.c_str()) != 0)
54 cerr
<< "Copy failed (\"" << stapconf_src_path
<< "\" to \""
55 << s
.stapconf_path
<< "\"): " << strerror(errno
) << endl
;
60 string module_src_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
62 clog
<< "Copying " << module_src_path
<< " to " << s
.hash_path
<< endl
;
63 if (copy_file(module_src_path
.c_str(), s
.hash_path
.c_str()) != 0)
65 cerr
<< "Copy failed (\"" << module_src_path
<< "\" to \""
66 << s
.hash_path
<< "\"): " << strerror(errno
) << endl
;
72 // This is the name of the cached module signature.
73 string module_signature_dest_path
= s
.hash_path
;
74 module_signature_dest_path
+= ".sgn";
76 if (!s
.cert_db_path
.empty())
78 // Copy the module signature, if it was signed.
79 string module_signature_src_path
= module_src_path
;
80 module_signature_src_path
+= ".sgn";
83 clog
<< "Copying " << module_signature_src_path
<< " to " << module_signature_dest_path
<< endl
;
84 if (copy_file(module_signature_src_path
.c_str(), module_signature_dest_path
.c_str()) != 0)
86 cerr
<< "Copy failed (\"" << module_signature_src_path
<< "\" to \""
87 << module_signature_dest_path
<< "\"): " << strerror(errno
) << endl
;
88 // NB: this is not so severe as to prevent reuse of the .ko
91 // s.use_cache = false;
96 // If this module was not signed, then delete any existing signature from the cache.
97 // This is not a fatal error. Even if the existing signature happens to match a
98 // new module later, it still means that the module is identical to one generated by a
100 if (remove_file_or_dir (module_signature_dest_path
.c_str()) != 0)
101 cerr
<< "Failed to remove \"" << module_signature_dest_path
<< "\" from the cache: "
102 << strerror(errno
) << endl
;
104 #endif /* HAVE_NSS */
106 string c_dest_path
= s
.hash_path
;
107 if (c_dest_path
.rfind(".ko") == (c_dest_path
.size() - 3))
108 c_dest_path
.resize(c_dest_path
.size() - 3);
112 clog
<< "Copying " << s
.translated_source
<< " to " << c_dest_path
114 if (copy_file(s
.translated_source
.c_str(), c_dest_path
.c_str()) != 0)
117 cerr
<< "Copy failed (\"" << s
.translated_source
<< "\" to \""
118 << c_dest_path
<< "\"): " << strerror(errno
) << endl
;
119 // NB: this is not so severe as to prevent reuse of the .ko
122 // s.use_cache = false;
130 get_from_cache(systemtap_session
& s
)
132 string stapconf_dest_path
= s
.tmpdir
+ "/" + s
.stapconf_name
;
133 string module_dest_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
134 string c_src_path
= s
.hash_path
;
135 int fd_stapconf
, fd_module
, fd_c
;
137 string hash_signature_path
= s
.hash_path
+ ".sgn";
141 if (c_src_path
.rfind(".ko") == (c_src_path
.size() - 3))
142 c_src_path
.resize(c_src_path
.size() - 3);
145 // See if stapconf exists
146 fd_stapconf
= open(s
.stapconf_path
.c_str(), O_RDONLY
);
147 if (fd_stapconf
== -1)
149 // It isn't in cache.
153 // Copy the stapconf header file to the destination
154 if (copy_file(s
.stapconf_path
.c_str(), stapconf_dest_path
.c_str()) != 0)
156 cerr
<< "Copy failed (\"" << s
.stapconf_path
<< "\" to \""
157 << stapconf_dest_path
<< "\"): " << strerror(errno
) << endl
;
162 // We're done with this file handle.
166 clog
<< "Pass 3: using cached " << s
.stapconf_path
<< endl
;
168 // See if module exists
169 fd_module
= open(s
.hash_path
.c_str(), O_RDONLY
);
172 // It isn't in cache.
176 // See if C file exists.
177 fd_c
= open(c_src_path
.c_str(), O_RDONLY
);
180 // The module is there, but the C file isn't. Cleanup and
183 unlink(s
.hash_path
.c_str());
187 // Copy the cached C file to the destination
188 if (copy_file(c_src_path
.c_str(), s
.translated_source
.c_str()) != 0)
190 cerr
<< "Copy failed (\"" << c_src_path
<< "\" to \""
191 << s
.translated_source
<< "\"): " << strerror(errno
) << endl
;
197 // Copy the cached module to the destination (if needed)
198 if (s
.last_pass
!= 3)
200 if (copy_file(s
.hash_path
.c_str(), module_dest_path
.c_str()) != 0)
202 cerr
<< "Copy failed (\"" << s
.hash_path
<< "\" to \""
203 << module_dest_path
<< "\"): " << strerror(errno
) << endl
;
204 unlink(c_src_path
.c_str());
210 // See if module signature exists. It's not an error if it doesn't. It just
211 // means that the module is unsigned.
212 fd_signature
= open(hash_signature_path
.c_str(), O_RDONLY
);
213 if (fd_signature
!= -1) {
214 string signature_dest_path
= module_dest_path
+ ".sgn";
216 if (copy_file(hash_signature_path
.c_str(), signature_dest_path
.c_str()) != 0)
218 cerr
<< "Copy failed (\"" << hash_signature_path
<< "\" to \""
219 << signature_dest_path
<< "\"): " << strerror(errno
) << endl
;
220 unlink(c_src_path
.c_str());
229 // We're done with these file handles.
233 // To preserve semantics (since this will happen if we're not
234 // caching), display the C source if the last pass is 3.
235 if (s
.last_pass
== 3)
237 ifstream
i (s
.translated_source
.c_str());
240 // And similarly, display probe module name for -p4.
241 if (s
.last_pass
== 4)
242 cout
<< s
.hash_path
<< endl
;
244 // If everything worked, tell the user. We need to do this here,
245 // since if copying the cached C file works, but copying the cached
246 // module fails, we remove the cached C file and let the C file get
250 clog
<< "Pass 3: using cached " << c_src_path
<< endl
;
251 if (s
.last_pass
!= 3)
252 clog
<< "Pass 4: using cached " << s
.hash_path
<< endl
;
260 clean_cache(systemtap_session
& s
)
262 if (s
.cache_path
!= "")
264 /* Get cache size limit from file in the stap cache dir */
265 string cache_max_filename
= s
.cache_path
+ "/";
266 cache_max_filename
+= SYSTEMTAP_CACHE_MAX_FILENAME
;
267 ifstream
cache_max_file(cache_max_filename
.c_str(), ios::in
);
268 unsigned long cache_mb_max
;
270 if (cache_max_file
.is_open())
272 cache_max_file
>> cache_mb_max
;
273 cache_max_file
.close();
277 //file doesnt exist, create a default size
278 ofstream
default_cache_max(cache_max_filename
.c_str(), ios::out
);
279 default_cache_max
<< SYSTEMTAP_CACHE_DEFAULT_MB
<< endl
;
280 cache_mb_max
= SYSTEMTAP_CACHE_DEFAULT_MB
;
283 clog
<< "Cache limit file " << s
.cache_path
<< "/"
284 << SYSTEMTAP_CACHE_MAX_FILENAME
285 << " missing, creating default." << endl
;
288 //glob for all kernel modules in the cache dir
290 string glob_str
= s
.cache_path
+ "/*/*.ko";
291 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
294 set
<struct cache_ent_info
> cache_contents
;
295 unsigned long cache_size_b
= 0;
297 //grab info for each cache entry (.ko and .c)
298 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
300 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
301 cache_ent_path
.resize(cache_ent_path
.length() - 3);
303 struct cache_ent_info
cur_info(cache_ent_path
, true);
304 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
306 cache_size_b
+= cur_info
.size
;
307 cache_contents
.insert(cur_info
);
311 globfree(&cache_glob
);
313 //grab info for each typequery user module (.so)
314 glob_str
= s
.cache_path
+ "/*/*.so";
315 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
316 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
318 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
319 struct cache_ent_info
cur_info(cache_ent_path
, false);
320 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
322 cache_size_b
+= cur_info
.size
;
323 cache_contents
.insert(cur_info
);
327 globfree(&cache_glob
);
329 //grab info for each stapconf cache entry (.h)
330 glob_str
= s
.cache_path
+ "/*/*.h";
331 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
332 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
334 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
335 struct cache_ent_info
cur_info(cache_ent_path
, false);
336 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
338 cache_size_b
+= cur_info
.size
;
339 cache_contents
.insert(cur_info
);
343 globfree(&cache_glob
);
345 set
<struct cache_ent_info
>::iterator i
;
346 unsigned long r_cache_size
= cache_size_b
;
347 string removed_dirs
= "";
349 //unlink .ko and .c until the cache size is under the limit
350 for (i
= cache_contents
.begin(); i
!= cache_contents
.end(); ++i
)
352 if ( (r_cache_size
/ 1024 / 1024) < cache_mb_max
) //convert r_cache_size to MiB
355 //remove this (*i) cache_entry, add to removed list
357 r_cache_size
-= i
->size
;
358 removed_dirs
+= i
->path
+ ", ";
361 cache_contents
.clear();
363 if (s
.verbose
> 1 && removed_dirs
!= "")
365 //remove trailing ", "
366 removed_dirs
= removed_dirs
.substr(0, removed_dirs
.length() - 2);
367 clog
<< "Cache cleaning successful, removed entries: "
368 << removed_dirs
<< endl
;
374 clog
<< "Cache cleaning skipped, no cache path." << endl
;
378 // Get the size of a file in bytes
380 get_file_size(const string
&path
)
382 struct stat file_info
;
384 if (stat(path
.c_str(), &file_info
) == 0)
385 return file_info
.st_size
;
390 //Assign a weight for a particular file. A lower weight
391 // will be removed before a higher weight.
392 //TODO: for now use system mtime... later base a
393 // weighting on size, ctime, atime etc..
395 get_file_weight(const string
&path
)
397 time_t dir_mtime
= 0;
398 struct stat dir_stat_info
;
400 if (stat(path
.c_str(), &dir_stat_info
) == 0)
401 //GNU struct stat defines st_atime as st_atim.tv_sec
402 // but it doesnt seem to work properly in practice
403 // so use st_atim.tv_sec -- bad for portability?
404 dir_mtime
= dir_stat_info
.st_mtim
.tv_sec
;
410 cache_ent_info::cache_ent_info(const string
& path
, bool is_module
):
411 path(path
), is_module(is_module
)
415 string mod_path
= path
+ ".ko";
416 string source_path
= path
+ ".c";
417 size
= get_file_size(mod_path
) + get_file_size(source_path
);
418 weight
= get_file_weight(mod_path
);
422 size
= get_file_size(path
);
423 weight
= get_file_weight(path
);
429 cache_ent_info::unlink() const
433 string mod_path
= path
+ ".ko";
434 string source_path
= path
+ ".c";
435 ::unlink(mod_path
.c_str());
436 ::unlink(source_path
.c_str());
439 ::unlink(path
.c_str());
442 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */