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
21 #include <sys/types.h>
30 #define SYSTEMTAP_CACHE_MAX_FILENAME "cache_mb_limit"
31 #define SYSTEMTAP_CACHE_DEFAULT_MB 64
33 struct cache_ent_info
{
37 long weight
; //lower == removed earlier
39 cache_ent_info(const string
& path
, bool is_module
);
40 bool operator<(const struct cache_ent_info
& other
) const
41 { return weight
< other
.weight
; }
47 add_stapconf_to_cache(systemtap_session
& s
)
49 bool verbose
= s
.verbose
> 1;
51 string stapconf_src_path
= s
.tmpdir
+ "/" + s
.stapconf_name
;
52 if (!copy_file(stapconf_src_path
, s
.stapconf_path
, verbose
))
54 // NB: this is not so severe as to prevent reuse of the .ko
57 // s.use_script_cache = false;
64 add_script_to_cache(systemtap_session
& s
)
66 bool verbose
= s
.verbose
> 1;
68 // PR10543: clean the cache *before* we try putting something new into it.
69 // We don't want to risk having the brand new contents being erased again.
72 string module_src_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
73 STAP_PROBE2(stap
, cache__add__module
, module_src_path
.c_str(), s
.hash_path
.c_str());
74 if (!copy_file(module_src_path
, s
.hash_path
, verbose
))
76 s
.use_script_cache
= false;
79 // Copy the signature file, if any. It is not an error if this fails.
80 if (file_exists (module_src_path
+ ".sgn"))
81 copy_file(module_src_path
+ ".sgn", s
.hash_path
+ ".sgn", verbose
);
83 string c_dest_path
= s
.hash_path
;
84 if (endswith(c_dest_path
, ".ko"))
85 c_dest_path
.resize(c_dest_path
.size() - 3);
88 STAP_PROBE2(stap
, cache__add__source
, s
.translated_source
.c_str(), c_dest_path
.c_str());
89 if (!copy_file(s
.translated_source
, c_dest_path
, verbose
))
91 // NB: this is not so severe as to prevent reuse of the .ko
94 // s.use_script_cache = false;
100 get_stapconf_from_cache(systemtap_session
& s
)
105 string stapconf_dest_path
= s
.tmpdir
+ "/" + s
.stapconf_name
;
108 // See if stapconf exists
109 fd_stapconf
= open(s
.stapconf_path
.c_str(), O_RDONLY
);
110 if (fd_stapconf
== -1)
112 // It isn't in cache.
116 // Copy the stapconf header file to the destination
117 if (!copy_file(s
.stapconf_path
, stapconf_dest_path
))
123 // We're done with this file handle.
127 clog
<< "Pass 4: using cached " << s
.stapconf_path
<< endl
;
134 get_script_from_cache(systemtap_session
& s
)
139 string module_dest_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
140 string c_src_path
= s
.hash_path
;
143 if (endswith(c_src_path
, ".ko"))
144 c_src_path
.resize(c_src_path
.size() - 3);
147 // See if module exists
148 fd_module
= open(s
.hash_path
.c_str(), O_RDONLY
);
151 // It isn't in cache.
155 // See if C file exists.
156 fd_c
= open(c_src_path
.c_str(), O_RDONLY
);
159 // The module is there, but the C file isn't. Cleanup and
162 unlink(s
.hash_path
.c_str());
166 // Copy the cached C file to the destination
167 if (!copy_file(c_src_path
, s
.translated_source
))
174 // Copy the cached module to the destination (if needed)
175 if (s
.last_pass
!= 3)
177 if (!copy_file(s
.hash_path
, module_dest_path
))
179 unlink(c_src_path
.c_str());
184 // Copy the module signature file, if any.
185 // It is not an error if this fails.
186 if (file_exists (s
.hash_path
+ ".sgn"))
187 copy_file(s
.hash_path
+ ".sgn", module_dest_path
+ ".sgn");
190 // We're done with these file handles.
194 // To preserve semantics (since this will happen if we're not
195 // caching), display the C source if the last pass is 3.
196 if (s
.last_pass
== 3)
198 ifstream
i (s
.translated_source
.c_str());
201 // And similarly, display probe module name for -p4.
202 if (s
.last_pass
== 4)
203 cout
<< s
.hash_path
<< endl
;
205 // If everything worked, tell the user. We need to do this here,
206 // since if copying the cached C file works, but copying the cached
207 // module fails, we remove the cached C file and let the C file get
209 // NB: don't use s.verbose here, since we're still in pass-2,
210 // i.e., s.verbose = s.perpass_verbose[1].
211 if (s
.perpass_verbose
[2])
212 clog
<< "Pass 3: using cached " << c_src_path
<< endl
;
213 if (s
.perpass_verbose
[3] && s
.last_pass
!= 3)
214 clog
<< "Pass 4: using cached " << s
.hash_path
<< endl
;
216 STAP_PROBE2(stap
, cache__get
, c_src_path
.c_str(), s
.hash_path
.c_str());
223 clean_cache(systemtap_session
& s
)
225 if (s
.cache_path
!= "")
227 /* Get cache size limit from file in the stap cache dir */
228 string cache_max_filename
= s
.cache_path
+ "/";
229 cache_max_filename
+= SYSTEMTAP_CACHE_MAX_FILENAME
;
230 ifstream
cache_max_file(cache_max_filename
.c_str(), ios::in
);
231 unsigned long cache_mb_max
;
233 if (cache_max_file
.is_open())
235 cache_max_file
>> cache_mb_max
;
236 cache_max_file
.close();
240 //file doesnt exist, create a default size
241 ofstream
default_cache_max(cache_max_filename
.c_str(), ios::out
);
242 default_cache_max
<< SYSTEMTAP_CACHE_DEFAULT_MB
<< endl
;
243 cache_mb_max
= SYSTEMTAP_CACHE_DEFAULT_MB
;
246 clog
<< "Cache limit file " << s
.cache_path
<< "/"
247 << SYSTEMTAP_CACHE_MAX_FILENAME
248 << " missing, creating default." << endl
;
251 //glob for all kernel modules in the cache dir
253 string glob_str
= s
.cache_path
+ "/*/*.ko";
254 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
257 set
<struct cache_ent_info
> cache_contents
;
258 unsigned long cache_size_b
= 0;
260 //grab info for each cache entry (.ko and .c)
261 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
263 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
264 cache_ent_path
.resize(cache_ent_path
.length() - 3);
266 struct cache_ent_info
cur_info(cache_ent_path
, true);
267 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
269 cache_size_b
+= cur_info
.size
;
270 cache_contents
.insert(cur_info
);
274 globfree(&cache_glob
);
276 //grab info for each typequery user module (.so)
277 glob_str
= s
.cache_path
+ "/*/*.so";
278 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
279 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
281 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
282 struct cache_ent_info
cur_info(cache_ent_path
, false);
283 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
285 cache_size_b
+= cur_info
.size
;
286 cache_contents
.insert(cur_info
);
290 globfree(&cache_glob
);
292 //grab info for each stapconf cache entry (.h)
293 glob_str
= s
.cache_path
+ "/*/*.h";
294 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
295 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
297 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
298 struct cache_ent_info
cur_info(cache_ent_path
, false);
299 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
301 cache_size_b
+= cur_info
.size
;
302 cache_contents
.insert(cur_info
);
306 globfree(&cache_glob
);
308 // grab info for each staphash log file (.log)
309 glob_str
= s
.cache_path
+ "/*/*.log";
310 glob(glob_str
.c_str(), 0, NULL
, &cache_glob
);
311 for (unsigned int i
= 0; i
< cache_glob
.gl_pathc
; i
++)
313 string cache_ent_path
= cache_glob
.gl_pathv
[i
];
314 struct cache_ent_info
cur_info(cache_ent_path
, false);
315 if (cur_info
.size
!= 0 && cur_info
.weight
!= 0)
317 cache_size_b
+= cur_info
.size
;
318 cache_contents
.insert(cur_info
);
322 globfree(&cache_glob
);
324 set
<struct cache_ent_info
>::iterator i
;
325 unsigned long r_cache_size
= cache_size_b
;
326 string removed_dirs
= "";
328 //unlink .ko and .c until the cache size is under the limit
329 for (i
= cache_contents
.begin(); i
!= cache_contents
.end(); ++i
)
331 if ( (r_cache_size
/ 1024 / 1024) < cache_mb_max
) //convert r_cache_size to MiB
334 STAP_PROBE1(stap
, cache__clean
, (i
->path
).c_str());
335 //remove this (*i) cache_entry, add to removed list
337 r_cache_size
-= i
->size
;
338 removed_dirs
+= i
->path
+ ", ";
341 cache_contents
.clear();
343 if (s
.verbose
> 1 && removed_dirs
!= "")
345 //remove trailing ", "
346 removed_dirs
= removed_dirs
.substr(0, removed_dirs
.length() - 2);
347 clog
<< "Cache cleaning successful, removed entries: "
348 << removed_dirs
<< endl
;
354 clog
<< "Cache cleaning skipped, no cache path." << endl
;
358 //Assign a weight for a particular file. A lower weight
359 // will be removed before a higher weight.
360 //TODO: for now use system mtime... later base a
361 // weighting on size, ctime, atime etc..
363 get_file_weight(const string
&path
)
365 time_t dir_mtime
= 0;
366 struct stat dir_stat_info
;
368 if (stat(path
.c_str(), &dir_stat_info
) == 0)
369 //GNU struct stat defines st_atime as st_atim.tv_sec
370 // but it doesnt seem to work properly in practice
371 // so use st_atim.tv_sec -- bad for portability?
372 dir_mtime
= dir_stat_info
.st_mtim
.tv_sec
;
378 cache_ent_info::cache_ent_info(const string
& path
, bool is_module
):
379 path(path
), is_module(is_module
)
383 string mod_path
= path
+ ".ko";
384 string modsgn_path
= path
+ ".ko.sgn";
385 string source_path
= path
+ ".c";
386 string hash_path
= path
+ ".log";
387 size
= get_file_size(mod_path
)
388 + get_file_size(modsgn_path
);
389 + get_file_size(source_path
);
390 + get_file_size(hash_path
);
391 weight
= get_file_weight(mod_path
);
395 size
= get_file_size(path
);
396 weight
= get_file_weight(path
);
402 cache_ent_info::unlink() const
406 string mod_path
= path
+ ".ko";
407 string modsgn_path
= path
+ ".ko.sgn";
408 string source_path
= path
+ ".c";
409 string hash_path
= path
+ ".log";
410 ::unlink(mod_path
.c_str());
411 ::unlink(modsgn_path
.c_str());
412 ::unlink(source_path
.c_str());
413 ::unlink(hash_path
.c_str());
416 ::unlink(path
.c_str());
419 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */