CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
List of all members | Classes | Public Member Functions | Private Member Functions | Private Attributes
LocalFileSystem Class Reference

#include <LocalFileSystem.h>

Classes

struct  FSInfo
 Information about file systems on this node. More...
 

Public Member Functions

std::string findCachePath (const std::vector< std::string > &paths, double minFreeSpace)
 
bool isLocalPath (const std::string &path)
 
void issueWarning ()
 
 LocalFileSystem (void)
 
 ~LocalFileSystem (void)
 

Private Member Functions

FSInfofindMount (const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &)
 
FSInfoinitFSInfo (void *p)
 
int initFSList (void)
 
 LocalFileSystem (LocalFileSystem &)
 
void operator= (LocalFileSystem &)
 
int readFSTypes (void)
 
int statFSInfo (FSInfo *i)
 

Private Attributes

std::vector< FSInfo * > fs_
 
std::vector< std::string > fstypes_
 
std::string unusable_dir_warnings_
 

Detailed Description

Definition at line 10 of file LocalFileSystem.h.

Constructor & Destructor Documentation

LocalFileSystem::LocalFileSystem ( void  )

Initialise local file system status.

Definition at line 591 of file LocalFileSystem.cc.

References initFSList(), and readFSTypes().

592 {
593  if (readFSTypes() < 0)
594  return;
595 
596  if (initFSList() < 0)
597  return;
598 }
int readFSTypes(void)
LocalFileSystem::~LocalFileSystem ( void  )

Free local file system status resources.

Definition at line 601 of file LocalFileSystem.cc.

References alignCSCRings::e, fs_, and i.

602 {
603  for (size_t i = 0, e = fs_.size(); i < e; ++i)
604  free(fs_[i]);
605 }
int i
Definition: DBlmapReader.cc:9
std::vector< FSInfo * > fs_
LocalFileSystem::LocalFileSystem ( LocalFileSystem )
private

Member Function Documentation

std::string LocalFileSystem::findCachePath ( const std::vector< std::string > &  paths,
double  minFreeSpace 
)

Find a writeable directory among paths which is known to be local and has at least minFreeSpace amount of free space in gigabytes.

The paths should contain list of relative or absolute candidate directories. If an entry starts with letter "$" then the value of that environment variable is used instead; if the value is $TMPDIR and the environment variable is empty, "/tmp" is used instead.

Returns the first path in paths which satisfies the criteria, expanded to environment variable value if appropriate, resolved to full absolute path. If no suitable path can be found, returns an empty string.

Does not throw exceptions. If any serious errors occur, the errors are reported as message logger warnings but the actual error is swallowed and the directory concerned is skipped. Non-existent and inaccessible directories are silently ignored without warning.

Definition at line 475 of file LocalFileSystem.cc.

References dtNoiseDBValidation_cfg::cerr, alignCSCRings::e, findMount(), LocalFileSystem::FSInfo::freespc, i, LocalFileSystem::FSInfo::local, contentValuesFiles::m, AlCaHLTBitMon_ParallelJobs::p, cmsHarvester::path, query::result, AlCaHLTBitMon_QueryRunRegistry::string, and unusable_dir_warnings_.

Referenced by StorageFactory::setTempDir().

