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

References initFSList(), and readFSTypes().

537 {
538  if (readFSTypes() < 0)
539  return;
540 
541  if (initFSList() < 0)
542  return;
543 }
int readFSTypes(void)
LocalFileSystem::~LocalFileSystem ( void  )

Free local file system status resources.

Definition at line 546 of file LocalFileSystem.cc.

References alignCSCRings::e, fs_, and i.

547 {
548  for (size_t i = 0, e = fs_.size(); i < e; ++i)
549  free(fs_[i]);
550 }
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 421 of file LocalFileSystem.cc.

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

Referenced by StorageFactory::setTempDir().

423 {
424  struct stat s;
425  struct statfs sfs;
426  std::ostringstream warningst;
427  warningst << "Cannot use lazy-download because:\n";
428 
429  for (size_t i = 0, e = paths.size(); i < e; ++i)
430  {
431  char *fullpath;
432  const char *inpath = paths[i].c_str();
433  const char *path = inpath;
434 
435  if (*path == '$')
436  {
437  char *p = getenv(path+1);
438  if (p && *p)
439  path = p;
440  else if (! strcmp(path, "$TMPDIR"))
441  path = "/tmp";
442  }
443 
444  if (! (fullpath = realpath(path, 0)))
445  fullpath = strdup(path);
446 
447 #if 0
448  std::cerr /* edm::LogInfo("LocalFileSystem") */
449  << "Checking if '" << fullpath << "', from '"
450  << inpath << "' is valid cache path with "
451  << minFreeSpace << " free space" << std::endl;
452 #endif
453 
454  if (lstat(fullpath, &s) < 0)
455  {
456  int nerr = errno;
457  if (nerr != ENOENT && nerr != EACCES)
458  edm::LogWarning("LocalFileSystem::findCachePath()")
459  << "Cannot lstat('" << fullpath << "', from '"
460  << inpath << "'): " << strerror(nerr) << " (error "
461  << nerr << ")";
462  free(fullpath);
463  continue;
464  }
465 
466  if (statfs(fullpath, &sfs) < 0)
467  {
468  int nerr = errno;
469  edm::LogWarning("LocalFileSystem::findCachePath()")
470  << "Cannot statfs('" << fullpath << "', from '"
471  << inpath << "'): " << strerror(nerr) << " (error "
472  << nerr << ")";
473  free(fullpath);
474  continue;
475  }
476 
477  FSInfo *m = findMount(fullpath, &sfs, &s);
478 #if 0
479  std::cerr /* edm::LogInfo("LocalFileSystem") */
480  << "Candidate '" << fullpath << "': "
481  << "found=" << (m ? 1 : 0)
482  << " local=" << (m && m->local)
483  << " free=" << (m ? m->freespc : 0)
484  << " access=" << access(fullpath, W_OK)
485  << std::endl;
486 #endif
487 
488  if (m
489  && m->local
490  && m->freespc >= minFreeSpace
491  && access(fullpath, W_OK) == 0)
492  {
493  std::string result(fullpath);
494  free(fullpath);
495  return result;
496  }
497  else if (m)
498  {
499  if (!m->local)
500  {
501  warningst << "- The mount " << fullpath << " is not local.\n";
502  }
503  else if (m->freespc < minFreeSpace)
504  {
505  warningst << " - The mount at " << fullpath << " has only " << m->freespc << " GB free; a minumum of " << minFreeSpace << " GB is required.\n";
506  }
507  else if (access(fullpath, W_OK))
508  {
509  warningst << " - The process has no permission to write into " << fullpath << "\n";
510  }
511  }
512 
513  free(fullpath);
514  }
515 
516  std::string warning_str = warningst.str();
517  if (warning_str.size())
518  {
519  warning_str = warning_str.substr(0, warning_str.size()-2);
520  }
521  unusable_dir_warnings_ = std::move(warning_str);
522 
523  return std::string();
524 }
int i
Definition: DBlmapReader.cc:9
std::string unusable_dir_warnings_
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s)
tuple path
else: Piece not in the list, fine.
tuple result
Definition: query.py:137
LocalFileSystem::FSInfo * LocalFileSystem::findMount ( const char *  path,
struct statfs *  sfs,
struct stat *  s 
)
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 316 of file LocalFileSystem.cc.

References dir, fs_, i, and statFSInfo().

Referenced by findCachePath(), and isLocalPath().

317 {
318  FSInfo *best = 0;
319  size_t bestlen = 0;
320  size_t len = strlen(path);
321  for (size_t i = 0; i < fs_.size(); ++i)
322  {
323  // First match simply against the file system path. We don't
324  // touch the file system until the path prefix matches.
325  size_t fslen = strlen(fs_[i]->dir);
326  if (! strncmp(fs_[i]->dir, path, fslen)
327  && ((fslen == 1 && fs_[i]->dir[0] == '/')
328  || len == fslen || path[fslen] == '/')
329  && (! best || fslen > bestlen))
330  {
331  // Get the file system device and file system ids.
332  if (statFSInfo(fs_[i]) < 0)
333  return 0;
334 
335  // Check the path is on the same device / file system. If this
336  // fails, we found a better prefix match on path, but it's the
337  // wrong device, so reset our idea of the best match: it can't
338  // be the outer mount any more. Not sure this is the right
339  // thing to do with e.g. loop-back or union mounts.
340  if (fs_[i]->dev != s->st_dev || fs_[i]->fstype != sfs->f_type)
341  {
342  best = 0;
343  continue;
344  }
345 
346  // OK this is better than anything else we found so far.
347  best = fs_[i];
348  bestlen = fslen;
349  }
350  }
351 
352  return best;
353 }
int i
Definition: DBlmapReader.cc:9
int statFSInfo(FSInfo *i)
tuple path
else: Piece not in the list, fine.
std::vector< FSInfo * > fs_
dbl *** dir
Definition: mlp_gen.cc:35
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 140 of file LocalFileSystem.cc.

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

