CMS 3D CMS Logo

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::pair< std::string, std::string > findCachePath (const std::vector< std::string > &paths, double minFreeSpace) const
 
bool isLocalPath (const std::string &path) const
 
 LocalFileSystem (void)
 
 ~LocalFileSystem (void)
 

Private Member Functions

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

Private Attributes

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

Detailed Description

Definition at line 11 of file LocalFileSystem.h.

Constructor & Destructor Documentation

LocalFileSystem::LocalFileSystem ( void  )

Initialise local file system status.

Definition at line 592 of file LocalFileSystem.cc.

References initFSList(), and readFSTypes().

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

Free local file system status resources.

Definition at line 602 of file LocalFileSystem.cc.

References MillePedeFileConverter_cfg::e, fs_, and mps_fire::i.

603 {
604  for (size_t i = 0, e = fs_.size(); i < e; ++i)
605  free(fs_[i]);
606 }
std::vector< FSInfo * > fs_
LocalFileSystem::LocalFileSystem ( LocalFileSystem )
privatedelete

Member Function Documentation

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

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 486 of file LocalFileSystem.cc.

References MessageLogger_cfi::cerr, MillePedeFileConverter_cfg::e, findMount(), LocalFileSystem::FSInfo::freespc, mps_fire::i, LocalFileSystem::FSInfo::local, funct::m, eostools::move(), AlCaHLTBitMon_ParallelJobs::p, callgraph::path, mps_fire::result, and AlCaHLTBitMon_QueryRunRegistry::string.

Referenced by StorageFactory::setTempDir().

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

References LocalFileSystem::FSInfo::bind, LocalFileSystem::FSInfo::dev, LocalFileSystem::FSInfo::dir, fs_, mps_fire::i, LocalFileSystem::FSInfo::local, LocalFileSystem::FSInfo::origin, callgraph::path, and statFSInfo().

Referenced by findCachePath(), and isLocalPath().

329 {
330  for (const auto & old_path : prev_paths)
331  {
332  if (!strcmp(old_path.c_str(), path))
333  {
334  edm::LogWarning("LocalFileSystem::findMount()")
335  << "Found a loop in bind mounts; stopping evaluation.";
336  return nullptr;
337  }
338  }
339 
340  FSInfo *best = nullptr;
341  size_t bestlen = 0;
342  size_t len = strlen(path);
343  for (size_t i = 0; i < fs_.size(); ++i)
344  {
345  // First match simply against the file system path. We don't
346  // touch the file system until the path prefix matches.
347  // When we have a path prefix match, check the file system if
348  // we don't have a best match candidate yet, OR
349  // this match is longer (more specific) than the previous best OR
350  // this match is the same length and the previous best isn't local
351  // The final condition handles cases such as '/' that can appear twice
352  // in the file system list, once as 'rootfs' and once as local fs.
353  size_t fslen = strlen(fs_[i]->dir);
354  if (! strncmp(fs_[i]->dir, path, fslen)
355  && ((fslen == 1 && fs_[i]->dir[0] == '/')
356  || len == fslen || path[fslen] == '/')
357  && (! best || fslen > bestlen || (fslen == bestlen && !best->local)))
358  {
359  // Get the file system device and file system ids.
360  if (statFSInfo(fs_[i]) < 0)
361  return nullptr;
362 
363  // Check the path is on the same device / file system. If this
364  // fails, we found a better prefix match on path, but it's the
365  // wrong device, so reset our idea of the best match: it can't
366  // be the outer mount any more. Not sure this is the right
367  // thing to do with e.g. loop-back or union mounts.
368  if (fs_[i]->dev != s->st_dev || fs_[i]->fstype != sfs->f_type)
369  {
370  best = nullptr;
371  continue;
372  }
373 
374  // OK this is better than anything else we found so far.
375  best = fs_[i];
376  bestlen = fslen;
377  }
378  }
379  // In the case of a bind mount, try looking again at the source directory.
380  if (best && best->bind && best->origin)
381  {
382  struct stat s2;
383  struct statfs sfs2;
384  char *fullpath = realpath(best->origin, nullptr);
385 
386  if (! fullpath)
387  fullpath = strdup(best->origin);
388 
389  if (lstat(fullpath, &s2) < 0)
390  {
391  int nerr = errno;
392  edm::LogWarning("LocalFileSystem::findMount()")
393  << "Cannot lstat('" << fullpath << "' alias '"
394  << path << "'): " << strerror(nerr) << " (error "
395  << nerr << ")";
396  free(fullpath);
397  return best;
398  }
399 
400  if (statfs(fullpath, &sfs2) < 0)
401  {
402  int nerr = errno;
403  edm::LogWarning("LocalFileSystem::findMount()")
404  << "Cannot statfs('" << fullpath << "' alias '"
405  << path << "'): " << strerror(nerr) << " (error "
406  << nerr << ")";
407  free(fullpath);
408  return best;
409  }
410 
411  prev_paths.push_back(path);
412  LocalFileSystem::FSInfo *new_best = findMount(fullpath, &sfs2, &s2, prev_paths);
413  return new_best ? new_best : best;
414  }
415 
416  return best;
417 }
int statFSInfo(FSInfo *i) const
Information about file systems on this node.
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 > &) const
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 143 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_, mps_fire::i, LocalFileSystem::FSInfo::local, funct::m, LocalFileSystem::FSInfo::origin, AlCaHLTBitMon_ParallelJobs::p, and LocalFileSystem::FSInfo::type.

Referenced by initFSList().

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

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

Referenced by LocalFileSystem().

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

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 429 of file LocalFileSystem.cc.

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

Referenced by StorageFactory::wrapNonLocalFile().

430 {
431  struct stat s;
432  struct statfs sfs;
433  char *fullpath = realpath(path.c_str(), nullptr);
434 
435  if (! fullpath)
436  fullpath = strdup(path.c_str());
437 
438  if (lstat(fullpath, &s) < 0)
439  {
440  int nerr = errno;
441  edm::LogWarning("LocalFileSystem::isLocalPath()")
442  << "Cannot lstat('" << fullpath << "' alias '"
443  << path << "'): " << strerror(nerr) << " (error "
444  << nerr << ")";
445  free(fullpath);
446  return false;
447  }
448 
449  if (statfs(fullpath, &sfs) < 0)
450  {
451  int nerr = errno;
452  edm::LogWarning("LocalFileSystem::isLocalPath()")
453  << "Cannot statfs('" << fullpath << "' alias '"
454  << path << "'): " << strerror(nerr) << " (error "
455  << nerr << ")";
456  free(fullpath);
457  return false;
458  }
459 
460  std::vector<std::string> prev_paths;
461  FSInfo *m = findMount(fullpath, &sfs, &s, prev_paths);
462  free(fullpath);
463 
464  return m ? m->local : false;
465 }
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &) const
void LocalFileSystem::operator= ( LocalFileSystem )
privatedelete
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 61 of file LocalFileSystem.cc.

References LocalFileSystem::FSInfo::fstype, fstypes_, and mps_splice::line.

Referenced by LocalFileSystem().

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

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

Referenced by findMount().

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

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().