477 {
478  struct stat s;
479  struct statfs sfs;
480  std::ostringstream warningst;
481  warningst << "Cannot use lazy-download because:\n";
482 
483  for (size_t i = 0, e = paths.size(); i < e; ++i)
484  {
485  char *fullpath;
486  const char *inpath = paths[i].c_str();
487  const char *path = inpath;
488 
489  if (*path == '$')
490  {
491  char *p = getenv(path+1);
492  if (p && *p)
493  path = p;
494  else if (! strcmp(path, "$TMPDIR"))
495  path = "/tmp";
496  }
497 
498  if (! (fullpath = realpath(path, 0)))
499  fullpath = strdup(path);
500 
501 #if 0
502  std::cerr /* edm::LogInfo("LocalFileSystem") */
503  << "Checking if '" << fullpath << "', from '"
504  << inpath << "' is valid cache path with "
505  << minFreeSpace << " free space" << std::endl;
506 #endif
507 
508  if (lstat(fullpath, &s) < 0)
509  {
510  int nerr = errno;
511  if (nerr != ENOENT && nerr != EACCES)
512  edm::LogWarning("LocalFileSystem::findCachePath()")
513  << "Cannot lstat('" << fullpath << "', from '"
514  << inpath << "'): " << strerror(nerr) << " (error "
515  << nerr << ")";
516  free(fullpath);
517  continue;
518  }
519 
520  if (statfs(fullpath, &sfs) < 0)
521  {
522  int nerr = errno;
523  edm::LogWarning("LocalFileSystem::findCachePath()")
524  << "Cannot statfs('" << fullpath << "', from '"
525  << inpath << "'): " << strerror(nerr) << " (error "
526  << nerr << ")";
527  free(fullpath);
528  continue;
529  }
530 
531  std::vector<std::string> prev_paths;
532  FSInfo *m = findMount(fullpath, &sfs, &s, prev_paths);
533 #if 0
534  std::cerr /* edm::LogInfo("LocalFileSystem") */
535  << "Candidate '" << fullpath << "': "
536  << "found=" << (m ? 1 : 0)
537  << " local=" << (m && m->local)
538  << " free=" << (m ? m->freespc : 0)
539  << " access=" << access(fullpath, W_OK)
540  << std::endl;
541 #endif
542 
543  if (m
544  && m->local
545  && m->freespc >= minFreeSpace
546  && access(fullpath, W_OK) == 0)
547  {
548  std::string result(fullpath);
549  free(fullpath);
550  return result;
551  }
552  else if (m)
553  {
554  if (!m->local)
555  {
556  warningst << "- The mount " << fullpath << " is not local.\n";
557  }
558  else if (m->freespc < minFreeSpace)
559  {
560  warningst << " - The mount at " << fullpath << " has only " << m->freespc << " GB free; a minumum of " << minFreeSpace << " GB is required.\n";
561  }
562  else if (access(fullpath, W_OK))
563  {
564  warningst << " - The process has no permission to write into " << fullpath << "\n";
565  }
566  }
567 
568  free(fullpath);
569  }
570 
571  std::string warning_str = warningst.str();
572  if (warning_str.size())
573  {
574  warning_str = warning_str.substr(0, warning_str.size()-2);
575  }
576  unusable_dir_warnings_ = std::move(warning_str);
577 
578  return std::string();
579 }
int i
Definition: DBlmapReader.cc:9
std::string unusable_dir_warnings_
tuple path
else: Piece not in the list, fine.
tuple result
Definition: query.py:137
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &)
LocalFileSystem::FSInfo * LocalFileSystem::findMount ( const char *  path,
struct statfs *  sfs,
struct stat *  s,
std::vector< std::string > &  prev_paths 
)
private

Find the file system path was mounted from. The statfs() and stat() information for path should be in sfs and s, respectively.

Finds currently mounted file system that path is owned by, and returns the FSInfo object for it, or null if no matching live file system can be found. If the return value is non-null, then it is guaranteed path was on that file system.

A null return value is possible for certain paths which are not on any mounted file system (e.g. /dev or /selinux), or if the file system is unavailable or some other way dysfunctional, such as dead nfs mount or filesystem does not implement statfs().

Definition at line 323 of file LocalFileSystem.cc.

References LocalFileSystem::FSInfo::bind, dir, fs_, i, LocalFileSystem::FSInfo::origin, cmsHarvester::path, and statFSInfo().

Referenced by findCachePath(), and isLocalPath().