Referenced by initFSList().

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

References fs_, initFSInfo(), and m.

Referenced by LocalFileSystem().

207 {
208 #if BSD
209  int rc;
210  struct statfs *mtab = 0;
211  if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0)
212  {
213  int nerr = errno;
214  edm::LogWarning("LocalFileSystem::initFSList()")
215  << "getmntinfo() failed: " << strerror(nerr)
216  << " (error " << nerr << ")";
217  return -1;
218  }
219 
220  fs_.reserve(rc);
221  for (int ix = 0; ix < rc; ++ix)
222  fs_.push_back(initFSInfo(&mtab[ix]));
223 
224  free(mtab);
225 #else
226  struct mntent *m;
227  FILE *mtab = setmntent(_PATH_MOUNTED, "r");
228  if (! mtab)
229  {
230  int nerr = errno;
231  edm::LogWarning("LocalFileSystem::initFSList()")
232  << "Cannot read '" << _PATH_MOUNTED << "': "
233  << strerror(nerr) << " (error " << nerr << ")";
234  return -1;
235  }
236 
237  fs_.reserve(20);
238  while ((m = getmntent(mtab)))
239  fs_.push_back(initFSInfo(m));
240 
241  endmntent(mtab);
242 #endif
243 
244  return 0;
245 }
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 365 of file LocalFileSystem.cc.

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

Referenced by StorageFactory::wrapNonLocalFile().

366 {
367  struct stat s;
368  struct statfs sfs;
369  char *fullpath = realpath(path.c_str(), 0);
370 
371  if (! fullpath)
372  fullpath = strdup(path.c_str());
373 
374  if (lstat(fullpath, &s) < 0)
375  {
376  int nerr = errno;
377  edm::LogWarning("LocalFileSystem::isLocalPath()")
378  << "Cannot lstat('" << fullpath << "' alias '"
379  << path << "'): " << strerror(nerr) << " (error "
380  << nerr << ")";
381  free(fullpath);
382  return false;
383  }
384 
385  if (statfs(fullpath, &sfs) < 0)
386  {
387  int nerr = errno;
388  edm::LogWarning("LocalFileSystem::isLocalPath()")
389  << "Cannot statfs('" << fullpath << "' alias '"
390  << path << "'): " << strerror(nerr) << " (error "
391  << nerr << ")";
392  free(fullpath);
393  return false;
394  }
395 
396  FSInfo *m = findMount(fullpath, &sfs, &s);
397  free(fullpath);
398 
399  return m ? m->local : false;
400 }
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s)
tuple path
else: Piece not in the list, fine.
void LocalFileSystem::issueWarning ( )

Definition at line 527 of file LocalFileSystem.cc.

References unusable_dir_warnings_.

Referenced by StorageFactory::wrapNonLocalFile().

528 {
529  if (unusable_dir_warnings_.size())
530  {
531  edm::LogWarning("LocalFileSystem::findCachePath()") << unusable_dir_warnings_;
532  }
533 }
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 58 of file LocalFileSystem.cc.

References fstypes_, geometryCSVtoXML::line, and run_regression::ret.

Referenced by LocalFileSystem().

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

257 {
258  int ret = 0;
259  struct stat s;
260  struct statfs sfs;
261 
262  if (! i->checked)
263  {
264  i->checked = 1;
265  if (lstat(i->dir, &s) < 0)
266  {
267  int nerr = errno;
268  if (nerr != ENOENT && nerr != EACCES)
269  edm::LogWarning("LocalFileSystem::statFSInfo()")
270  << "Cannot lstat('" << i->dir << "'): "
271  << strerror(nerr) << " (error " << nerr << ")";
272  return -1;
273  }
274 
275  if (statfs(i->dir, &sfs) < 0)
276  {
277  int nerr = errno;
278  edm::LogWarning("LocalFileSystem::statFSInfo()")
279  << "Cannot statfs('" << i->dir << "'): "
280  << strerror(nerr) << " (error " << nerr << ")";
281  return -1;
282  }
283 
284  i->dev = s.st_dev;
285  i->fstype = sfs.f_type;
286  if (sfs.f_bsize > 0)
287  {
288  i->freespc = sfs.f_bavail;
289  i->freespc *= sfs.f_bsize;
290  i->freespc /= 1024. * 1024. * 1024.;
291  }
292  }
293  else if (i->fstype == -1)
294  {
295  errno = ENOENT;
296  ret = -1;
297  }
298 
299  return ret;
300 }
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().