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::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 &)
 
void operator= (LocalFileSystem &)
 
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 586 of file LocalFileSystem.cc.

References initFSList(), and readFSTypes().

587 {
588  if (readFSTypes() < 0)
589  return;
590 
591  if (initFSList() < 0)
592  return;
593 }
int readFSTypes(void)
LocalFileSystem::~LocalFileSystem ( void  )

Free local file system status resources.

Definition at line 596 of file LocalFileSystem.cc.

References alignCSCRings::e, fs_, and i.

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

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

References ecal_dqm_sourceclient-live_cfg::cerr, alignCSCRings::e, findMount(), LocalFileSystem::FSInfo::freespc, i, LocalFileSystem::FSInfo::local, visualization-live-secondInstance_cfg::m, eostools::move(), AlCaHLTBitMon_ParallelJobs::p, fed_dqm_sourceclient-live_cfg::path, query::result, and AlCaHLTBitMon_QueryRunRegistry::string.

Referenced by StorageFactory::setTempDir().

482 {
483  struct stat s;
484  struct statfs sfs;
485  std::ostringstream warningst;
486  warningst << "Cannot use lazy-download because:\n";
487 
488  for (size_t i = 0, e = paths.size(); i < e; ++i)
489  {
490  char *fullpath;
491  const char *inpath = paths[i].c_str();
492  const char *path = inpath;
493 
494  if (*path == '$')
495  {
496  char *p = getenv(path+1);
497  if (p && *p)
498  path = p;
499  else if (! strcmp(path, "$TMPDIR"))
500  path = "/tmp";
501  }
502 
503  if (! (fullpath = realpath(path, 0)))
504  fullpath = strdup(path);
505 
506 #if 0
507  std::cerr /* edm::LogInfo("LocalFileSystem") */
508  << "Checking if '" << fullpath << "', from '"
509  << inpath << "' is valid cache path with "
510  << minFreeSpace << " free space" << std::endl;
511 #endif
512 
513  if (lstat(fullpath, &s) < 0)
514  {
515  int nerr = errno;
516  if (nerr != ENOENT && nerr != EACCES)
517  edm::LogWarning("LocalFileSystem::findCachePath()")
518  << "Cannot lstat('" << fullpath << "', from '"
519  << inpath << "'): " << strerror(nerr) << " (error "
520  << nerr << ")";
521  free(fullpath);
522  continue;
523  }
524 
525  if (statfs(fullpath, &sfs) < 0)
526  {
527  int nerr = errno;
528  edm::LogWarning("LocalFileSystem::findCachePath()")
529  << "Cannot statfs('" << fullpath << "', from '"
530  << inpath << "'): " << strerror(nerr) << " (error "
531  << nerr << ")";
532  free(fullpath);
533  continue;
534  }
535 
536  std::vector<std::string> prev_paths;
537  FSInfo *m = findMount(fullpath, &sfs, &s, prev_paths);
538 #if 0
539  std::cerr /* edm::LogInfo("LocalFileSystem") */
540  << "Candidate '" << fullpath << "': "
541  << "found=" << (m ? 1 : 0)
542  << " local=" << (m && m->local)
543  << " free=" << (m ? m->freespc : 0)
544  << " access=" << access(fullpath, W_OK)
545  << std::endl;
546 #endif
547 
548  if (m
549  && m->local
550  && m->freespc >= minFreeSpace
551  && access(fullpath, W_OK) == 0)
552  {
553  std::string result(fullpath);
554  free(fullpath);
555  return std::make_pair(result,std::string());
556  }
557  else if (m)
558  {
559  if (!m->local)
560  {
561  warningst << "- The mount " << fullpath << " is not local.\n";
562  }
563  else if (m->freespc < minFreeSpace)
564  {
565  warningst << " - The mount at " << fullpath << " has only " << m->freespc << " GB free; a minumum of " << minFreeSpace << " GB is required.\n";
566  }
567  else if (access(fullpath, W_OK))
568  {
569  warningst << " - The process has no permission to write into " << fullpath << "\n";
570  }
571  }
572 
573  free(fullpath);
574  }
575 
576  std::string warning_str = warningst.str();
577  if (warning_str.size())
578  {
579  warning_str = warning_str.substr(0, warning_str.size()-2);
580  }
581 
582  return std::make_pair(std::string(), std::move(warning_str));
583 }
int i
Definition: DBlmapReader.cc:9
tuple result
Definition: query.py:137
def move
Definition: eostools.py:510
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, dir, fs_, i, LocalFileSystem::FSInfo::origin, fed_dqm_sourceclient-live_cfg::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 = 0;
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  size_t fslen = strlen(fs_[i]->dir);
348  if (! strncmp(fs_[i]->dir, path, fslen)
349  && ((fslen == 1 && fs_[i]->dir[0] == '/')
350  || len == fslen || path[fslen] == '/')
351  && (! best || fslen > bestlen))
352  {
353  // Get the file system device and file system ids.
354  if (statFSInfo(fs_[i]) < 0)
355  return 0;
356 
357  // Check the path is on the same device / file system. If this
358  // fails, we found a better prefix match on path, but it's the
359  // wrong device, so reset our idea of the best match: it can't
360  // be the outer mount any more. Not sure this is the right
361  // thing to do with e.g. loop-back or union mounts.
362  if (fs_[i]->dev != s->st_dev || fs_[i]->fstype != sfs->f_type)
363  {
364  best = 0;
365  continue;
366  }
367 
368  // OK this is better than anything else we found so far.
369  best = fs_[i];
370  bestlen = fslen;
371  }
372  }
373  // In the case of a bind mount, try looking again at the source directory.
374  if (best && best->bind && best->origin)
375  {
376  struct stat s2;
377  struct statfs sfs2;
378  char *fullpath = realpath(best->origin, 0);
379 
380  if (! fullpath)
381  fullpath = strdup(best->origin);
382 
383  if (lstat(fullpath, &s2) < 0)
384  {
385  int nerr = errno;
386  edm::LogWarning("LocalFileSystem::findMount()")
387  << "Cannot lstat('" << fullpath << "' alias '"
388  << path << "'): " << strerror(nerr) << " (error "
389  << nerr << ")";
390  free(fullpath);
391  return best;
392  }
393 
394  if (statfs(fullpath, &sfs2) < 0)
395  {
396  int nerr = errno;
397  edm::LogWarning("LocalFileSystem::findMount()")
398  << "Cannot statfs('" << fullpath << "' alias '"
399  << path << "'): " << strerror(nerr) << " (error "
400  << nerr << ")";
401  free(fullpath);
402  return best;
403  }
404 
405  prev_paths.push_back(path);
406  LocalFileSystem::FSInfo *new_best = findMount(fullpath, &sfs2, &s2, prev_paths);
407  return new_best ? new_best : best;
408  }
409 
410  return best;
411 }
int statFSInfo(FSInfo *i) const
int i
Definition: DBlmapReader.cc:9
Information about file systems on this node.
tuple s2
Definition: indexGen.py:106
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_, i, j, LocalFileSystem::FSInfo::local, visualization-live-secondInstance_cfg::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 = strncpy(p += infolen, m->mnt_fsname, fslen);
189  i->type = strncpy(p += fslen, m->mnt_type, typelen);
190  i->dir = strncpy(p += typelen, m->mnt_dir, dirlen);
191  i->origin = strncpy(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 = 0;
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 }
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 214 of file LocalFileSystem.cc.

References fs_, initFSInfo(), and visualization-live-secondInstance_cfg::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 423 of file LocalFileSystem.cc.

References findMount(), LocalFileSystem::FSInfo::local, and visualization-live-secondInstance_cfg::m.

Referenced by StorageFactory::wrapNonLocalFile().

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

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

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 = 0;
82  char *fstype = 0;
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
assert(m_qm.get())
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, LocalFileSystem::FSInfo::fstype, and run_regression::ret.

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 = 1;
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 = 1;
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 = 1;
304  }
305  else if (i->fstype == -1)
306  {
307  errno = ENOENT;
308  ret = -1;
309  }
310 
311  return ret;
312 }
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().