324 {
325  for (const auto & old_path : prev_paths)
326  {
327  if (!strcmp(old_path.c_str(), path))
328  {
329  edm::LogWarning("LocalFileSystem::findMount()")
330  << "Found a loop in bind mounts; stopping evaluation.";
331  return nullptr;
332  }
333  }
334 
335  FSInfo *best = 0;
336  size_t bestlen = 0;
337  size_t len = strlen(path);
338  for (size_t i = 0; i < fs_.size(); ++i)
339  {
340  // First match simply against the file system path. We don't
341  // touch the file system until the path prefix matches.
342  size_t fslen = strlen(fs_[i]->dir);
343  if (! strncmp(fs_[i]->dir, path, fslen)
344  && ((fslen == 1 && fs_[i]->dir[0] == '/')
345  || len == fslen || path[fslen] == '/')
346  && (! best || fslen > bestlen))
347  {
348  // Get the file system device and file system ids.
349  if (statFSInfo(fs_[i]) < 0)
350  return 0;
351 
352  // Check the path is on the same device / file system. If this
353  // fails, we found a better prefix match on path, but it's the
354  // wrong device, so reset our idea of the best match: it can't
355  // be the outer mount any more. Not sure this is the right
356  // thing to do with e.g. loop-back or union mounts.
357  if (fs_[i]->dev != s->st_dev || fs_[i]->fstype != sfs->f_type)
358  {
359  best = 0;
360  continue;
361  }
362 
363  // OK this is better than anything else we found so far.
364  best = fs_[i];
365  bestlen = fslen;
366  }
367  }
368  // In the case of a bind mount, try looking again at the source directory.
369  if (best->bind && best->origin)
370  {
371  struct stat s2;
372  struct statfs sfs2;
373  char *fullpath = realpath(best->origin, 0);
374 
375  if (! fullpath)
376  fullpath = strdup(best->origin);
377 
378  if (lstat(fullpath, &s2) < 0)
379  {
380  int nerr = errno;
381  edm::LogWarning("LocalFileSystem::findMount()")
382  << "Cannot lstat('" << fullpath << "' alias '"
383  << path << "'): " << strerror(nerr) << " (error "
384  << nerr << ")";
385  free(fullpath);
386  return best;
387  }
388 
389  if (statfs(fullpath, &sfs2) < 0)
390  {
391  int nerr = errno;
392  edm::LogWarning("LocalFileSystem::findMount()")
393  << "Cannot statfs('" << fullpath << "' alias '"
394  << path << "'): " << strerror(nerr) << " (error "
395  << nerr << ")";
396  free(fullpath);
397  return best;
398  }
399 
400  prev_paths.push_back(path);
401  LocalFileSystem::FSInfo *new_best = findMount(fullpath, &sfs2, &s2, prev_paths);
402  return new_best ? new_best : best;
403  }
404 
405  return best;
406 }
int i
Definition: DBlmapReader.cc:9
int statFSInfo(FSInfo *i)
Information about file systems on this node.
tuple s2
Definition: indexGen.py:106
tuple path
else: Piece not in the list, fine.
std::vector< FSInfo * > fs_
dbl *** dir
Definition: mlp_gen.cc:35
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &)
LocalFileSystem::FSInfo * LocalFileSystem::initFSInfo ( void *  arg)
private

Initialise file system description from /etc/mtab info.

This function saves the information from getmntent(), matching the file system type to the known local ones. It only remembers the information from /etc/mtab, so the dev and fstype attributes are not yet valid; call statFSInfo() to fill those in. This avoids touching irrelevant filesystems unnecessarily; the file system may not be fully functional, or partially offline, or just very slow.

Definition at line 142 of file LocalFileSystem.cc.

References LocalFileSystem::FSInfo::bind, LocalFileSystem::FSInfo::checked, LocalFileSystem::FSInfo::dev, LocalFileSystem::FSInfo::dir, LocalFileSystem::FSInfo::freespc, LocalFileSystem::FSInfo::fsname, LocalFileSystem::FSInfo::fstype, fstypes_, i, j, LocalFileSystem::FSInfo::local, contentValuesFiles::m, LocalFileSystem::FSInfo::origin, AlCaHLTBitMon_ParallelJobs::p, and LocalFileSystem::FSInfo::type.

Referenced by initFSList().

143 {
144 #if BSD
145  struct statfs *m = static_cast<struct statfs *>(arg);
146  size_t infolen = sizeof(struct FSInfo);
147  size_t fslen = strlen(m->f_mntfromname) + 1;
148  size_t dirlen = strlen(m->f_mntonname) + 1;
149  size_t typelen = strlen(m->f_fstypename) + 1;
150  size_t totlen = infolen + fslen + dirlen + typelen;
151  FSInfo *i = (FSInfo *) malloc(totlen);
152  char *p = (char *) i;
153  i->fsname = strncpy(p += infolen, m->f_mntfromname, fslen);
154  i->type = strncpy(p += fslen, m->f_fstypename, typelen);
155  i->dir = strncpy(p += typelen, m->f_mntonname, dirlen);
156  i->dev = m->f_fsid.val[0];
157  i->fstype = m->f_type;
158  i->freespc = 0;
159  i->bind = 0;
160  i->origin = nullptr;
161  if (m->f_bsize > 0)
162  {
163  i->freespc = m->f_bavail;
164  i->freespc *= m->f_bsize;
165  i->freespc /= 1024. * 1024. * 1024.;
166  }
167  /* FIXME: This incorrectly says that mounted disk images are local,
168  even if it was mounted from a network server. The alternative is
169  to walk up the device tree using either a) process IORegistry to
170  get the device tree, which lists devices for disk images, and from
171  there translate volume uuid to a mount point; b) parse output from
172  'hdiutil info -plist' to determine image-path / dev-entry map. */
173  i->local = ((m->f_flags & MNT_LOCAL) ? 1 : 0);
174  i->checked = 1;
175  return i;
176 
177 #else // ! BSD
178  mntent *m = static_cast<mntent *>(arg);
179  size_t infolen = sizeof(struct FSInfo);
180  size_t fslen = strlen(m->mnt_fsname) + 1;
181  size_t dirlen = strlen(m->mnt_dir) + 1;
182  size_t typelen = strlen(m->mnt_type) + 1;
183  size_t originlen = strlen(m->mnt_fsname) + 1;
184  size_t totlen = infolen + fslen + dirlen + typelen + originlen;
185  FSInfo *i = (FSInfo *) malloc(totlen);
186  char *p = (char *) i;
187  i->fsname = strncpy(p += infolen, m->mnt_fsname, fslen);
188  i->type = strncpy(p += fslen, m->mnt_type, typelen);
189  i->dir = strncpy(p += typelen, m->mnt_dir, dirlen);
190  i->origin = strncpy(p += dirlen, m->mnt_fsname, originlen);
191  i->dev = -1;
192  i->fstype = -1;
193  i->freespc = 0;
194  i->local = 0;
195  i->checked = 0;
196  i->bind = strstr(m->mnt_opts, "bind") != nullptr;
197 
198  for (size_t j = 0; j < fstypes_.size() && ! i->local; ++j)
199  if (fstypes_[j] == i->type)
200  i->local = 1;
201 #endif // BSD
202 
203  return i;
204 }
int i
Definition: DBlmapReader.cc:9
A arg
Definition: Factorize.h:36
std::vector< std::string > fstypes_
int j
Definition: DBlmapReader.cc:9
int LocalFileSystem::initFSList ( void  )
private

Initialise the list of currently mounted file systems.

Reads /etc/mtab (or equivalent) to determine all currently mounted file systems, and initialises FSInfo structure for them. It does not yet call statFSInfo() on them, so the device and file type ids are not yet complete.

Definition at line 213 of file LocalFileSystem.cc.

References fs_, initFSInfo(), and contentValuesFiles::m.

Referenced by LocalFileSystem().

214 {
215 #if BSD
216  int rc;
217  struct statfs *mtab = 0;
218  if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0)
219  {
220  int nerr = errno;
221  edm::LogWarning("LocalFileSystem::initFSList()")
222  << "getmntinfo() failed: " << strerror(nerr)
223  << " (error " << nerr << ")";
224  return -1;
225  }
226 
227  fs_.reserve(rc);
228  for (int ix = 0; ix < rc; ++ix)
229  fs_.push_back(initFSInfo(&mtab[ix]));
230 
231  free(mtab);
232 #else
233  struct mntent *m;
234  FILE *mtab = setmntent(_PATH_MOUNTED, "r");
235  if (! mtab)
236  {
237  int nerr = errno;
238  edm::LogWarning("LocalFileSystem::initFSList()")
239  << "Cannot read '" << _PATH_MOUNTED << "': "
240  << strerror(nerr) << " (error " << nerr << ")";
241  return -1;
242  }
243 
244  fs_.reserve(20);
245  while ((m = getmntent(mtab)))
246  fs_.push_back(initFSInfo(m));
247 
248  endmntent(mtab);
249 #endif
250 
251  return 0;
252 }
FSInfo * initFSInfo(void *p)
std::vector< FSInfo * > fs_
bool LocalFileSystem::isLocalPath ( const std::string &  path)

Determine if path is on a file system known to be local.

Returns true if the path is definitely known to be local. Returns false otherwise, including when it's not possible to determine anything about the path at all.

Does not throw exceptions. If any errors occur, the errors are reported as message logger warnings but the actual error is swallowed and the function simply returns false.

Definition at line 418 of file LocalFileSystem.cc.

References findMount(), LocalFileSystem::FSInfo::local, and contentValuesFiles::m.

Referenced by StorageFactory::wrapNonLocalFile().

419 {
420  struct stat s;
421  struct statfs sfs;
422  char *fullpath = realpath(path.c_str(), 0);
423 
424  if (! fullpath)
425  fullpath = strdup(path.c_str());
426 
427  if (lstat(fullpath, &s) < 0)
428  {
429  int nerr = errno;
430  edm::LogWarning("LocalFileSystem::isLocalPath()")
431  << "Cannot lstat('" << fullpath << "' alias '"
432  << path << "'): " << strerror(nerr) << " (error "
433  << nerr << ")";
434  free(fullpath);
435  return false;
436  }
437 
438  if (statfs(fullpath, &sfs) < 0)
439  {
440  int nerr = errno;
441  edm::LogWarning("LocalFileSystem::isLocalPath()")
442  << "Cannot statfs('" << fullpath << "' alias '"
443  << path << "'): " << strerror(nerr) << " (error "
444  << nerr << ")";
445  free(fullpath);
446  return false;
447  }
448 
449  std::vector<std::string> prev_paths;
450  FSInfo *m = findMount(fullpath, &sfs, &s, prev_paths);
451  free(fullpath);
452 
453  return m ? m->local : false;
454 }
tuple path
else: Piece not in the list, fine.
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &)
void LocalFileSystem::issueWarning ( )

Definition at line 582 of file LocalFileSystem.cc.

References unusable_dir_warnings_.

Referenced by StorageFactory::wrapNonLocalFile().

583 {
584  if (unusable_dir_warnings_.size())
585  {
586  edm::LogWarning("LocalFileSystem::findCachePath()") << unusable_dir_warnings_;
587  }
588 }
std::string unusable_dir_warnings_
void LocalFileSystem::operator= ( LocalFileSystem )
private
int LocalFileSystem::readFSTypes ( void  )
private

Read /proc/filesystems to determine which filesystems are local, meaning access latency is tolerably small, and operating system buffer cache will likely do a good job at caching file contents and accelerate many small file operations reasonably well.

The /proc list enumerates all filesystems known by the kernel, except a few special ones like /dev and /selinux. The ones marked as "nodev" have unstable device definition, meaning they are some way or another "virtual" file systems. This labeling is used by kernel nfsd to determine which file systems are safe for exporting without help (fixing fsid), and turns out to be close enough to list of file systems that we can consider to be high-speed local, minus a few exceptions. Everything else we consider "remote" or "slow" file systems where application should prefer massive bulk streaming I/O for better performance.

The exceptions to /proc/filesystems list: lustre and fuse file systems are forced to remote status. Everything else like NFS, AFS, GPFS and various cluster-based systems are already remote.

Definition at line 60 of file LocalFileSystem.cc.

References assert(), fstypes_, geometryCSVtoXML::line, and run_regression::ret.

Referenced by LocalFileSystem().

61 {
62  int ret = 0;
63 
64 #if __linux__
65  static const char procfs[] = "/proc/filesystems";
66  FILE *fs = fopen(procfs, "r");
67  if (! fs)
68  {
69  int nerr = errno;
70  edm::LogWarning("LocalFileSystem::readFSTypes()")
71  << "Cannot read '" << procfs << "': "
72  << strerror(nerr) << " (error " << nerr << ")";
73  return -1;
74  }
75 
76  ssize_t nread;
77  int line = 0;
78  while (! feof(fs))
79  {
80  char *type = 0;
81  char *fstype = 0;
82  size_t len = 0;
83  ++line;
84 
85  if ((nread = getdelim(&type, &len, '\t', fs)) == -1 && ! feof(fs))
86  {
87  fprintf(stderr, "%s:%d: %s (%zd; 1)\n",
88  procfs, line, strerror(errno), nread);
89  free(type);
90  ret = -1;
91  break;
92  }
93 
94  if ((nread = getdelim(&fstype, &len, '\n', fs)) == -1 && ! feof(fs))
95  {
96  fprintf(stderr, "%s:%d: %s (%zd; 2)\n",
97  procfs, line, strerror(errno), nread);
98  free(type);
99  free(fstype);
100  ret = -1;
101  break;
102  }
103 
104  if (feof (fs))
105  {
106  free(type);
107  free(fstype);
108  break;
109  }
110 
111  if (! strcmp(type, "nodev\t")
112  || ! strcmp(fstype, "lustre\n")
113  || ! strncmp(fstype, "fuse", 4))
114  {
115  free(type);
116  free(fstype);
117  continue;
118  }
119 
120  assert(nread >= 1);
121  fstype[nread-1] = 0;
122  fstypes_.push_back(fstype);
123  free(fstype);
124  free(type);
125  }
126 
127  fclose(fs);
128 #endif // __linux__
129 
130  return ret;
131 }
type
Definition: HCALResponse.h:21
assert(m_qm.get())
std::vector< std::string > fstypes_
int LocalFileSystem::statFSInfo ( FSInfo i)
private

Figure out file system device and type ids.

Calls stat() and statfs() on the file system to determine device and file system type ids. These are required to determine if two paths are actually on the same file system.

This function can be called any number of times. It only does the file system check the first time the function is called.

Definition at line 263 of file LocalFileSystem.cc.

References LocalFileSystem::FSInfo::checked, LocalFileSystem::FSInfo::dev, LocalFileSystem::FSInfo::dir, LocalFileSystem::FSInfo::freespc, LocalFileSystem::FSInfo::fstype, and run_regression::ret.

Referenced by findMount().

264 {
265  int ret = 0;
266  struct stat s;
267  struct statfs sfs;
268 
269  if (! i->checked)
270  {
271  i->checked = 1;
272  if (lstat(i->dir, &s) < 0)
273  {
274  int nerr = errno;
275  if (nerr != ENOENT && nerr != EACCES)
276  edm::LogWarning("LocalFileSystem::statFSInfo()")
277  << "Cannot lstat('" << i->dir << "'): "
278  << strerror(nerr) << " (error " << nerr << ")";
279  return -1;
280  }
281 
282  if (statfs(i->dir, &sfs) < 0)
283  {
284  int nerr = errno;
285  edm::LogWarning("LocalFileSystem::statFSInfo()")
286  << "Cannot statfs('" << i->dir << "'): "
287  << strerror(nerr) << " (error " << nerr << ")";
288  return -1;
289  }
290 
291  i->dev = s.st_dev;
292  i->fstype = sfs.f_type;
293  if (sfs.f_bsize > 0)
294  {
295  i->freespc = sfs.f_bavail;
296  i->freespc *= sfs.f_bsize;
297  i->freespc /= 1024. * 1024. * 1024.;
298  }
299  }
300  else if (i->fstype == -1)
301  {
302  errno = ENOENT;
303  ret = -1;
304  }
305 
306  return ret;
307 }
int i
Definition: DBlmapReader.cc:9

Member Data Documentation

std::vector<FSInfo *> LocalFileSystem::fs_
private

Definition at line 28 of file LocalFileSystem.h.

Referenced by findMount(), initFSList(), and ~LocalFileSystem().

std::vector<std::string> LocalFileSystem::fstypes_
private

Definition at line 29 of file LocalFileSystem.h.

Referenced by initFSInfo(), and readFSTypes().

std::string LocalFileSystem::unusable_dir_warnings_
private

Definition at line 30 of file LocalFileSystem.h.

Referenced by findCachePath(), and issueWarning().