CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cvmfs.cc
Go to the documentation of this file.
1 
22 // TODO(jblomer): the file system root should probably always return 1 for an
23 // inode. See also integration test #23.
24 
25 #define ENOATTR ENODATA
27 #ifndef __STDC_FORMAT_MACROS
28 #define __STDC_FORMAT_MACROS
29 #endif
30 
31 // sys/xattr.h conflicts with linux/xattr.h and needs to be loaded very early
32 #include <sys/xattr.h> // NOLINT
33 
34 #include "cvmfs_config.h"
35 #include "cvmfs.h"
36 
37 #include <dirent.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <google/dense_hash_map>
41 #include <inttypes.h>
42 #include <pthread.h>
43 #include <stddef.h>
44 #include <stdint.h>
45 #include <sys/errno.h>
46 #include <sys/file.h>
47 #include <sys/mount.h>
48 #include <sys/resource.h>
49 #include <sys/stat.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <sys/wait.h>
53 #include <unistd.h>
54 
55 #include <algorithm>
56 #include <cassert>
57 #include <cstdio>
58 #include <cstdlib>
59 #include <cstring>
60 #include <ctime>
61 #include <functional>
62 #include <map>
63 #include <new>
64 #include <string>
65 #include <vector>
66 
67 #include "authz/authz_session.h"
68 #include "auto_umount.h"
69 #include "backoff.h"
70 #include "cache.h"
71 #include "cache_posix.h"
72 #include "cache_stream.h"
73 #include "catalog_mgr_client.h"
74 #include "clientctx.h"
75 #include "compat.h"
76 #include "compression.h"
77 #include "crypto/crypto_util.h"
78 #include "crypto/hash.h"
79 #include "crypto/signature.h"
80 #include "directory_entry.h"
81 #include "duplex_fuse.h"
82 #include "fence.h"
83 #include "fetch.h"
84 #include "file_chunk.h"
85 #include "fuse_inode_gen.h"
86 #include "fuse_remount.h"
87 #include "globals.h"
88 #include "glue_buffer.h"
89 #include "history_sqlite.h"
90 #include "interrupt.h"
91 #include "loader.h"
92 #include "lru_md.h"
93 #include "magic_xattr.h"
94 #include "manifest_fetch.h"
95 #include "monitor.h"
96 #include "mountpoint.h"
97 #include "network/download.h"
98 #include "nfs_maps.h"
99 #include "notification_client.h"
100 #include "options.h"
101 #include "quota_listener.h"
102 #include "quota_posix.h"
103 #include "shortstring.h"
104 #include "sqlitemem.h"
105 #include "sqlitevfs.h"
106 #include "statistics.h"
107 #include "talk.h"
108 #include "telemetry_aggregator.h"
109 #include "tracer.h"
110 #include "util/algorithm.h"
111 #include "util/atomic.h"
112 #include "util/concurrency.h"
113 #include "util/exception.h"
114 #include "util/logging.h"
115 #include "util/platform.h"
116 #include "util/smalloc.h"
117 #include "util/uuid.h"
118 #include "wpad.h"
119 #include "xattr.h"
120 
121 using namespace std; // NOLINT
122 
123 namespace cvmfs {
124 
132 
133 
139  char *buffer;
141  // Not really used anymore. But directory listing needs to be migrated during
142  // hotpatch. If buffer is allocated by smmap, capacity is zero.
143  size_t size;
144  size_t capacity;
145 
146  DirectoryListing() : buffer(NULL), size(0), capacity(0) { }
147 };
148 
151 pid_t pid_ = 0;
154 
155 
156 typedef google::dense_hash_map<uint64_t, DirectoryListing,
160 pthread_mutex_t lock_directory_handles_ = PTHREAD_MUTEX_INITIALIZER;
162 
163 unsigned max_open_files_;
169 bool check_fd_overflow_ = true;
173 const int kNumReservedFd = 512;
177 const unsigned int kMinOpenFiles = 8192;
178 
179 
181  public:
182  explicit FuseInterruptCue(fuse_req_t *r) : req_ptr_(r) { }
183  virtual ~FuseInterruptCue() { }
184  virtual bool IsCanceled() { return fuse_req_interrupted(*req_ptr_); }
185  private:
186  fuse_req_t *req_ptr_;
187 };
188 
195 struct FuseState {
196  FuseState() : version(0), cache_symlinks(false), has_dentry_expire(false) {}
197  unsigned version;
200 };
201 
202 
208 static inline bool IncAndCheckNoOpenFiles() {
209  const int64_t no_open_files = perf::Xadd(file_system_->no_open_files(), 1);
210  if (!check_fd_overflow_)
211  return true;
212  return no_open_files < (static_cast<int>(max_open_files_) - kNumReservedFd);
213 }
214 
215 static inline double GetKcacheTimeout() {
216  if (!fuse_remounter_->IsCaching())
217  return 0.0;
219 }
220 
221 
222 void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode) {
223  *drainout_mode = fuse_remounter_->IsInDrainoutMode();
224  *maintenance_mode = fuse_remounter_->IsInMaintenanceMode();
225 }
226 
227 
228 static bool UseWatchdog() {
229  if (loader_exports_ == NULL || loader_exports_->version < 2) {
230  return true; // spawn watchdog by default
231  // Note: with library versions before 2.1.8 it might not
232  // create stack traces properly in all cases
233  }
234 
236 }
237 
238 std::string PrintInodeGeneration() {
239  return "init-catalog-revision: " +
241  "current-catalog-revision: " +
243  "incarnation: " + StringifyInt(inode_generation_info_.incarnation) + " " +
245  + "\n";
246 }
247 
248 
249 static bool CheckVoms(const fuse_ctx &fctx) {
251  return true;
252  string mreq = mount_point_->membership_req();
253  LogCvmfs(kLogCvmfs, kLogDebug, "Got VOMS authz %s from filesystem "
254  "properties", mreq.c_str());
255 
256  if (fctx.uid == 0)
257  return true;
258 
259  return mount_point_->authz_session_mgr()->IsMemberOf(fctx.pid, mreq);
260 }
261 
263  return dirent.IsRegular() &&
264  (dirent.inode() < mount_point_->catalog_mgr()->GetRootInode());
265 }
266 
268  const catalog::DirectoryEntry &dirent,
269  const shash::Any &hash,
270  const struct stat &info)
271 {
272  if (hash == dirent.checksum())
273  return false;
274  // For chunked files, we don't want to load the full list of chunk hashes
275  // so we only check the last modified timestamp
276  if (dirent.IsChunkedFile() && (info.st_mtime == dirent.mtime()))
277  return false;
278  return true;
279 }
280 
291 static bool FixupOpenInode(const PathString &path,
292  catalog::DirectoryEntry *dirent)
293 {
294  if (!MayBeInPageCacheTracker(*dirent))
295  return false;
296 
297  shash::Any hash_open;
298  struct stat info;
299  bool is_open = mount_point_->page_cache_tracker()->GetInfoIfOpen(
300  dirent->inode(), &hash_open, &info);
301  if (!is_open)
302  return false;
303  if (!HasDifferentContent(*dirent, hash_open, info))
304  return false;
305 
306  // Overwrite dirent with inode from current generation
307  bool found = mount_point_->catalog_mgr()->LookupPath(
308  path, catalog::kLookupDefault, dirent);
309  assert(found);
310 
311  return true;
312 }
313 
314 static bool GetDirentForInode(const fuse_ino_t ino,
315  catalog::DirectoryEntry *dirent)
316 {
317  // Lookup inode in cache
318  if (mount_point_->inode_cache()->Lookup(ino, dirent))
319  return true;
320 
321  // Look in the catalogs in 2 steps: lookup inode->path, lookup path
322  static catalog::DirectoryEntry dirent_negative =
324  // Reset directory entry. If the function returns false and dirent is no
325  // the kDirentNegative, it was an I/O error
326  *dirent = catalog::DirectoryEntry();
327 
329 
330  if (file_system_->IsNfsSource()) {
331  // NFS mode
332  PathString path;
333  bool retval = file_system_->nfs_maps()->GetPath(ino, &path);
334  if (!retval) {
335  *dirent = dirent_negative;
336  return false;
337  }
338  if (catalog_mgr->LookupPath(path, catalog::kLookupDefault, dirent)) {
339  // Fix inodes
340  dirent->set_inode(ino);
341  mount_point_->inode_cache()->Insert(ino, *dirent);
342  return true;
343  }
344  return false; // Not found in catalog or catalog load error
345  }
346 
347  // Non-NFS mode
348  PathString path;
349  if (ino == catalog_mgr->GetRootInode()) {
350  bool retval =
351  catalog_mgr->LookupPath(PathString(), catalog::kLookupDefault, dirent);
352 
354  "GetDirentForInode: Race condition? Not found dirent %s",
355  dirent->name().c_str())) {
356  return false;
357  }
358 
359  dirent->set_inode(ino);
360  mount_point_->inode_cache()->Insert(ino, *dirent);
361  return true;
362  }
363 
365  bool retval = mount_point_->inode_tracker()->FindPath(&inode_ex, &path);
366  if (!retval) {
367  // This may be a retired inode whose stat information is only available
368  // in the page cache tracker because there is still an open file
370  "GetDirentForInode inode lookup failure %" PRId64, ino);
371  *dirent = dirent_negative;
372  // Indicate that the inode was not found in the tracker rather than not
373  // found in the catalog
374  dirent->set_inode(ino);
375  return false;
376  }
377  if (catalog_mgr->LookupPath(path, catalog::kLookupDefault, dirent)) {
378  if (!inode_ex.IsCompatibleFileType(dirent->mode())) {
380  "Warning: inode %" PRId64 " (%s) changed file type",
381  ino, path.c_str());
382  // TODO(jblomer): we detect this issue but let it continue unhandled.
383  // Fix me.
384  }
385 
386  // Fix inodes
387  dirent->set_inode(ino);
388  mount_point_->inode_cache()->Insert(ino, *dirent);
389  return true;
390  }
391 
392  // Can happen after reload of catalogs or on catalog load failure
393  LogCvmfs(kLogCvmfs, kLogDebug, "GetDirentForInode path lookup failure");
394  return false;
395 }
396 
397 
405 static uint64_t GetDirentForPath(const PathString &path,
406  catalog::DirectoryEntry *dirent)
407 {
408  uint64_t live_inode = 0;
409  if (!file_system_->IsNfsSource())
410  live_inode = mount_point_->inode_tracker()->FindInode(path);
411 
412  shash::Md5 md5path(path.GetChars(), path.GetLength());
413  if (mount_point_->md5path_cache()->Lookup(md5path, dirent)) {
414  if (dirent->GetSpecial() == catalog::kDirentNegative)
415  return false;
416  // We may have initially stored the entry with an old inode in the
417  // md5path cache and now should update it with the new one.
418  if (!file_system_->IsNfsSource() && (live_inode != 0))
419  dirent->set_inode(live_inode);
420  return 1;
421  }
422 
424 
425  // Lookup inode in catalog TODO: not twice md5 calculation
426  bool retval;
427  retval = catalog_mgr->LookupPath(path, catalog::kLookupDefault, dirent);
428  if (retval) {
429  if (file_system_->IsNfsSource()) {
430  dirent->set_inode(file_system_->nfs_maps()->GetInode(path));
431  } else if (live_inode != 0) {
432  dirent->set_inode(live_inode);
433  if (FixupOpenInode(path, dirent)) {
435  "content of %s change, replacing inode %" PRIu64 " --> %" PRIu64,
436  path.c_str(), live_inode, dirent->inode());
437  return live_inode;
438  // Do not populate the md5path cache until the inode tracker is fixed
439  }
440  }
441  mount_point_->md5path_cache()->Insert(md5path, *dirent);
442  return 1;
443  }
444 
445  LogCvmfs(kLogCvmfs, kLogDebug, "GetDirentForPath, no entry");
446  // Only insert ENOENT results into negative cache. Otherwise it was an
447  // error loading nested catalogs
448  if (dirent->GetSpecial() == catalog::kDirentNegative)
450  return 0;
451 }
452 
453 
454 static bool GetPathForInode(const fuse_ino_t ino, PathString *path) {
455  // Check the path cache first
456  if (mount_point_->path_cache()->Lookup(ino, path))
457  return true;
458 
459  if (file_system_->IsNfsSource()) {
460  // NFS mode, just a lookup
461  LogCvmfs(kLogCvmfs, kLogDebug, "MISS %d - lookup in NFS maps", ino);
462  if (file_system_->nfs_maps()->GetPath(ino, path)) {
463  mount_point_->path_cache()->Insert(ino, *path);
464  return true;
465  }
466  return false;
467  }
468 
469  if (ino == mount_point_->catalog_mgr()->GetRootInode())
470  return true;
471 
472  LogCvmfs(kLogCvmfs, kLogDebug, "MISS %d - looking in inode tracker", ino);
474  bool retval = mount_point_->inode_tracker()->FindPath(&inode_ex, path);
475 
477  "GetPathForInode: Race condition? "
478  "Inode not found in inode tracker at path %s",
479  path->c_str())) {
480  return false;
481  }
482 
483 
484  mount_point_->path_cache()->Insert(ino, *path);
485  return true;
486 }
487 
488 static void DoTraceInode(const int event,
489  fuse_ino_t ino,
490  const std::string &msg)
491 {
492  PathString path;
493  bool found = GetPathForInode(ino, &path);
494  if (!found) {
496  "Tracing: Could not find path for inode %" PRIu64, uint64_t(ino));
497  mount_point_->tracer()->Trace(event, PathString("@UNKNOWN"), msg);
498  } else {
499  mount_point_->tracer()->Trace(event, path, msg);
500  }
501 }
502 
503 static void inline TraceInode(const int event,
504  fuse_ino_t ino,
505  const std::string &msg)
506 {
507  if (mount_point_->tracer()->IsActive()) DoTraceInode(event, ino, msg);
508 }
509 
515 static void cvmfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) {
517 
519  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
520  FuseInterruptCue ic(&req);
521  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
523 
526 
527  fuse_ino_t parent_fuse = parent;
528  parent = catalog_mgr->MangleInode(parent);
530  "cvmfs_lookup in parent inode: %" PRIu64 " for name: %s",
531  uint64_t(parent), name);
532 
533  PathString path;
534  PathString parent_path;
535  uint64_t live_inode = 0;
537  struct fuse_entry_param result;
538 
539  memset(&result, 0, sizeof(result));
540  double timeout = GetKcacheTimeout();
541  result.attr_timeout = timeout;
542  result.entry_timeout = timeout;
543 
544  // Special NFS lookups: . and ..
545  if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
546  if (GetDirentForInode(parent, &dirent)) {
547  if (strcmp(name, ".") == 0) {
548  goto lookup_reply_positive;
549  } else {
550  // Lookup for ".."
551  if (dirent.inode() == catalog_mgr->GetRootInode()) {
552  dirent.set_inode(1);
553  goto lookup_reply_positive;
554  }
555  if (!GetPathForInode(parent, &parent_path))
556  goto lookup_reply_negative;
557  if (GetDirentForPath(GetParentPath(parent_path), &dirent) > 0)
558  goto lookup_reply_positive;
559  }
560  }
561  // No entry for "." or no entry for ".."
562  if (dirent.GetSpecial() == catalog::kDirentNegative)
563  goto lookup_reply_negative;
564  else
565  goto lookup_reply_error;
566  assert(false);
567  }
568 
569  if (!GetPathForInode(parent, &parent_path)) {
570  LogCvmfs(kLogCvmfs, kLogDebug, "no path for parent inode found");
571  goto lookup_reply_negative;
572  }
573 
574  path.Assign(parent_path);
575  path.Append("/", 1);
576  path.Append(name, strlen(name));
577  mount_point_->tracer()->Trace(Tracer::kEventLookup, path, "lookup()");
578  live_inode = GetDirentForPath(path, &dirent);
579  if (live_inode == 0) {
580  if (dirent.GetSpecial() == catalog::kDirentNegative)
581  goto lookup_reply_negative;
582  else
583  goto lookup_reply_error;
584  }
585 
586  lookup_reply_positive:
587  if (!file_system_->IsNfsSource()) {
588  if (live_inode > 1) {
589  // live inode is stale (open file), we replace it
590  assert(dirent.IsRegular());
591  assert(dirent.inode() != live_inode);
592  // The new inode is put in the tracker with refcounter == 0
593  bool replaced = mount_point_->inode_tracker()->ReplaceInode(
594  live_inode, glue::InodeEx(dirent.inode(), dirent.mode()));
595  if (replaced)
597  }
599  glue::InodeEx(dirent.inode(), dirent.mode()), path);
600  }
601  // We do _not_ track (and evict) positive replies; among other things, test
602  // 076 fails with the following line uncommented
603  //
604  // WARNING! ENABLING THIS BREAKS ANY TYPE OF MOUNTPOINT POINTING TO THIS INODE
605  //
606  // only safe if fuse_expire_entry is available
608  || (mount_point_->cache_symlinks() && dirent.IsLink())) {
609  LogCvmfs(kLogCache, kLogDebug, "Dentry to evict: %s", name);
610  mount_point_->dentry_tracker()->Add(parent_fuse, name,
611  static_cast<uint64_t>(timeout));
612  }
613 
615  result.ino = dirent.inode();
616  result.attr = dirent.GetStatStructure();
617  fuse_reply_entry(req, &result);
618  return;
619 
620  lookup_reply_negative:
621  // Will be a no-op if there is no fuse cache eviction
622  mount_point_->dentry_tracker()->Add(parent_fuse, name, uint64_t(timeout));
625  result.ino = 0;
626  fuse_reply_entry(req, &result);
627  return;
628 
629  lookup_reply_error:
631 
632  LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr, "EIO (01) on %s", name);
635 
636  fuse_reply_err(req, EIO);
637 }
638 
639 
643 static void cvmfs_forget(
644  fuse_req_t req,
645  fuse_ino_t ino,
646 #if CVMFS_USE_LIBFUSE == 2
647  unsigned long nlookup // NOLINT
648 #else
649  uint64_t nlookup
650 #endif
651 ) {
653 
655 
656  // The libfuse high-level library does the same
657  if (ino == FUSE_ROOT_ID) {
658  fuse_reply_none(req);
659  return;
660  }
661 
663  ino = mount_point_->catalog_mgr()->MangleInode(ino);
664  // This has been seen to deadlock on the debug log mutex on SL5. Problem of
665  // old kernel/fuse?
666 #if CVMFS_USE_LIBCVMFS == 2
667  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %u",
668  uint64_t(ino), nlookup);
669 #else
670  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %" PRIu64,
671  uint64_t(ino), nlookup);
672 #endif
673  if (!file_system_->IsNfsSource()) {
674  bool removed =
675  mount_point_->inode_tracker()->GetVfsPutRaii().VfsPut(ino, nlookup);
676  if (removed)
678  }
680  fuse_reply_none(req);
681 }
682 
683 
684 #if (FUSE_VERSION >= 29)
685 static void cvmfs_forget_multi(
686  fuse_req_t req,
687  size_t count,
688  struct fuse_forget_data *forgets
689 ) {
691 
693  if (file_system_->IsNfsSource()) {
694  fuse_reply_none(req);
695  return;
696  }
697 
699  {
700  glue::InodeTracker::VfsPutRaii vfs_put_raii =
704  for (size_t i = 0; i < count; ++i) {
705  if (forgets[i].ino == FUSE_ROOT_ID) {
706  continue;
707  }
708 
709  uint64_t ino = mount_point_->catalog_mgr()->MangleInode(forgets[i].ino);
710  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %" PRIu64,
711  ino, forgets[i].nlookup);
712 
713  bool removed = vfs_put_raii.VfsPut(ino, forgets[i].nlookup);
714  if (removed)
715  evict_raii.Evict(ino);
716  }
717  }
719 
720  fuse_reply_none(req);
721 }
722 #endif // FUSE_VERSION >= 29
723 
724 
731 static void ReplyNegative(const catalog::DirectoryEntry &dirent,
732  fuse_req_t req)
733 {
734  if (dirent.GetSpecial() == catalog::kDirentNegative) {
735  fuse_reply_err(req, ENOENT);
736  } else {
737  const char * name = dirent.name().c_str();
738  const char * link = dirent.symlink().c_str();
739 
741  "EIO (02) name=%s symlink=%s",
742  name ? name: "<unset>",
743  link ? link: "<unset>");
744 
747  fuse_reply_err(req, EIO);
748  }
749 }
750 
751 
755 static void cvmfs_getattr(fuse_req_t req, fuse_ino_t ino,
756  struct fuse_file_info *fi)
757 {
759 
761  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
762  FuseInterruptCue ic(&req);
763  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
765 
767  ino = mount_point_->catalog_mgr()->MangleInode(ino);
768  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_getattr (stat) for inode: %" PRIu64,
769  uint64_t(ino));
770 
771  if (!CheckVoms(*fuse_ctx)) {
773  fuse_reply_err(req, EACCES);
774  return;
775  }
777  bool found = GetDirentForInode(ino, &dirent);
778  TraceInode(Tracer::kEventGetAttr, ino, "getattr()");
779  if ((!found && (dirent.inode() == ino)) || MayBeInPageCacheTracker(dirent)) {
780  // Serve retired inode from page cache tracker; even if we find it in the
781  // catalog, we replace the dirent by the page cache tracker version to
782  // not confuse open file handles
783  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_getattr %" PRIu64 " "
784  "served from page cache tracker", ino);
785  shash::Any hash;
786  struct stat info;
787  bool is_open =
788  mount_point_->page_cache_tracker()->GetInfoIfOpen(ino, &hash, &info);
789  if (is_open) {
791  if (found && HasDifferentContent(dirent, hash, info)) {
792  // We should from now on provide the new inode information instead
793  // of the stale one. To this end, we need to invalidate the dentry to
794  // trigger a fresh LOOKUP call
795  uint64_t parent_ino;
796  NameString name;
798  dirent.inode(), &parent_ino, &name))
799  {
800  fuse_remounter_->InvalidateDentry(parent_ino, name);
801  }
803  }
804  fuse_reply_attr(req, &info, GetKcacheTimeout());
805  return;
806  }
807  }
809 
810  if (!found) {
811  ReplyNegative(dirent, req);
812  return;
813  }
814 
815  struct stat info = dirent.GetStatStructure();
816 
817  fuse_reply_attr(req, &info, GetKcacheTimeout());
818 }
819 
820 
824 static void cvmfs_readlink(fuse_req_t req, fuse_ino_t ino) {
826 
828  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
829  FuseInterruptCue ic(&req);
830  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
831 
833  ino = mount_point_->catalog_mgr()->MangleInode(ino);
834  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_readlink on inode: %" PRIu64,
835  uint64_t(ino));
836 
838  const bool found = GetDirentForInode(ino, &dirent);
839  TraceInode(Tracer::kEventReadlink, ino, "readlink()");
841 
842  if (!found) {
843  ReplyNegative(dirent, req);
844  return;
845  }
846 
847  if (!dirent.IsLink()) {
848  fuse_reply_err(req, EINVAL);
849  return;
850  }
851 
852  fuse_reply_readlink(req, dirent.symlink().c_str());
853 }
854 
855 
856 static void AddToDirListing(const fuse_req_t req,
857  const char *name, const struct stat *stat_info,
858  BigVector<char> *listing)
859 {
860  LogCvmfs(kLogCvmfs, kLogDebug, "Add to listing: %s, inode %" PRIu64,
861  name, uint64_t(stat_info->st_ino));
862  size_t remaining_size = listing->capacity() - listing->size();
863  const size_t entry_size = fuse_add_direntry(req, NULL, 0, name, stat_info, 0);
864 
865  while (entry_size > remaining_size) {
866  listing->DoubleCapacity();
867  remaining_size = listing->capacity() - listing->size();
868  }
869 
870  char *buffer;
871  bool large_alloc;
872  listing->ShareBuffer(&buffer, &large_alloc);
873  fuse_add_direntry(req, buffer + listing->size(),
874  remaining_size, name, stat_info,
875  listing->size() + entry_size);
876  listing->SetSize(listing->size() + entry_size);
877 }
878 
879 
883 static void cvmfs_opendir(fuse_req_t req, fuse_ino_t ino,
884  struct fuse_file_info *fi)
885 {
887 
888  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
889  FuseInterruptCue ic(&req);
890  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
892 
895  ino = catalog_mgr->MangleInode(ino);
896  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_opendir on inode: %" PRIu64,
897  uint64_t(ino));
898  if (!CheckVoms(*fuse_ctx)) {
900  fuse_reply_err(req, EACCES);
901  return;
902  }
903 
904  TraceInode(Tracer::kEventOpenDir, ino, "opendir()");
905  PathString path;
907  bool found = GetPathForInode(ino, &path);
908  if (!found) {
910  fuse_reply_err(req, ENOENT);
911  return;
912  }
913  found = GetDirentForInode(ino, &d);
914 
915  if (!found) {
917  ReplyNegative(d, req);
918  return;
919  }
920  if (!d.IsDirectory()) {
922  fuse_reply_err(req, ENOTDIR);
923  return;
924  }
925 
926  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_opendir on inode: %" PRIu64 ", path %s",
927  uint64_t(ino), path.c_str());
928 
929  // Build listing
930  BigVector<char> fuse_listing(512);
931 
932  // Add current directory link
933  struct stat info;
934  info = d.GetStatStructure();
935  AddToDirListing(req, ".", &info, &fuse_listing);
936 
937  // Add parent directory link
939  if (d.inode() != catalog_mgr->GetRootInode() &&
940  (GetDirentForPath(GetParentPath(path), &p) > 0))
941  {
942  info = p.GetStatStructure();
943  AddToDirListing(req, "..", &info, &fuse_listing);
944  }
945 
946  // Add all names
947  catalog::StatEntryList listing_from_catalog;
948  bool retval = catalog_mgr->ListingStat(path, &listing_from_catalog);
949 
950  if (!retval) {
952  fuse_listing.Clear(); // Buffer is shared, empty manually
953 
955  "EIO (03) on %s", path.c_str());
958  fuse_reply_err(req, EIO);
959  return;
960  }
961  for (unsigned i = 0; i < listing_from_catalog.size(); ++i) {
962  // Fix inodes
963  PathString entry_path;
964  entry_path.Assign(path);
965  entry_path.Append("/", 1);
966  entry_path.Append(listing_from_catalog.AtPtr(i)->name.GetChars(),
967  listing_from_catalog.AtPtr(i)->name.GetLength());
968 
969  catalog::DirectoryEntry entry_dirent;
970  if (!GetDirentForPath(entry_path, &entry_dirent)) {
971  LogCvmfs(kLogCvmfs, kLogDebug, "listing entry %s vanished, skipping",
972  entry_path.c_str());
973  continue;
974  }
975 
976  struct stat fixed_info = listing_from_catalog.AtPtr(i)->info;
977  fixed_info.st_ino = entry_dirent.inode();
978  AddToDirListing(req, listing_from_catalog.AtPtr(i)->name.c_str(),
979  &fixed_info, &fuse_listing);
980  }
982 
983  DirectoryListing stream_listing;
984  stream_listing.size = fuse_listing.size();
985  stream_listing.capacity = fuse_listing.capacity();
986  bool large_alloc;
987  fuse_listing.ShareBuffer(&stream_listing.buffer, &large_alloc);
988  if (large_alloc)
989  stream_listing.capacity = 0;
990 
991  // Save the directory listing and return a handle to the listing
992  {
995  "linking directory handle %d to dir inode: %" PRIu64,
996  next_directory_handle_, uint64_t(ino));
997  (*directory_handles_)[next_directory_handle_] = stream_listing;
998  fi->fh = next_directory_handle_;
1000  }
1003 
1004 #if (FUSE_VERSION >= 30)
1005 #ifdef CVMFS_ENABLE_FUSE3_CACHE_READDIR
1006  // This affects only reads on the same open directory handle (e.g. multiple
1007  // reads with rewinddir() between them). A new opendir on the same directory
1008  // will trigger readdir calls independently of this setting.
1009  fi->cache_readdir = 1;
1010 #endif
1011 #endif
1012  fuse_reply_open(req, fi);
1013 }
1014 
1015 
1019 static void cvmfs_releasedir(fuse_req_t req, fuse_ino_t ino,
1020  struct fuse_file_info *fi)
1021 {
1023 
1024  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1025  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_releasedir on inode %" PRIu64
1026  ", handle %d", uint64_t(ino), fi->fh);
1027 
1028  int reply = 0;
1029 
1030  {
1032  DirectoryHandles::iterator iter_handle = directory_handles_->find(fi->fh);
1033  if (iter_handle != directory_handles_->end()) {
1034  if (iter_handle->second.capacity == 0)
1035  smunmap(iter_handle->second.buffer);
1036  else
1037  free(iter_handle->second.buffer);
1038  directory_handles_->erase(iter_handle);
1040  } else {
1041  reply = EINVAL;
1042  }
1043  }
1044 
1045  fuse_reply_err(req, reply);
1046 }
1047 
1048 
1052 static void ReplyBufferSlice(const fuse_req_t req, const char *buffer,
1053  const size_t buffer_size, const off_t offset,
1054  const size_t max_size)
1055 {
1056  if (offset < static_cast<int>(buffer_size)) {
1057  fuse_reply_buf(req, buffer + offset,
1058  std::min(static_cast<size_t>(buffer_size - offset), max_size));
1059  } else {
1060  fuse_reply_buf(req, NULL, 0);
1061  }
1062 }
1063 
1064 
1068 static void cvmfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1069  off_t off, struct fuse_file_info *fi)
1070 {
1072 
1074  "cvmfs_readdir on inode %" PRIu64 " reading %d bytes from offset %d",
1075  uint64_t(mount_point_->catalog_mgr()->MangleInode(ino)), size, off);
1076 
1077  DirectoryListing listing;
1078 
1080  DirectoryHandles::const_iterator iter_handle =
1081  directory_handles_->find(fi->fh);
1082  if (iter_handle != directory_handles_->end()) {
1083  listing = iter_handle->second;
1084 
1085  ReplyBufferSlice(req, listing.buffer, listing.size, off, size);
1086  return;
1087  }
1088 
1089  fuse_reply_err(req, EINVAL);
1090 }
1091 
1093  struct fuse_file_info *fi)
1094 {
1096  fi->keep_cache = od.keep_cache;
1097  fi->direct_io = od.direct_io;
1098  if (fi->direct_io)
1100 }
1101 
1102 
1103 #ifdef __APPLE__
1104 // On macOS, xattr on a symlink opens and closes the file (with O_SYMLINK)
1105 // around the actual getxattr call. In order to not run into an I/O error
1106 // we use a special file handle for symlinks, from which one cannot read.
1107 static const uint64_t kFileHandleIgnore = static_cast<uint64_t>(2) << 60;
1108 #endif
1109 
1116 static void cvmfs_open(fuse_req_t req, fuse_ino_t ino,
1117  struct fuse_file_info *fi)
1118 {
1120 
1121  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1122  FuseInterruptCue ic(&req);
1123  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
1124  fuse_remounter_->fence()->Enter();
1126  ino = catalog_mgr->MangleInode(ino);
1127  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_open on inode: %" PRIu64,
1128  uint64_t(ino));
1129 
1130  int fd = -1;
1131  catalog::DirectoryEntry dirent;
1132  PathString path;
1133 
1134  bool found = GetPathForInode(ino, &path);
1135  if (!found) {
1136  fuse_remounter_->fence()->Leave();
1137  fuse_reply_err(req, ENOENT);
1138  return;
1139  }
1140  found = GetDirentForInode(ino, &dirent);
1141  if (!found) {
1142  fuse_remounter_->fence()->Leave();
1143  ReplyNegative(dirent, req);
1144  return;
1145  }
1146 
1147  if (!CheckVoms(*fuse_ctx)) {
1148  fuse_remounter_->fence()->Leave();
1149  fuse_reply_err(req, EACCES);
1150  return;
1151  }
1152 
1153  mount_point_->tracer()->Trace(Tracer::kEventOpen, path, "open()");
1154  // Don't check. Either done by the OS or one wants to purposefully work
1155  // around wrong open flags
1156  // if ((fi->flags & 3) != O_RDONLY) {
1157  // fuse_reply_err(req, EROFS);
1158  // return;
1159  // }
1160 #ifdef __APPLE__
1161  if ((fi->flags & O_SHLOCK) || (fi->flags & O_EXLOCK)) {
1162  fuse_remounter_->fence()->Leave();
1163  fuse_reply_err(req, EOPNOTSUPP);
1164  return;
1165  }
1166  if (fi->flags & O_SYMLINK) {
1167  fuse_remounter_->fence()->Leave();
1168  fi->fh = kFileHandleIgnore;
1169  fuse_reply_open(req, fi);
1170  return;
1171  }
1172 #endif
1173  if (fi->flags & O_EXCL) {
1174  fuse_remounter_->fence()->Leave();
1175  fuse_reply_err(req, EEXIST);
1176  return;
1177  }
1178 
1179  perf::Inc(file_system_->n_fs_open()); // Count actual open / fetch operations
1180 
1182  if (!dirent.IsChunkedFile()) {
1183  if (dirent.IsDirectIo()) {
1184  open_directives = mount_point_->page_cache_tracker()->OpenDirect();
1185  } else {
1186  open_directives =
1188  ino, dirent.checksum(), dirent.GetStatStructure());
1189  }
1190  fuse_remounter_->fence()->Leave();
1191  } else {
1193  "chunked file %s opened (download delayed to read() call)",
1194  path.c_str());
1195 
1196  if (!IncAndCheckNoOpenFiles()) {
1198  fuse_remounter_->fence()->Leave();
1199  LogCvmfs(kLogCvmfs, kLogSyslogErr, "open file descriptor limit exceeded");
1200  fuse_reply_err(req, EMFILE);
1201  return;
1202  }
1203 
1204  // Figure out unique inode from annotated catalog
1205  // TODO(jblomer): we only need to lookup if the inode is not from the
1206  // current generation
1207  catalog::DirectoryEntry dirent_origin;
1208  if (!catalog_mgr->LookupPath(path, catalog::kLookupDefault,
1209  &dirent_origin)) {
1210  fuse_remounter_->fence()->Leave();
1212  "chunked file %s vanished unexpectedly", path.c_str());
1213  fuse_reply_err(req, ENOENT);
1214  return;
1215  }
1216  const uint64_t unique_inode = dirent_origin.inode();
1217 
1218  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1219  chunk_tables->Lock();
1220  if (!chunk_tables->inode2chunks.Contains(unique_inode)) {
1221  chunk_tables->Unlock();
1222 
1223  // Retrieve File chunks from the catalog
1225  if (!catalog_mgr->ListFileChunks(path, dirent.hash_algorithm(),
1226  chunks.weak_ref()) ||
1227  chunks->IsEmpty())
1228  {
1229  fuse_remounter_->fence()->Leave();
1231  "EIO (04) file %s is marked as 'chunked', but no chunks found.",
1232  path.c_str());
1235  fuse_reply_err(req, EIO);
1236  return;
1237  }
1238  fuse_remounter_->fence()->Leave();
1239 
1240  chunk_tables->Lock();
1241  // Check again to avoid race
1242  if (!chunk_tables->inode2chunks.Contains(unique_inode)) {
1243  chunk_tables->inode2chunks.Insert(
1244  unique_inode, FileChunkReflist(chunks.Release(), path,
1245  dirent.compression_algorithm(),
1246  dirent.IsExternalFile()));
1247  chunk_tables->inode2references.Insert(unique_inode, 1);
1248  } else {
1249  uint32_t refctr;
1250  bool retval =
1251  chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1252  assert(retval);
1253  chunk_tables->inode2references.Insert(unique_inode, refctr+1);
1254  }
1255  } else {
1256  fuse_remounter_->fence()->Leave();
1257  uint32_t refctr;
1258  bool retval =
1259  chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1260  assert(retval);
1261  chunk_tables->inode2references.Insert(unique_inode, refctr+1);
1262  }
1263 
1264  // Update the chunk handle list
1266  "linking chunk handle %d to unique inode: %" PRIu64,
1267  chunk_tables->next_handle, uint64_t(unique_inode));
1268  chunk_tables->handle2fd.Insert(chunk_tables->next_handle, ChunkFd());
1269  chunk_tables->handle2uniqino.Insert(chunk_tables->next_handle,
1270  unique_inode);
1271 
1272  // Generate artificial content hash as hash over chunk hashes
1273  // TODO(jblomer): we may want to cache the result in the chunk tables
1274  FileChunkReflist chunk_reflist;
1275  bool retval =
1276  chunk_tables->inode2chunks.Lookup(unique_inode, &chunk_reflist);
1277  assert(retval);
1278 
1279  fi->fh = chunk_tables->next_handle;
1280  if (dirent.IsDirectIo()) {
1281  open_directives = mount_point_->page_cache_tracker()->OpenDirect();
1282  } else {
1283  open_directives = mount_point_->page_cache_tracker()->Open(
1284  ino, chunk_reflist.HashChunkList(), dirent.GetStatStructure());
1285  }
1286  FillOpenFlags(open_directives, fi);
1287  fi->fh = static_cast<uint64_t>(-static_cast<int64_t>(fi->fh));
1288  ++chunk_tables->next_handle;
1289  chunk_tables->Unlock();
1290 
1291  fuse_reply_open(req, fi);
1292  return;
1293  }
1294 
1295  Fetcher *this_fetcher = dirent.IsExternalFile()
1297  : mount_point_->fetcher();
1298  CacheManager::Label label;
1299  label.path = path.ToString();
1300  label.size = dirent.size();
1301  label.zip_algorithm = dirent.compression_algorithm();
1304  if (dirent.IsExternalFile())
1306  fd =
1307  this_fetcher->Fetch(CacheManager::LabeledObject(dirent.checksum(), label));
1308 
1309  if (fd >= 0) {
1310  if (IncAndCheckNoOpenFiles()) {
1311  LogCvmfs(kLogCvmfs, kLogDebug, "file %s opened (fd %d)",
1312  path.c_str(), fd);
1313  fi->fh = fd;
1314  FillOpenFlags(open_directives, fi);
1315  fuse_reply_open(req, fi);
1316  return;
1317  } else {
1318  if (file_system_->cache_mgr()->Close(fd) == 0)
1320  LogCvmfs(kLogCvmfs, kLogSyslogErr, "open file descriptor limit exceeded");
1321  fuse_reply_err(req, EMFILE);
1322  return;
1323  }
1324  assert(false);
1325  }
1326 
1327  // fd < 0
1329  "failed to open inode: %" PRIu64 ", CAS key %s, error code %d",
1330  uint64_t(ino), dirent.checksum().ToString().c_str(), errno);
1331  if (errno == EMFILE) {
1332  fuse_reply_err(req, EMFILE);
1333  return;
1334  }
1335 
1337 
1339  if (EIO == errno || EIO == -fd) {
1341  "EIO (06) on %s", path.c_str() );
1344  }
1345 
1346  fuse_reply_err(req, -fd);
1347 }
1348 
1349 
1353 static void cvmfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1354  struct fuse_file_info *fi)
1355 {
1357 
1359  "cvmfs_read inode: %" PRIu64 " reading %d bytes from offset %d "
1360  "fd %d", uint64_t(mount_point_->catalog_mgr()->MangleInode(ino)),
1361  size, off, fi->fh);
1363 
1364 #ifdef __APPLE__
1365  if (fi->fh == kFileHandleIgnore) {
1366  fuse_reply_err(req, EBADF);
1367  return;
1368  }
1369 #endif
1370 
1371  // Get data chunk (<=128k guaranteed by Fuse)
1372  char *data = static_cast<char *>(alloca(size));
1373  unsigned int overall_bytes_fetched = 0;
1374 
1375  int64_t fd = static_cast<int64_t>(fi->fh);
1376  uint64_t abs_fd = (fd < 0) ? -fd : fd;
1378 
1379  // Do we have a a chunked file?
1380  if (fd < 0) {
1381  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1382  FuseInterruptCue ic(&req);
1383  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
1384 
1385  const uint64_t chunk_handle = abs_fd;
1386  uint64_t unique_inode;
1387  ChunkFd chunk_fd;
1388  FileChunkReflist chunks;
1389  bool retval;
1390 
1391  // Fetch unique inode, chunk list and file descriptor
1392  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1393  chunk_tables->Lock();
1394  retval = chunk_tables->handle2uniqino.Lookup(chunk_handle, &unique_inode);
1395  if (!retval) {
1396  LogCvmfs(kLogCvmfs, kLogDebug, "no unique inode, fall back to fuse ino");
1397  unique_inode = ino;
1398  }
1399  retval = chunk_tables->inode2chunks.Lookup(unique_inode, &chunks);
1400  assert(retval);
1401  chunk_tables->Unlock();
1402 
1403  unsigned chunk_idx = chunks.FindChunkIdx(off);
1404 
1405  // Lock chunk handle
1406  pthread_mutex_t *handle_lock = chunk_tables->Handle2Lock(chunk_handle);
1407  MutexLockGuard m(handle_lock);
1408  chunk_tables->Lock();
1409  retval = chunk_tables->handle2fd.Lookup(chunk_handle, &chunk_fd);
1410  assert(retval);
1411  chunk_tables->Unlock();
1412 
1413  // Fetch all needed chunks and read the requested data
1414  off_t offset_in_chunk = off - chunks.list->AtPtr(chunk_idx)->offset();
1415  do {
1416  // Open file descriptor to chunk
1417  if ((chunk_fd.fd == -1) || (chunk_fd.chunk_idx != chunk_idx)) {
1418  if (chunk_fd.fd != -1) file_system_->cache_mgr()->Close(chunk_fd.fd);
1419  Fetcher *this_fetcher = chunks.external_data
1421  : mount_point_->fetcher();
1422  CacheManager::Label label;
1423  label.path = chunks.path.ToString();
1424  label.size = chunks.list->AtPtr(chunk_idx)->size();
1425  label.zip_algorithm = chunks.compression_alg;
1429  if (chunks.external_data) {
1431  label.range_offset = chunks.list->AtPtr(chunk_idx)->offset();
1432  }
1433  chunk_fd.fd = this_fetcher->Fetch(CacheManager::LabeledObject(
1434  chunks.list->AtPtr(chunk_idx)->content_hash(), label));
1435  if (chunk_fd.fd < 0) {
1436  chunk_fd.fd = -1;
1437  chunk_tables->Lock();
1438  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1439  chunk_tables->Unlock();
1440 
1442  "EIO (05) on %s", chunks.path.ToString().c_str() );
1445  fuse_reply_err(req, EIO);
1446  return;
1447  }
1448  chunk_fd.chunk_idx = chunk_idx;
1449  }
1450 
1451  LogCvmfs(kLogCvmfs, kLogDebug, "reading from chunk fd %d",
1452  chunk_fd.fd);
1453  // Read data from chunk
1454  const size_t bytes_to_read = size - overall_bytes_fetched;
1455  const size_t remaining_bytes_in_chunk =
1456  chunks.list->AtPtr(chunk_idx)->size() - offset_in_chunk;
1457  size_t bytes_to_read_in_chunk =
1458  std::min(bytes_to_read, remaining_bytes_in_chunk);
1459  const int64_t bytes_fetched = file_system_->cache_mgr()->Pread(
1460  chunk_fd.fd,
1461  data + overall_bytes_fetched,
1462  bytes_to_read_in_chunk,
1463  offset_in_chunk);
1464 
1465  if (bytes_fetched < 0) {
1466  LogCvmfs(kLogCvmfs, kLogSyslogErr, "read err no %" PRId64 " (%s)",
1467  bytes_fetched, chunks.path.ToString().c_str());
1468  chunk_tables->Lock();
1469  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1470  chunk_tables->Unlock();
1471  if ( EIO == errno || EIO == -bytes_fetched ) {
1473  "EIO (07) on %s", chunks.path.ToString().c_str() );
1476  }
1477  fuse_reply_err(req, -bytes_fetched);
1478  return;
1479  }
1480  overall_bytes_fetched += bytes_fetched;
1481 
1482  // Proceed to the next chunk to keep on reading data
1483  ++chunk_idx;
1484  offset_in_chunk = 0;
1485  } while ((overall_bytes_fetched < size) &&
1486  (chunk_idx < chunks.list->size()));
1487 
1488  // Update chunk file descriptor
1489  chunk_tables->Lock();
1490  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1491  chunk_tables->Unlock();
1492  LogCvmfs(kLogCvmfs, kLogDebug, "released chunk file descriptor %d",
1493  chunk_fd.fd);
1494  } else {
1495  int64_t nbytes = file_system_->cache_mgr()->Pread(abs_fd, data, size, off);
1496  if (nbytes < 0) {
1497  if ( EIO == errno || EIO == -nbytes ) {
1498  PathString path;
1499  bool found = GetPathForInode(ino, &path);
1500  if ( found ) {
1502  "EIO (08) on %s", path.ToString().c_str() );
1503  } else {
1505  "EIO (08) on <unknown inode>");
1506  }
1509  }
1510  fuse_reply_err(req, -nbytes);
1511  return;
1512  }
1513  overall_bytes_fetched = nbytes;
1514  }
1515 
1516  // Push it to user
1517  fuse_reply_buf(req, data, overall_bytes_fetched);
1518  LogCvmfs(kLogCvmfs, kLogDebug, "pushed %d bytes to user",
1519  overall_bytes_fetched);
1520 }
1521 
1522 
1526 static void cvmfs_release(fuse_req_t req, fuse_ino_t ino,
1527  struct fuse_file_info *fi)
1528 {
1530 
1531  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1532  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_release on inode: %" PRIu64,
1533  uint64_t(ino));
1534 
1535 #ifdef __APPLE__
1536  if (fi->fh == kFileHandleIgnore) {
1537  fuse_reply_err(req, 0);
1538  return;
1539  }
1540 #endif
1541 
1542  int64_t fd = static_cast<int64_t>(fi->fh);
1543  uint64_t abs_fd = (fd < 0) ? -fd : fd;
1546  }
1548 
1549  // do we have a chunked file?
1550  if (fd < 0) {
1551  const uint64_t chunk_handle = abs_fd;
1552  LogCvmfs(kLogCvmfs, kLogDebug, "releasing chunk handle %" PRIu64,
1553  chunk_handle);
1554  uint64_t unique_inode;
1555  ChunkFd chunk_fd;
1556  FileChunkReflist chunks;
1557  uint32_t refctr;
1558  bool retval;
1559 
1560  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1561  chunk_tables->Lock();
1562  retval = chunk_tables->handle2uniqino.Lookup(chunk_handle, &unique_inode);
1563  if (!retval) {
1564  LogCvmfs(kLogCvmfs, kLogDebug, "no unique inode, fall back to fuse ino");
1565  unique_inode = ino;
1566  } else {
1567  chunk_tables->handle2uniqino.Erase(chunk_handle);
1568  }
1569  retval = chunk_tables->handle2fd.Lookup(chunk_handle, &chunk_fd);
1570  assert(retval);
1571  chunk_tables->handle2fd.Erase(chunk_handle);
1572 
1573  retval = chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1574  assert(retval);
1575  refctr--;
1576  if (refctr == 0) {
1577  LogCvmfs(kLogCvmfs, kLogDebug, "releasing chunk list for inode %" PRIu64,
1578  uint64_t(unique_inode));
1579  FileChunkReflist to_delete;
1580  retval = chunk_tables->inode2chunks.Lookup(unique_inode, &to_delete);
1581  assert(retval);
1582  chunk_tables->inode2references.Erase(unique_inode);
1583  chunk_tables->inode2chunks.Erase(unique_inode);
1584  delete to_delete.list;
1585  } else {
1586  chunk_tables->inode2references.Insert(unique_inode, refctr);
1587  }
1588  chunk_tables->Unlock();
1589 
1590  if (chunk_fd.fd != -1)
1591  file_system_->cache_mgr()->Close(chunk_fd.fd);
1593  } else {
1594  if (file_system_->cache_mgr()->Close(abs_fd) == 0) {
1596  }
1597  }
1598  fuse_reply_err(req, 0);
1599 }
1600 
1608 static void cvmfs_statfs(fuse_req_t req, fuse_ino_t ino) {
1609  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1610  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_statfs on inode: %" PRIu64,
1611  uint64_t(ino));
1612 
1613  TraceInode(Tracer::kEventStatFs, ino, "statfs()");
1614 
1616 
1617  // Unmanaged cache (no lock needed - statfs is never modified)
1620  {
1621  LogCvmfs(kLogCvmfs, kLogDebug, "QuotaManager does not support statfs");
1622  fuse_reply_statfs(req, (mount_point_->statfs_cache()->info()));
1623  return;
1624  }
1625 
1627 
1628  const uint64_t deadline = *mount_point_->statfs_cache()->expiry_deadline();
1629  struct statvfs *info = mount_point_->statfs_cache()->info();
1630 
1631  // cached version still valid
1632  if ( platform_monotonic_time() < deadline ) {
1634  fuse_reply_statfs(req, info);
1635  return;
1636  }
1637 
1638  uint64_t available = 0;
1639  uint64_t size = file_system_->cache_mgr()->quota_mgr()->GetSize();
1640  uint64_t capacity = file_system_->cache_mgr()->quota_mgr()->GetCapacity();
1641  // Fuse/OS X doesn't like values < 512
1642  info->f_bsize = info->f_frsize = 512;
1643 
1644  if (capacity == (uint64_t)(-1)) {
1645  // Unknown capacity, set capacity = size
1646  info->f_blocks = size / info->f_bsize;
1647  } else {
1648  // Take values from LRU module
1649  info->f_blocks = capacity / info->f_bsize;
1650  available = capacity - size;
1651  }
1652 
1653  info->f_bfree = info->f_bavail = available / info->f_bsize;
1654 
1655  // Inodes / entries
1656  fuse_remounter_->fence()->Enter();
1657  uint64_t all_inodes = mount_point_->catalog_mgr()->all_inodes();
1658  uint64_t loaded_inode = mount_point_->catalog_mgr()->loaded_inodes();
1659  info->f_files = all_inodes;
1660  info->f_ffree = info->f_favail = all_inodes - loaded_inode;
1661  fuse_remounter_->fence()->Leave();
1662 
1666 
1667  fuse_reply_statfs(req, info);
1668 }
1669 
1670 #ifdef __APPLE__
1671 static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1672  size_t size, uint32_t position)
1673 #else
1674 static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1675  size_t size)
1676 #endif
1677 {
1678  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1679  FuseInterruptCue ic(&req);
1680  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
1681 
1682  fuse_remounter_->fence()->Enter();
1684  ino = catalog_mgr->MangleInode(ino);
1686  "cvmfs_getxattr on inode: %" PRIu64 " for xattr: %s",
1687  uint64_t(ino), name);
1688  if (!CheckVoms(*fuse_ctx)) {
1689  fuse_remounter_->fence()->Leave();
1690  fuse_reply_err(req, EACCES);
1691  return;
1692  }
1693  TraceInode(Tracer::kEventGetXAttr, ino, "getxattr()");
1694 
1695  const string attr = name;
1697  const bool found = GetDirentForInode(ino, &d);
1698  bool retval;
1699  XattrList xattrs;
1700 
1701  PathString path;
1702  retval = GetPathForInode(ino, &path);
1703  assert(retval);
1704  if (d.IsLink()) {
1705  catalog::LookupOptions lookup_options = static_cast<catalog::LookupOptions>(
1707  catalog::DirectoryEntry raw_symlink;
1708  retval = catalog_mgr->LookupPath(path, lookup_options, &raw_symlink);
1709  assert(retval);
1710  d.set_symlink(raw_symlink.symlink());
1711  }
1712  if (d.HasXattrs()) {
1713  retval = catalog_mgr->LookupXattrs(path, &xattrs);
1714 
1716  "cvmfs_statfs: Race condition? "
1717  "LookupXattrs did not succeed for path %s",
1718  path.c_str())) {
1719  fuse_remounter_->fence()->Leave();
1720  fuse_reply_err(req, ESTALE);
1721  }
1722  }
1723 
1724  bool magic_xattr_success = true;
1726  attr, path, &d));
1727  if (!magic_xattr.IsNull()) {
1728  magic_xattr_success = magic_xattr->
1729  PrepareValueFencedProtected(fuse_ctx->gid);
1730  }
1731 
1732  fuse_remounter_->fence()->Leave();
1733 
1734  if (!found) {
1735  ReplyNegative(d, req);
1736  return;
1737  }
1738 
1739  if (!magic_xattr_success) {
1740  fuse_reply_err(req, ENOATTR);
1741  return;
1742  }
1743 
1744  string attribute_value;
1745 
1746  if (!magic_xattr.IsNull()) {
1747  attribute_value = magic_xattr->GetValue();
1748  } else {
1749  if (!xattrs.Get(attr, &attribute_value)) {
1750  fuse_reply_err(req, ENOATTR);
1751  return;
1752  }
1753  }
1754 
1755  if (size == 0) {
1756  fuse_reply_xattr(req, attribute_value.length());
1757  } else if (size >= attribute_value.length()) {
1758  fuse_reply_buf(req, &attribute_value[0], attribute_value.length());
1759  } else {
1760  fuse_reply_err(req, ERANGE);
1761  }
1762 }
1763 
1764 
1765 static void cvmfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) {
1766  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1767  FuseInterruptCue ic(&req);
1768  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid, &ic);
1769 
1770  fuse_remounter_->fence()->Enter();
1772  ino = catalog_mgr->MangleInode(ino);
1773  TraceInode(Tracer::kEventListAttr, ino, "listxattr()");
1775  "cvmfs_listxattr on inode: %" PRIu64 ", size %u [visibility %d]",
1776  uint64_t(ino), size,
1778 
1780  const bool found = GetDirentForInode(ino, &d);
1781  XattrList xattrs;
1782  if (d.HasXattrs()) {
1783  PathString path;
1784  bool retval = GetPathForInode(ino, &path);
1785 
1787  "cvmfs_listxattr: Race condition? "
1788  "GetPathForInode did not succeed for ino %lu",
1789  ino)) {
1790  fuse_remounter_->fence()->Leave();
1791  fuse_reply_err(req, ESTALE);
1792  return;
1793  }
1794 
1795  retval = catalog_mgr->LookupXattrs(path, &xattrs);
1797  "cvmfs_listxattr: Race condition? "
1798  "LookupXattrs did not succeed for ino %lu",
1799  ino)) {
1800  fuse_remounter_->fence()->Leave();
1801  fuse_reply_err(req, ESTALE);
1802  return;
1803  }
1804  }
1805  fuse_remounter_->fence()->Leave();
1806 
1807  if (!found) {
1808  ReplyNegative(d, req);
1809  return;
1810  }
1811 
1812  string attribute_list;
1813  attribute_list = mount_point_->magic_xattr_mgr()->GetListString(&d);
1814  attribute_list += xattrs.ListKeysPosix(attribute_list);
1815 
1816  if (size == 0) {
1817  fuse_reply_xattr(req, attribute_list.length());
1818  } else if (size >= attribute_list.length()) {
1819  if (attribute_list.empty())
1820  fuse_reply_buf(req, NULL, 0);
1821  else
1822  fuse_reply_buf(req, &attribute_list[0], attribute_list.length());
1823  } else {
1824  fuse_reply_err(req, ERANGE);
1825  }
1826 }
1827 
1828 bool Evict(const string &path) {
1829  catalog::DirectoryEntry dirent;
1830  fuse_remounter_->fence()->Enter();
1831  const bool found = (GetDirentForPath(PathString(path), &dirent) > 0);
1832 
1833  if (!found || !dirent.IsRegular()) {
1834  fuse_remounter_->fence()->Leave();
1835  return false;
1836  }
1837 
1838  if (!dirent.IsChunkedFile()) {
1839  fuse_remounter_->fence()->Leave();
1840  } else {
1841  FileChunkList chunks;
1843  PathString(path), dirent.hash_algorithm(), &chunks);
1844  fuse_remounter_->fence()->Leave();
1845  for (unsigned i = 0; i < chunks.size(); ++i) {
1847  ->Remove(chunks.AtPtr(i)->content_hash());
1848  }
1849  }
1850  file_system_->cache_mgr()->quota_mgr()->Remove(dirent.checksum());
1851  return true;
1852 }
1853 
1854 
1855 bool Pin(const string &path) {
1856  catalog::DirectoryEntry dirent;
1857  fuse_remounter_->fence()->Enter();
1858  const bool found = (GetDirentForPath(PathString(path), &dirent) > 0);
1859  if (!found || !dirent.IsRegular()) {
1860  fuse_remounter_->fence()->Leave();
1861  return false;
1862  }
1863 
1864  Fetcher *this_fetcher = dirent.IsExternalFile()
1866  : mount_point_->fetcher();
1867 
1868  if (!dirent.IsChunkedFile()) {
1869  fuse_remounter_->fence()->Leave();
1870  } else {
1871  FileChunkList chunks;
1873  PathString(path), dirent.hash_algorithm(), &chunks);
1874  fuse_remounter_->fence()->Leave();
1875  for (unsigned i = 0; i < chunks.size(); ++i) {
1876  bool retval =
1878  chunks.AtPtr(i)->content_hash(),
1879  chunks.AtPtr(i)->size(),
1880  "Part of " + path,
1881  false);
1882  if (!retval)
1883  return false;
1884  int fd = -1;
1885  CacheManager::Label label;
1886  label.path = path;
1887  label.size = chunks.AtPtr(i)->size();
1888  label.zip_algorithm = dirent.compression_algorithm();
1891  if (dirent.IsExternalFile()) {
1893  label.range_offset = chunks.AtPtr(i)->offset();
1894  }
1895  fd = this_fetcher->Fetch(CacheManager::LabeledObject(
1896  chunks.AtPtr(i)->content_hash(), label));
1897  if (fd < 0) {
1898  return false;
1899  }
1900  file_system_->cache_mgr()->Close(fd);
1901  }
1902  return true;
1903  }
1904 
1905  bool retval = file_system_->cache_mgr()->quota_mgr()->Pin(
1906  dirent.checksum(), dirent.size(), path, false);
1907  if (!retval)
1908  return false;
1909  CacheManager::Label label;
1911  label.size = dirent.size();
1912  label.path = path;
1913  label.zip_algorithm = dirent.compression_algorithm();
1914  int fd = this_fetcher->Fetch(
1915  CacheManager::LabeledObject(dirent.checksum(), label));
1916  if (fd < 0) {
1917  return false;
1918  }
1919  file_system_->cache_mgr()->Close(fd);
1920  return true;
1921 }
1922 
1923 
1927 static void cvmfs_init(void *userdata, struct fuse_conn_info *conn) {
1928  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_init");
1929 
1930  // NFS support
1931 #ifdef CVMFS_NFS_SUPPORT
1932  conn->want |= FUSE_CAP_EXPORT_SUPPORT;
1933 #endif
1934 
1935  if (mount_point_->enforce_acls()) {
1936 #ifdef FUSE_CAP_POSIX_ACL
1937  if ((conn->capable & FUSE_CAP_POSIX_ACL) == 0) {
1939  "FUSE: ACL support requested but missing fuse kernel support, "
1940  "aborting");
1941  }
1942  conn->want |= FUSE_CAP_POSIX_ACL;
1943  LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog, "enforcing ACLs");
1944 #else
1946  "FUSE: ACL support requested but not available in this version of "
1947  "libfuse %d, aborting", FUSE_VERSION);
1948 #endif
1949  }
1950 
1951  if ( mount_point_->cache_symlinks() ) {
1952 #ifdef FUSE_CAP_CACHE_SYMLINKS
1953  if ((conn->capable & FUSE_CAP_CACHE_SYMLINKS) == FUSE_CAP_CACHE_SYMLINKS) {
1954  conn->want |= FUSE_CAP_CACHE_SYMLINKS;
1955  LogCvmfs(kLogCvmfs, kLogDebug, "FUSE: Enable symlink caching");
1956  #ifndef FUSE_CAP_EXPIRE_ONLY
1958  "FUSE: Symlink caching enabled but no support for fuse_expire_entry. "
1959  "Symlinks will be cached but mountpoints on top of symlinks will "
1960  "break! "
1961  "Current libfuse %d is too old; required: libfuse >= 3.16, "
1962  "kernel >= 6.2-rc1",
1963  FUSE_VERSION);
1964  #endif
1965  } else {
1968  "FUSE: Symlink caching requested but missing fuse kernel support, "
1969  "falling back to no caching");
1970  }
1971 #else
1974  "FUSE: Symlink caching requested but missing libfuse support, "
1975  "falling back to no caching. Current libfuse %d",
1976  FUSE_VERSION);
1977 #endif
1978  }
1979 
1980 #ifdef FUSE_CAP_EXPIRE_ONLY
1981  if ((conn->capable & FUSE_CAP_EXPIRE_ONLY) == FUSE_CAP_EXPIRE_ONLY &&
1982  FUSE_VERSION >= FUSE_MAKE_VERSION(3, 16)) {
1984  LogCvmfs(kLogCvmfs, kLogDebug, "FUSE: Enable fuse_expire_entry ");
1985  } else if (mount_point_->cache_symlinks()) {
1987  "FUSE: Symlink caching enabled but no support for fuse_expire_entry. "
1988  "Symlinks will be cached but mountpoints on top of symlinks will break! "
1989  "Current libfuse %d; required: libfuse >= 3.16, kernel >= 6.2-rc1",
1990  FUSE_VERSION);
1991  }
1992 #endif
1993 }
1994 
1995 static void cvmfs_destroy(void *unused __attribute__((unused))) {
1996  // The debug log is already closed at this point
1997  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_destroy");
1998 }
1999 
2003 static void SetCvmfsOperations(struct fuse_lowlevel_ops *cvmfs_operations) {
2004  memset(cvmfs_operations, 0, sizeof(*cvmfs_operations));
2005 
2006  // Init/Fini
2007  cvmfs_operations->init = cvmfs_init;
2008  cvmfs_operations->destroy = cvmfs_destroy;
2009 
2010  cvmfs_operations->lookup = cvmfs_lookup;
2011  cvmfs_operations->getattr = cvmfs_getattr;
2012  cvmfs_operations->readlink = cvmfs_readlink;
2013  cvmfs_operations->open = cvmfs_open;
2014  cvmfs_operations->read = cvmfs_read;
2015  cvmfs_operations->release = cvmfs_release;
2016  cvmfs_operations->opendir = cvmfs_opendir;
2017  cvmfs_operations->readdir = cvmfs_readdir;
2018  cvmfs_operations->releasedir = cvmfs_releasedir;
2019  cvmfs_operations->statfs = cvmfs_statfs;
2020  cvmfs_operations->getxattr = cvmfs_getxattr;
2021  cvmfs_operations->listxattr = cvmfs_listxattr;
2022  cvmfs_operations->forget = cvmfs_forget;
2023 #if (FUSE_VERSION >= 29)
2024  cvmfs_operations->forget_multi = cvmfs_forget_multi;
2025 #endif
2026 }
2027 
2028 // Called by cvmfs_talk when switching into read-only cache mode
2030  if (cvmfs::unpin_listener_) {
2032  cvmfs::unpin_listener_ = NULL;
2033  }
2037  }
2038 }
2039 
2040 bool SendFuseFd(const std::string &socket_path) {
2041  int fuse_fd;
2042 #if (FUSE_VERSION >= 30)
2043  fuse_fd = fuse_session_fd(*reinterpret_cast<struct fuse_session**>(
2045 #else
2046  fuse_fd = fuse_chan_fd(*reinterpret_cast<struct fuse_chan**>(
2048 #endif
2049  assert(fuse_fd >= 0);
2050  int sock_fd = ConnectSocket(socket_path);
2051  if (sock_fd < 0) {
2052  LogCvmfs(kLogCvmfs, kLogDebug, "cannot connect to socket %s: %d",
2053  socket_path.c_str(), errno);
2054  return false;
2055  }
2056  bool retval = SendFd2Socket(sock_fd, fuse_fd);
2057  close(sock_fd);
2058  return retval;
2059 }
2060 
2061 } // namespace cvmfs
2062 
2063 
2064 string *g_boot_error = NULL;
2065 
2066 __attribute__((visibility("default")))
2067 loader::CvmfsExports *g_cvmfs_exports = NULL;
2068 
2075 
2076  virtual bool PrepareValueFenced() {
2077  catalogs_valid_until_ = cvmfs::fuse_remounter_->catalogs_valid_until();
2078  return true;
2079  }
2080 
2081  virtual std::string GetValue() {
2082  if (catalogs_valid_until_ == MountPoint::kIndefiniteDeadline) {
2083  return "never (fixed root catalog)";
2084  } else {
2085  time_t now = time(NULL);
2086  return StringifyInt( (catalogs_valid_until_ - now) / 60);
2087  }
2088  }
2089 };
2090 
2092  virtual std::string GetValue() {
2093  return StringifyInt(
2094  cvmfs::inode_generation_info_.inode_generation +
2095  xattr_mgr_->mount_point()->catalog_mgr()->inode_gauge());
2096  }
2097 };
2098 
2100  virtual std::string GetValue() {
2102  }
2103 };
2104 
2106  virtual std::string GetValue() { return StringifyInt(cvmfs::pid_); }
2107 };
2108 
2110  virtual std::string GetValue() {
2111  time_t now = time(NULL);
2112  uint64_t uptime = now - cvmfs::loader_exports_->boot_time;
2113  return StringifyInt(uptime / 60);
2114  }
2115 };
2116 
2121 static void RegisterMagicXattrs() {
2123  mgr->Register("user.expires", new ExpiresMagicXattr());
2124  mgr->Register("user.inode_max", new InodeMaxMagicXattr());
2125  mgr->Register("user.pid", new PidMagicXattr());
2126  mgr->Register("user.maxfd", new MaxFdMagicXattr());
2127  mgr->Register("user.uptime", new UptimeMagicXattr());
2128 
2129  mgr->Freeze();
2130 }
2131 
2137  const string &mount_path,
2138  const string &fqrn,
2140 {
2141  fs_info.wait_workspace = false;
2142  FileSystem *file_system = FileSystem::Create(fs_info);
2143 
2144  if (file_system->boot_status() == loader::kFailLockWorkspace) {
2145  string fqrn_from_xattr;
2146  int retval = platform_getxattr(mount_path, "user.fqrn", &fqrn_from_xattr);
2147  if (!retval) {
2148  // Cvmfs not mounted anymore, but another cvmfs process is still in
2149  // shutdown procedure. Try again and wait for lock
2150  delete file_system;
2151  fs_info.wait_workspace = true;
2152  file_system = FileSystem::Create(fs_info);
2153  } else {
2154  if (fqrn_from_xattr == fqrn) {
2156  "repository already mounted on %s", mount_path.c_str());
2158  } else {
2160  "CernVM-FS repository %s already mounted on %s",
2161  fqrn.c_str(), mount_path.c_str());
2163  }
2164  }
2165  }
2166 
2167  return file_system;
2168 }
2169 
2170 
2171 static void InitOptionsMgr(const loader::LoaderExports *loader_exports) {
2172  if (loader_exports->version >= 3 && loader_exports->simple_options_parsing) {
2174  new DefaultOptionsTemplateManager(loader_exports->repository_name));
2175  } else {
2177  new DefaultOptionsTemplateManager(loader_exports->repository_name));
2178  }
2179 
2180  if (loader_exports->config_files != "") {
2181  vector<string> tokens = SplitString(loader_exports->config_files, ':');
2182  for (unsigned i = 0, s = tokens.size(); i < s; ++i) {
2183  cvmfs::options_mgr_->ParsePath(tokens[i], false);
2184  }
2185  } else {
2187  }
2188 }
2189 
2190 
2191 static unsigned CheckMaxOpenFiles() {
2192  static unsigned max_open_files;
2193  static bool already_done = false;
2194 
2195  // check number of open files (lazy evaluation)
2196  if (!already_done) {
2197  unsigned soft_limit = 0;
2198  unsigned hard_limit = 0;
2199  GetLimitNoFile(&soft_limit, &hard_limit);
2200 
2201  if (soft_limit < cvmfs::kMinOpenFiles) {
2203  "Warning: current limits for number of open files are "
2204  "(%lu/%lu)\n"
2205  "CernVM-FS is likely to run out of file descriptors, "
2206  "set ulimit -n to at least %lu",
2207  soft_limit, hard_limit, cvmfs::kMinOpenFiles);
2208  }
2209  max_open_files = soft_limit;
2210  already_done = true;
2211  }
2212 
2213  return max_open_files;
2214 }
2215 
2216 
2217 static int Init(const loader::LoaderExports *loader_exports) {
2218  g_boot_error = new string("unknown error");
2219  cvmfs::loader_exports_ = loader_exports;
2220 
2222 
2223  InitOptionsMgr(loader_exports);
2224 
2225  // We need logging set up before forking the watchdog
2227  *cvmfs::options_mgr_, loader_exports->repository_name);
2228 
2229  // Monitor, check for maximum number of open files
2230  if (cvmfs::UseWatchdog()) {
2231  auto_umount::SetMountpoint(loader_exports->mount_point);
2233  if (cvmfs::watchdog_ == NULL) {
2234  *g_boot_error = "failed to initialize watchdog.";
2235  return loader::kFailMonitor;
2236  }
2237  }
2239 
2241  fs_info.type = FileSystem::kFsFuse;
2242  fs_info.name = loader_exports->repository_name;
2243  fs_info.exe_path = loader_exports->program_name;
2244  fs_info.options_mgr = cvmfs::options_mgr_;
2245  fs_info.foreground = loader_exports->foreground;
2247  loader_exports->mount_point,
2248  loader_exports->repository_name,
2249  fs_info);
2250  if (!cvmfs::file_system_->IsValid()) {
2252  return cvmfs::file_system_->boot_status();
2253  }
2254  if ((cvmfs::file_system_->cache_mgr()->id() == kPosixCacheManager) &&
2255  dynamic_cast<PosixCacheManager *>(
2256  cvmfs::file_system_->cache_mgr())->do_refcount())
2257  {
2258  cvmfs::check_fd_overflow_ = false;
2259  }
2260 
2263  if (!cvmfs::mount_point_->IsValid()) {
2265  return cvmfs::mount_point_->boot_status();
2266  }
2267 
2269 
2271  cvmfs::directory_handles_->set_empty_key((uint64_t)(-1));
2272  cvmfs::directory_handles_->set_deleted_key((uint64_t)(-2));
2273 
2274  LogCvmfs(kLogCvmfs, kLogDebug, "fuse inode size is %d bits",
2275  sizeof(fuse_ino_t) * 8);
2276 
2281  LogCvmfs(kLogCvmfs, kLogDebug, "root inode is %" PRIu64,
2282  uint64_t(cvmfs::mount_point_->catalog_mgr()->GetRootInode()));
2283 
2284  void **channel_or_session = NULL;
2285  if (loader_exports->version >= 4) {
2286  channel_or_session = loader_exports->fuse_channel_or_session;
2287  }
2288 
2289  bool fuse_notify_invalidation = true;
2290  std::string buf;
2291  if (cvmfs::options_mgr_->GetValue("CVMFS_FUSE_NOTIFY_INVALIDATION",
2292  &buf)) {
2293  if (!cvmfs::options_mgr_->IsOn(buf)) {
2294  fuse_notify_invalidation = false;
2296  }
2297  }
2300  channel_or_session, fuse_notify_invalidation);
2301 
2302  // Control & command interface
2304  cvmfs::mount_point_->talk_socket_path(),
2307  if ((cvmfs::mount_point_->talk_socket_uid() != 0) ||
2308  (cvmfs::mount_point_->talk_socket_gid() != 0))
2309  {
2310  uid_t tgt_uid = cvmfs::mount_point_->talk_socket_uid();
2311  gid_t tgt_gid = cvmfs::mount_point_->talk_socket_gid();
2312  int rvi = chown(cvmfs::mount_point_->talk_socket_path().c_str(),
2313  tgt_uid, tgt_gid);
2314  if (rvi != 0) {
2315  *g_boot_error = std::string("failed to set talk socket ownership - ")
2316  + "target " + StringifyInt(tgt_uid) + ":" + StringifyInt(tgt_uid)
2317  + ", user " + StringifyInt(geteuid()) + ":" + StringifyInt(getegid());
2318  return loader::kFailTalk;
2319  }
2320  }
2321  if (cvmfs::talk_mgr_ == NULL) {
2322  *g_boot_error = "failed to initialize talk socket (" +
2323  StringifyInt(errno) + ")";
2324  return loader::kFailTalk;
2325  }
2326 
2327  // Notification system client
2328  {
2330  if (options->IsDefined("CVMFS_NOTIFICATION_SERVER")) {
2331  std::string config;
2332  options->GetValue("CVMFS_NOTIFICATION_SERVER", &config);
2333  const std::string repo_name = cvmfs::mount_point_->fqrn();
2335  new NotificationClient(config, repo_name, cvmfs::fuse_remounter_,
2336  cvmfs::mount_point_->download_mgr(),
2338  }
2339  }
2340 
2341  return loader::kFailOk;
2342 }
2343 
2344 
2348 static void Spawn() {
2349  // First thing: kick off the watchdog while we still have a single-threaded
2350  // well-defined state
2351  cvmfs::pid_ = getpid();
2352  if (cvmfs::watchdog_) {
2353  cvmfs::watchdog_->Spawn(GetCurrentWorkingDirectory() + "/stacktrace." +
2354  cvmfs::mount_point_->fqrn());
2355  }
2356 
2358  if (cvmfs::mount_point_->dentry_tracker()->is_active()) {
2360  // Usually every minute
2361  static_cast<unsigned int>(cvmfs::mount_point_->kcache_timeout_sec()));
2362  }
2363 
2366  if (cvmfs::mount_point_->resolv_conf_watcher() != NULL) {
2368  }
2370  quota_mgr->Spawn();
2371  if (quota_mgr->HasCapability(QuotaManager::kCapListeners)) {
2373  quota_mgr,
2374  cvmfs::mount_point_->uuid()->uuid() + "-watchdog");
2376  quota_mgr,
2377  cvmfs::mount_point_->catalog_mgr(),
2378  cvmfs::mount_point_->uuid()->uuid() + "-unpin");
2379  }
2382 
2383  if (cvmfs::notification_client_ != NULL) {
2385  }
2386 
2387  if (cvmfs::file_system_->nfs_maps() != NULL) {
2389  }
2390 
2392 
2393  if (cvmfs::mount_point_->telemetry_aggr() != NULL) {
2395  }
2396 }
2397 
2398 
2399 static string GetErrorMsg() {
2400  if (g_boot_error)
2401  return *g_boot_error;
2402  return "";
2403 }
2404 
2405 
2411 static void ShutdownMountpoint() {
2412  delete cvmfs::talk_mgr_;
2413  cvmfs::talk_mgr_ = NULL;
2414 
2417 
2418  // The remonter has a reference to the mount point and the inode generation
2419  delete cvmfs::fuse_remounter_;
2420  cvmfs::fuse_remounter_ = NULL;
2421 
2422  // The unpin listener requires the catalog, so this must be unregistered
2423  // before the catalog manager is removed
2424  if (cvmfs::unpin_listener_ != NULL) {
2426  cvmfs::unpin_listener_ = NULL;
2427  }
2428  if (cvmfs::watchdog_listener_ != NULL) {
2431  }
2432 
2434  delete cvmfs::mount_point_;
2436  cvmfs::mount_point_ = NULL;
2437 }
2438 
2439 
2440 static void Fini() {
2442 
2443  delete cvmfs::file_system_;
2444  delete cvmfs::options_mgr_;
2445  cvmfs::file_system_ = NULL;
2446  cvmfs::options_mgr_ = NULL;
2447 
2448  delete cvmfs::watchdog_;
2449  cvmfs::watchdog_ = NULL;
2450 
2451  delete g_boot_error;
2452  g_boot_error = NULL;
2454 
2456 }
2457 
2458 
2459 static int AltProcessFlavor(int argc, char **argv) {
2460  if (strcmp(argv[1], "__cachemgr__") == 0) {
2461  return PosixQuotaManager::MainCacheManager(argc, argv);
2462  }
2463  if (strcmp(argv[1], "__wpad__") == 0) {
2464  return download::MainResolveProxyDescription(argc, argv);
2465  }
2466  return 1;
2467 }
2468 
2469 
2470 static bool MaintenanceMode(const int fd_progress) {
2471  SendMsg2Socket(fd_progress, "Entering maintenance mode\n");
2472  string msg_progress = "Draining out kernel caches (";
2474  msg_progress += "up to ";
2475  msg_progress += StringifyInt(static_cast<int>(
2476  cvmfs::mount_point_->kcache_timeout_sec())) +
2477  "s)\n";
2478  SendMsg2Socket(fd_progress, msg_progress);
2480  return true;
2481 }
2482 
2483 
2484 static bool SaveState(const int fd_progress, loader::StateList *saved_states) {
2485  string msg_progress;
2486 
2487  unsigned num_open_dirs = cvmfs::directory_handles_->size();
2488  if (num_open_dirs != 0) {
2489 #ifdef DEBUGMSG
2490  for (cvmfs::DirectoryHandles::iterator i =
2491  cvmfs::directory_handles_->begin(),
2492  iEnd = cvmfs::directory_handles_->end(); i != iEnd; ++i)
2493  {
2494  LogCvmfs(kLogCvmfs, kLogDebug, "saving dirhandle %d", i->first);
2495  }
2496 #endif
2497 
2498  msg_progress = "Saving open directory handles (" +
2499  StringifyInt(num_open_dirs) + " handles)\n";
2500  SendMsg2Socket(fd_progress, msg_progress);
2501 
2502  // TODO(jblomer): should rather be saved just in a malloc'd memory block
2503  cvmfs::DirectoryHandles *saved_handles =
2505  loader::SavedState *save_open_dirs = new loader::SavedState();
2506  save_open_dirs->state_id = loader::kStateOpenDirs;
2507  save_open_dirs->state = saved_handles;
2508  saved_states->push_back(save_open_dirs);
2509  }
2510 
2511  if (!cvmfs::file_system_->IsNfsSource()) {
2512  msg_progress = "Saving inode tracker\n";
2513  SendMsg2Socket(fd_progress, msg_progress);
2514  glue::InodeTracker *saved_inode_tracker =
2515  new glue::InodeTracker(*cvmfs::mount_point_->inode_tracker());
2516  loader::SavedState *state_glue_buffer = new loader::SavedState();
2517  state_glue_buffer->state_id = loader::kStateGlueBufferV4;
2518  state_glue_buffer->state = saved_inode_tracker;
2519  saved_states->push_back(state_glue_buffer);
2520  }
2521 
2522  msg_progress = "Saving negative entry cache\n";
2523  SendMsg2Socket(fd_progress, msg_progress);
2524  glue::DentryTracker *saved_dentry_tracker =
2525  new glue::DentryTracker(*cvmfs::mount_point_->dentry_tracker());
2526  loader::SavedState *state_dentry_tracker = new loader::SavedState();
2527  state_dentry_tracker->state_id = loader::kStateDentryTracker;
2528  state_dentry_tracker->state = saved_dentry_tracker;
2529  saved_states->push_back(state_dentry_tracker);
2530 
2531  msg_progress = "Saving page cache entry tracker\n";
2532  SendMsg2Socket(fd_progress, msg_progress);
2533  glue::PageCacheTracker *saved_page_cache_tracker =
2534  new glue::PageCacheTracker(*cvmfs::mount_point_->page_cache_tracker());
2535  loader::SavedState *state_page_cache_tracker = new loader::SavedState();
2536  state_page_cache_tracker->state_id = loader::kStatePageCacheTracker;
2537  state_page_cache_tracker->state = saved_page_cache_tracker;
2538  saved_states->push_back(state_page_cache_tracker);
2539 
2540  msg_progress = "Saving chunk tables\n";
2541  SendMsg2Socket(fd_progress, msg_progress);
2542  ChunkTables *saved_chunk_tables = new ChunkTables(
2543  *cvmfs::mount_point_->chunk_tables());
2544  loader::SavedState *state_chunk_tables = new loader::SavedState();
2545  state_chunk_tables->state_id = loader::kStateOpenChunksV4;
2546  state_chunk_tables->state = saved_chunk_tables;
2547  saved_states->push_back(state_chunk_tables);
2548 
2549  msg_progress = "Saving inode generation\n";
2550  SendMsg2Socket(fd_progress, msg_progress);
2553  cvmfs::InodeGenerationInfo *saved_inode_generation =
2555  loader::SavedState *state_inode_generation = new loader::SavedState();
2556  state_inode_generation->state_id = loader::kStateInodeGeneration;
2557  state_inode_generation->state = saved_inode_generation;
2558  saved_states->push_back(state_inode_generation);
2559 
2560  msg_progress = "Saving fuse state\n";
2561  SendMsg2Socket(fd_progress, msg_progress);
2562  cvmfs::FuseState *saved_fuse_state = new cvmfs::FuseState();
2563  saved_fuse_state->cache_symlinks = cvmfs::mount_point_->cache_symlinks();
2564  saved_fuse_state->has_dentry_expire =
2566  loader::SavedState *state_fuse = new loader::SavedState();
2567  state_fuse->state_id = loader::kStateFuse;
2568  state_fuse->state = saved_fuse_state;
2569  saved_states->push_back(state_fuse);
2570 
2571  // Close open file catalogs
2573 
2574  loader::SavedState *state_cache_mgr = new loader::SavedState();
2575  state_cache_mgr->state_id = loader::kStateOpenFiles;
2576  state_cache_mgr->state =
2577  cvmfs::file_system_->cache_mgr()->SaveState(fd_progress);
2578  saved_states->push_back(state_cache_mgr);
2579 
2580  msg_progress = "Saving open files counter\n";
2581  uint32_t *saved_num_fd =
2582  new uint32_t(cvmfs::file_system_->no_open_files()->Get());
2583  loader::SavedState *state_num_fd = new loader::SavedState();
2584  state_num_fd->state_id = loader::kStateOpenFilesCounter;
2585  state_num_fd->state = saved_num_fd;
2586  saved_states->push_back(state_num_fd);
2587 
2588  return true;
2589 }
2590 
2591 
2592 static bool RestoreState(const int fd_progress,
2593  const loader::StateList &saved_states)
2594 {
2595  // If we have no saved version of the page cache tracker, it is unsafe
2596  // to start using it. The page cache tracker has to run for the entire
2597  // lifetime of the mountpoint or not at all.
2599 
2600  for (unsigned i = 0, l = saved_states.size(); i < l; ++i) {
2601  if (saved_states[i]->state_id == loader::kStateOpenDirs) {
2602  SendMsg2Socket(fd_progress, "Restoring open directory handles... ");
2604  cvmfs::DirectoryHandles *saved_handles =
2605  (cvmfs::DirectoryHandles *)saved_states[i]->state;
2606  cvmfs::directory_handles_ = new cvmfs::DirectoryHandles(*saved_handles);
2609  cvmfs::DirectoryHandles::const_iterator i =
2610  cvmfs::directory_handles_->begin();
2611  for (; i != cvmfs::directory_handles_->end(); ++i) {
2612  if (i->first >= cvmfs::next_directory_handle_)
2613  cvmfs::next_directory_handle_ = i->first + 1;
2614  }
2615 
2616  SendMsg2Socket(fd_progress,
2617  StringifyInt(cvmfs::directory_handles_->size()) + " handles\n");
2618  }
2619 
2620  if (saved_states[i]->state_id == loader::kStateGlueBuffer) {
2621  SendMsg2Socket(fd_progress, "Migrating inode tracker (v1 to v4)... ");
2622  compat::inode_tracker::InodeTracker *saved_inode_tracker =
2623  (compat::inode_tracker::InodeTracker *)saved_states[i]->state;
2625  saved_inode_tracker, cvmfs::mount_point_->inode_tracker());
2626  SendMsg2Socket(fd_progress, " done\n");
2627  }
2628 
2629  if (saved_states[i]->state_id == loader::kStateGlueBufferV2) {
2630  SendMsg2Socket(fd_progress, "Migrating inode tracker (v2 to v4)... ");
2631  compat::inode_tracker_v2::InodeTracker *saved_inode_tracker =
2632  (compat::inode_tracker_v2::InodeTracker *)saved_states[i]->state;
2633  compat::inode_tracker_v2::Migrate(saved_inode_tracker,
2634  cvmfs::mount_point_->inode_tracker());
2635  SendMsg2Socket(fd_progress, " done\n");
2636  }
2637 
2638  if (saved_states[i]->state_id == loader::kStateGlueBufferV3) {
2639  SendMsg2Socket(fd_progress, "Migrating inode tracker (v3 to v4)... ");
2640  compat::inode_tracker_v3::InodeTracker *saved_inode_tracker =
2641  (compat::inode_tracker_v3::InodeTracker *)saved_states[i]->state;
2642  compat::inode_tracker_v3::Migrate(saved_inode_tracker,
2643  cvmfs::mount_point_->inode_tracker());
2644  SendMsg2Socket(fd_progress, " done\n");
2645  }
2646 
2647  if (saved_states[i]->state_id == loader::kStateGlueBufferV4) {
2648  SendMsg2Socket(fd_progress, "Restoring inode tracker... ");
2650  glue::InodeTracker *saved_inode_tracker =
2651  (glue::InodeTracker *)saved_states[i]->state;
2653  glue::InodeTracker(*saved_inode_tracker);
2654  SendMsg2Socket(fd_progress, " done\n");
2655  }
2656 
2657  if (saved_states[i]->state_id == loader::kStateDentryTracker) {
2658  SendMsg2Socket(fd_progress, "Restoring dentry tracker... ");
2660  glue::DentryTracker *saved_dentry_tracker =
2661  static_cast<glue::DentryTracker *>(saved_states[i]->state);
2663  glue::DentryTracker(*saved_dentry_tracker);
2664  SendMsg2Socket(fd_progress, " done\n");
2665  }
2666 
2667  if (saved_states[i]->state_id == loader::kStatePageCacheTracker) {
2668  SendMsg2Socket(fd_progress, "Restoring page cache entry tracker... ");
2670  glue::PageCacheTracker *saved_page_cache_tracker =
2671  (glue::PageCacheTracker *)saved_states[i]->state;
2673  glue::PageCacheTracker(*saved_page_cache_tracker);
2674  SendMsg2Socket(fd_progress, " done\n");
2675  }
2676 
2677  ChunkTables *chunk_tables = cvmfs::mount_point_->chunk_tables();
2678 
2679  if (saved_states[i]->state_id == loader::kStateOpenChunks) {
2680  SendMsg2Socket(fd_progress, "Migrating chunk tables (v1 to v4)... ");
2681  compat::chunk_tables::ChunkTables *saved_chunk_tables =
2682  (compat::chunk_tables::ChunkTables *)saved_states[i]->state;
2683  compat::chunk_tables::Migrate(saved_chunk_tables, chunk_tables);
2684  SendMsg2Socket(fd_progress,
2685  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2686  }
2687 
2688  if (saved_states[i]->state_id == loader::kStateOpenChunksV2) {
2689  SendMsg2Socket(fd_progress, "Migrating chunk tables (v2 to v4)... ");
2690  compat::chunk_tables_v2::ChunkTables *saved_chunk_tables =
2691  (compat::chunk_tables_v2::ChunkTables *)saved_states[i]->state;
2692  compat::chunk_tables_v2::Migrate(saved_chunk_tables, chunk_tables);
2693  SendMsg2Socket(fd_progress,
2694  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2695  }
2696 
2697  if (saved_states[i]->state_id == loader::kStateOpenChunksV3) {
2698  SendMsg2Socket(fd_progress, "Migrating chunk tables (v3 to v4)... ");
2699  compat::chunk_tables_v3::ChunkTables *saved_chunk_tables =
2700  (compat::chunk_tables_v3::ChunkTables *)saved_states[i]->state;
2701  compat::chunk_tables_v3::Migrate(saved_chunk_tables, chunk_tables);
2702  SendMsg2Socket(fd_progress,
2703  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2704  }
2705 
2706  if (saved_states[i]->state_id == loader::kStateOpenChunksV4) {
2707  SendMsg2Socket(fd_progress, "Restoring chunk tables... ");
2708  chunk_tables->~ChunkTables();
2709  ChunkTables *saved_chunk_tables = reinterpret_cast<ChunkTables *>(
2710  saved_states[i]->state);
2711  new (chunk_tables) ChunkTables(*saved_chunk_tables);
2712  SendMsg2Socket(fd_progress, " done\n");
2713  }
2714 
2715  if (saved_states[i]->state_id == loader::kStateInodeGeneration) {
2716  SendMsg2Socket(fd_progress, "Restoring inode generation... ");
2717  cvmfs::InodeGenerationInfo *old_info =
2718  (cvmfs::InodeGenerationInfo *)saved_states[i]->state;
2719  if (old_info->version == 1) {
2720  // Migration
2722  old_info->initial_revision;
2724  // Note: in the rare case of inode generation being 0 before, inode
2725  // can clash after reload before remount
2726  } else {
2727  cvmfs::inode_generation_info_ = *old_info;
2728  }
2730  SendMsg2Socket(fd_progress, " done\n");
2731  }
2732 
2733  if (saved_states[i]->state_id == loader::kStateOpenFilesCounter) {
2734  SendMsg2Socket(fd_progress, "Restoring open files counter... ");
2735  cvmfs::file_system_->no_open_files()->Set(*(reinterpret_cast<uint32_t *>(
2736  saved_states[i]->state)));
2737  SendMsg2Socket(fd_progress, " done\n");
2738  }
2739 
2740  if (saved_states[i]->state_id == loader::kStateOpenFiles) {
2741  int old_root_fd = cvmfs::mount_point_->catalog_mgr()->root_fd();
2742 
2743  // TODO(jblomer): make this less hacky
2744 
2745  CacheManagerIds saved_type =
2746  cvmfs::file_system_->cache_mgr()->PeekState(saved_states[i]->state);
2747  int fixup_root_fd = -1;
2748 
2749  if ((saved_type == kStreamingCacheManager) &&
2750  (cvmfs::file_system_->cache_mgr()->id() != kStreamingCacheManager))
2751  {
2752  // stick to the streaming cache manager
2753  StreamingCacheManager *new_cache_mgr = new
2755  cvmfs::file_system_->cache_mgr(),
2756  cvmfs::mount_point_->download_mgr(),
2757  cvmfs::mount_point_->external_download_mgr());
2758  fixup_root_fd = new_cache_mgr->PlantFd(old_root_fd);
2759  cvmfs::file_system_->ReplaceCacheManager(new_cache_mgr);
2760  cvmfs::mount_point_->fetcher()->ReplaceCacheManager(new_cache_mgr);
2762  new_cache_mgr);
2763  }
2764 
2765  if ((cvmfs::file_system_->cache_mgr()->id() == kStreamingCacheManager) &&
2766  (saved_type != kStreamingCacheManager))
2767  {
2768  // stick to the cache manager wrapped into the streaming cache
2769  CacheManager *wrapped_cache_mgr = dynamic_cast<StreamingCacheManager *>(
2770  cvmfs::file_system_->cache_mgr())->MoveOutBackingCacheMgr(
2771  &fixup_root_fd);
2772  delete cvmfs::file_system_->cache_mgr();
2773  cvmfs::file_system_->ReplaceCacheManager(wrapped_cache_mgr);
2774  cvmfs::mount_point_->fetcher()->ReplaceCacheManager(wrapped_cache_mgr);
2776  wrapped_cache_mgr);
2777  }
2778 
2779  int new_root_fd = cvmfs::file_system_->cache_mgr()->RestoreState(
2780  fd_progress, saved_states[i]->state);
2781  LogCvmfs(kLogCvmfs, kLogDebug, "new root file catalog descriptor @%d",
2782  new_root_fd);
2783  if (new_root_fd >= 0) {
2784  cvmfs::file_system_->RemapCatalogFd(old_root_fd, new_root_fd);
2785  } else if (fixup_root_fd >= 0) {
2787  "new root file catalog descriptor (fixup) @%d", fixup_root_fd);
2788  cvmfs::file_system_->RemapCatalogFd(old_root_fd, fixup_root_fd);
2789  }
2790  }
2791 
2792  if (saved_states[i]->state_id == loader::kStateFuse) {
2793  SendMsg2Socket(fd_progress, "Restoring fuse state... ");
2794  cvmfs::FuseState *fuse_state =
2795  static_cast<cvmfs::FuseState *>(saved_states[i]->state);
2796  if (!fuse_state->cache_symlinks)
2798  if (fuse_state->has_dentry_expire)
2800  SendMsg2Socket(fd_progress, " done\n");
2801  }
2802  }
2803  if (cvmfs::mount_point_->inode_annotation()) {
2804  uint64_t saved_generation = cvmfs::inode_generation_info_.inode_generation;
2805  cvmfs::mount_point_->inode_annotation()->IncGeneration(saved_generation);
2806  }
2807 
2808  return true;
2809 }
2810 
2811 
2812 static void FreeSavedState(const int fd_progress,
2813  const loader::StateList &saved_states)
2814 {
2815  for (unsigned i = 0, l = saved_states.size(); i < l; ++i) {
2816  switch (saved_states[i]->state_id) {
2818  SendMsg2Socket(fd_progress, "Releasing saved open directory handles\n");
2819  delete static_cast<cvmfs::DirectoryHandles *>(saved_states[i]->state);
2820  break;
2823  fd_progress, "Releasing saved glue buffer (version 1)\n");
2824  delete static_cast<compat::inode_tracker::InodeTracker *>(
2825  saved_states[i]->state);
2826  break;
2829  fd_progress, "Releasing saved glue buffer (version 2)\n");
2830  delete static_cast<compat::inode_tracker_v2::InodeTracker *>(
2831  saved_states[i]->state);
2832  break;
2835  fd_progress, "Releasing saved glue buffer (version 3)\n");
2836  delete static_cast<compat::inode_tracker_v3::InodeTracker *>(
2837  saved_states[i]->state);
2838  break;
2840  SendMsg2Socket(fd_progress, "Releasing saved glue buffer\n");
2841  delete static_cast<glue::InodeTracker *>(saved_states[i]->state);
2842  break;
2844  SendMsg2Socket(fd_progress, "Releasing saved dentry tracker\n");
2845  delete static_cast<glue::DentryTracker *>(saved_states[i]->state);
2846  break;
2848  SendMsg2Socket(fd_progress, "Releasing saved page cache entry cache\n");
2849  delete static_cast<glue::PageCacheTracker *>(saved_states[i]->state);
2850  break;
2852  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 1)\n");
2853  delete static_cast<compat::chunk_tables::ChunkTables *>(
2854  saved_states[i]->state);
2855  break;
2857  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 2)\n");
2858  delete static_cast<compat::chunk_tables_v2::ChunkTables *>(
2859  saved_states[i]->state);
2860  break;
2862  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 3)\n");
2863  delete static_cast<compat::chunk_tables_v3::ChunkTables *>(
2864  saved_states[i]->state);
2865  break;
2867  SendMsg2Socket(fd_progress, "Releasing chunk tables\n");
2868  delete static_cast<ChunkTables *>(saved_states[i]->state);
2869  break;
2871  SendMsg2Socket(fd_progress, "Releasing saved inode generation info\n");
2872  delete static_cast<cvmfs::InodeGenerationInfo *>(
2873  saved_states[i]->state);
2874  break;
2877  fd_progress, saved_states[i]->state);
2878  break;
2880  SendMsg2Socket(fd_progress, "Releasing open files counter\n");
2881  delete static_cast<uint32_t *>(saved_states[i]->state);
2882  break;
2883  case loader::kStateFuse:
2884  SendMsg2Socket(fd_progress, "Releasing fuse state\n");
2885  delete static_cast<cvmfs::FuseState *>(saved_states[i]->state);
2886  break;
2887  default:
2888  break;
2889  }
2890  }
2891 }
2892 
2893 
2894 static void __attribute__((constructor)) LibraryMain() {
2895  g_cvmfs_exports = new loader::CvmfsExports();
2896  g_cvmfs_exports->so_version = PACKAGE_VERSION;
2897  g_cvmfs_exports->fnAltProcessFlavor = AltProcessFlavor;
2898  g_cvmfs_exports->fnInit = Init;
2899  g_cvmfs_exports->fnSpawn = Spawn;
2900  g_cvmfs_exports->fnFini = Fini;
2901  g_cvmfs_exports->fnGetErrorMsg = GetErrorMsg;
2902  g_cvmfs_exports->fnMaintenanceMode = MaintenanceMode;
2903  g_cvmfs_exports->fnSaveState = SaveState;
2904  g_cvmfs_exports->fnRestoreState = RestoreState;
2905  g_cvmfs_exports->fnFreeSavedState = FreeSavedState;
2906  cvmfs::SetCvmfsOperations(&g_cvmfs_exports->cvmfs_operations);
2907 }
2908 
2909 
2910 static void __attribute__((destructor)) LibraryExit() {
2911  delete g_cvmfs_exports;
2912  g_cvmfs_exports = NULL;
2913 }
bool GetInfoIfOpen(uint64_t inode, shash::Any *hash, struct stat *info)
Definition: glue_buffer.h:1025
perf::Counter * n_eio_total()
Definition: mountpoint.h:238
bool cache_symlinks()
Definition: mountpoint.h:519
VfsPutRaii GetVfsPutRaii()
Definition: glue_buffer.h:688
std::string repository_name
Definition: loader.h:178
OptionsManager * options_mgr()
Definition: mountpoint.h:247
#define LogCvmfs(source, mask,...)
Definition: logging.h:25
uint32_t version
Definition: loader.h:173
bool IsCaching()
Definition: fuse_remount.h:60
void Dec(class Counter *counter)
Definition: statistics.h:49
NfsMaps * nfs_maps()
Definition: mountpoint.h:235
bool IsExternalFile() const
std::string mount_point
Definition: loader.h:179
perf::Counter * n_eio_05()
Definition: mountpoint.h:243
bool IsInDrainoutMode()
Definition: fuse_remount.h:64
void UnregisterQuotaListener()
Definition: cvmfs.cc:2029
static const time_t kIndefiniteDeadline
Definition: mountpoint.h:487
perf::Counter * n_fs_inode_replace()
Definition: mountpoint.h:223
virtual std::string GetValue()
Definition: cvmfs.cc:2081
int64_t Xadd(class Counter *counter, const int64_t delta)
Definition: statistics.h:51
static void cvmfs_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:755
std::string ListKeysPosix(const std::string &merge_with) const
Definition: xattr.cc:137
perf::Counter * n_eio_01()
Definition: mountpoint.h:239
FileSystem * file_system()
Definition: mountpoint.h:515
void TryFinish(const shash::Any &root_hash=shash::Any())
bool InsertNegative(const shash::Md5 &hash)
Definition: lru_md.h:129
Log2Histogram * hist_fs_opendir()
Definition: mountpoint.h:214
time_t catalogs_valid_until_
Definition: cvmfs.cc:2074
static bool HasDifferentContent(const catalog::DirectoryEntry &dirent, const shash::Any &hash, const struct stat &info)
Definition: cvmfs.cc:267
virtual void ParsePath(const std::string &config_file, const bool external)=0
void Enter()
Definition: fence.h:34
bool ReplaceInode(uint64_t old_inode, const InodeEx &new_inode)
Definition: glue_buffer.h:738
static void cvmfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
Definition: cvmfs.cc:1353
time_t mtime() const
static double GetKcacheTimeout()
Definition: cvmfs.cc:215
void EnterMaintenanceMode()
void set_inode(const inode_t inode)
InodeGenerationInfo inode_generation_info_
Definition: cvmfs.cc:131
loader::Failures boot_status()
Definition: mountpoint.h:77
static void FreeSavedState(const int fd_progress, const loader::StateList &saved_states)
Definition: cvmfs.cc:2812
int PlantFd(int fd_in_cache_mgr)
bool IsDirectory() const
static void cvmfs_statfs(fuse_req_t req, fuse_ino_t ino)
Definition: cvmfs.cc:1608
off_t range_offset
Definition: cache.h:127
void set_boot_status(loader::Failures code)
Definition: mountpoint.h:84
static void DoTraceInode(const int event, fuse_ino_t ino, const std::string &msg)
Definition: cvmfs.cc:488
cvmfs::Fetcher * fetcher()
Definition: mountpoint.h:510
void Migrate(ChunkTables *old_tables,::ChunkTables *new_tables)
Definition: compat.cc:182
void ShareBuffer(Item **duplicate, bool *large_alloc)
Definition: bigvector.h:81
static void cvmfs_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:1019
bool IsChunkedFile() const
FuseRemounter * fuse_remounter_
Definition: cvmfs.cc:130
uid_t talk_socket_uid()
Definition: mountpoint.h:537
int RestoreState(const int fd_progress, void *state)
Definition: cache.cc:188
void Register(const std::string &name, BaseMagicXattr *magic_xattr)
Definition: magic_xattr.cc:135
SmallHashDynamic< uint64_t, uint64_t > handle2uniqino
Definition: file_chunk.h:119
bool Insert(const fuse_ino_t &inode, const catalog::DirectoryEntry &dirent)
Definition: lru_md.h:51
google::dense_hash_map< uint64_t, DirectoryListing, hash_murmur< uint64_t > > DirectoryHandles
Definition: cvmfs.cc:158
#define PANIC(...)
Definition: exception.h:29
void Spawn()
Definition: tracer.cc:212
SpecialDirents GetSpecial() const
bool fuse_expire_entry()
Definition: mountpoint.h:520
virtual void Spawn()=0
static int AltProcessFlavor(int argc, char **argv)
Definition: cvmfs.cc:2459
uint64_t size() const
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:249
double kcache_timeout_sec()
Definition: mountpoint.h:526
void Assign(const char *chars, const unsigned length)
Definition: shortstring.h:61
static void cvmfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
Definition: cvmfs.cc:643
std::string PrintInodeGeneration()
Definition: cvmfs.cc:238
zlib::Algorithms compression_alg
Definition: file_chunk.h:71
static void SetupLoggingStandalone(const OptionsManager &options_mgr, const std::string &prefix)
Definition: mountpoint.cc:869
int MainResolveProxyDescription(int argc, char **argv)
Definition: wpad.cc:272
bool FindDentry(uint64_t ino, uint64_t *parent_ino, NameString *name)
Definition: glue_buffer.h:716
perf::Counter * n_fs_readlink()
Definition: mountpoint.h:228
std::string fqrn() const
Definition: mountpoint.h:512
unsigned LookupOptions
Definition: catalog_mgr.h:40
void SetMountpoint(const string &mountpoint)
Definition: auto_umount.cc:28
void InvalidateDentry(uint64_t parent_ino, const NameString &name)
Definition: fuse_remount.h:70
void set_symlink(const LinkString &symlink)
static void cvmfs_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:1526
BaseMagicXattr * GetLocked(const std::string &name, PathString path, catalog::DirectoryEntry *d)
Definition: magic_xattr.cc:119
Watchdog * watchdog_
Definition: cvmfs.cc:129
bool Lookup(const shash::Md5 &hash, catalog::DirectoryEntry *dirent, bool update_lru=true)
Definition: lru_md.h:136
lru::InodeCache * inode_cache()
Definition: mountpoint.h:525
NotificationClient * notification_client_
Definition: cvmfs.cc:128
void * SaveState(const int fd_progress)
Definition: cache.cc:215
DirectoryHandles * directory_handles_
Definition: cvmfs.cc:159
StateId state_id
Definition: loader.h:123
CVMFS_EXPORT void CleanupLibcryptoMt()
Definition: crypto_util.cc:70
bool check_fd_overflow_
Definition: cvmfs.cc:169
const shash::Any & content_hash() const
Definition: file_chunk.h:41
time_t catalogs_valid_until()
Definition: fuse_remount.h:68
static bool SaveState(const int fd_progress, loader::StateList *saved_states)
Definition: cvmfs.cc:2484
inode_t inode() const
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:659
bool ListingStat(const PathString &path, StatEntryList *listing)
assert((mem||(size==0))&&"Out Of Memory")
void ** fuse_channel_or_session
Definition: loader.h:196
MountPoint * mount_point_
Definition: cvmfs.cc:126
MagicXattrManager * magic_xattr_mgr()
Definition: mountpoint.h:516
std::string program_name
Definition: loader.h:181
Log2Histogram * hist_fs_read()
Definition: mountpoint.h:218
bool IsDirectIo() const
bool SendFd2Socket(int socket_fd, int passing_fd)
Definition: posix.cc:668
bool LookupPath(const PathString &path, const LookupOptions options, DirectoryEntry *entry)
void EnableFuseExpireEntry()
Definition: mountpoint.cc:1261
static bool RestoreState(const int fd_progress, const loader::StateList &saved_states)
Definition: cvmfs.cc:2592
virtual uint64_t GetSize()=0
perf::Counter * n_fs_read()
Definition: mountpoint.h:227
bool Lookup(const fuse_ino_t &inode, catalog::DirectoryEntry *dirent, bool update_lru=true)
Definition: lru_md.h:59
void UmountOnCrash()
Definition: auto_umount.cc:38
int fd
Definition: file_chunk.h:82
lru::Md5PathCache * md5path_cache()
Definition: mountpoint.h:527
shash::Any checksum() const
void ParseDefault(const std::string &fqrn)
Definition: options.cc:282
SmallHashDynamic< uint64_t, ChunkFd > handle2fd
Definition: file_chunk.h:120
bool VfsPut(const uint64_t inode, const uint32_t by)
Definition: glue_buffer.h:616
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:110
bool has_dentry_expire
Definition: cvmfs.cc:199
bool has_membership_req()
Definition: mountpoint.h:517
virtual bool PrepareValueFenced()
Definition: cvmfs.cc:2076
virtual std::string GetValue()
Definition: cvmfs.cc:2092
unsigned int mode() const
struct cvmcache_object_info __attribute__
Definition: atomic.h:24
const unsigned kLookupDefault
Definition: catalog_mgr.h:41
void RemapCatalogFd(int from, int to)
Definition: mountpoint.cc:1146
bool Pin(const string &path)
Definition: cvmfs.cc:1855
static void cvmfs_destroy(void *unused __attribute__((unused)))
Definition: cvmfs.cc:1995
perf::Counter * n_eio_08()
Definition: mountpoint.h:246
static TalkManager * Create(const std::string &socket_path, MountPoint *mount_point, FuseRemounter *remounter)
Definition: talk.cc:78
unsigned max_open_files_
Definition: cvmfs.cc:163
static bool HasFuseNotifyInval()
Definition: fuse_evict.cc:54
perf::Counter * n_fs_open()
Definition: mountpoint.h:226
static void cvmfs_init(void *userdata, struct fuse_conn_info *conn)
Definition: cvmfs.cc:1927
TalkManager * talk_mgr_
Definition: cvmfs.cc:127
const unsigned int kMinOpenFiles
Definition: cvmfs.cc:177
virtual uint64_t GetCapacity()=0
std::string membership_req()
Definition: mountpoint.h:528
void Throttle()
Definition: backoff.cc:50
std::string GetListString(catalog::DirectoryEntry *dirent)
Definition: magic_xattr.cc:77
bool Lookup(const fuse_ino_t &inode, PathString *path, bool update_lru=true)
Definition: lru_md.h:92
uint64_t next_directory_handle_
Definition: cvmfs.cc:161
void Unlock()
Definition: file_chunk.h:106
static void InitOptionsMgr(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:2171
Fence * fence()
Definition: fuse_remount.h:67
const uint64_t cache_timeout()
Definition: mountpoint.h:457
pid_t pid_
Definition: cvmfs.cc:151
void ReplaceCacheManager(CacheManager *new_cache_mgr)
Definition: mountpoint.cc:1150
void DisableCacheSymlinks()
Definition: mountpoint.cc:1253
PathString path
Definition: file_chunk.h:70
static bool GetDirentForInode(const fuse_ino_t ino, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:314
glue::PageCacheTracker * page_cache_tracker()
Definition: mountpoint.h:530
NameString name() const
static Watchdog * Create(FnOnCrash on_crash)
Definition: monitor.cc:70
bool IsLink() const
void SetBit(unsigned int bit, T *field)
Definition: algorithm.h:31
perf::Counter * n_eio_07()
Definition: mountpoint.h:245
BigVector< FileChunk > FileChunkList
Definition: file_chunk.h:51
virtual void Spawn()=0
static bool FixupOpenInode(const PathString &path, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:291
bool HasXattrs() const
virtual std::string GetValue()
Definition: cvmfs.cc:2110
static void TraceInode(const int event, fuse_ino_t ino, const std::string &msg)
Definition: cvmfs.cc:503
void GetLimitNoFile(unsigned *soft_limit, unsigned *hard_limit)
Definition: posix.cc:1480
bool Get(const std::string &key, std::string *value) const
Definition: xattr.cc:108
catalog::ClientCatalogManager * catalog_mgr()
Definition: mountpoint.h:501
void Set(const int64_t val)
Definition: statistics.h:33
Log2Histogram * hist_fs_forget_multi()
Definition: mountpoint.h:211
static void cvmfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Definition: cvmfs.cc:1765
bool IsRegular() const
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:290
void ClearBit(unsigned int bit, T *field)
Definition: algorithm.h:36
uint64_t size
unzipped size, if known
Definition: cache.h:125
void DoubleCapacity()
Definition: bigvector.h:87
bool platform_getxattr(const std::string &path, const std::string &name, std::string *value)
static bool MayBeInPageCacheTracker(const catalog::DirectoryEntry &dirent)
Definition: cvmfs.cc:262
Log2Histogram * hist_fs_release()
Definition: mountpoint.h:219
pthread_mutex_t * Handle2Lock(const uint64_t handle) const
Definition: file_chunk.cc:141
void Lock()
Definition: file_chunk.h:101
uint64_t FindInode(const PathString &path)
Definition: glue_buffer.h:708
ListenerHandle * RegisterWatchdogListener(QuotaManager *quota_manager, const string &repository_name)
const loader::LoaderExports * loader_exports_
Definition: cvmfs.cc:149
int Fetch(const CacheManager::LabeledObject &object, const std::string &alt_url="")
Definition: fetch.cc:81
EVisibility visibility()
Definition: magic_xattr.h:198
virtual inode_t GetGeneration()=0
std::string config_files
Definition: loader.h:180
perf::Counter * no_open_dirs()
Definition: mountpoint.h:236
catalog::InodeAnnotation * inode_annotation()
Definition: mountpoint.h:521
CacheManagerIds
Definition: cache.h:24
Log2Histogram * hist_fs_releasedir()
Definition: mountpoint.h:215
quota::ListenerHandle * watchdog_listener_
Definition: cvmfs.cc:152
void Add(const uint64_t inode_parent, const char *name, uint64_t timeout_s)
Definition: glue_buffer.h:854
virtual bool IsCanceled()
Definition: cvmfs.cc:184
void SetSize(const size_t new_size)
Definition: bigvector.h:116
std::string boot_error()
Definition: mountpoint.h:78
off_t offset() const
Definition: file_chunk.h:42
lru::PathCache * path_cache()
Definition: mountpoint.h:531
struct statvfs * info()
Definition: mountpoint.h:458
virtual std::string GetValue()
Definition: cvmfs.cc:2100
static void cvmfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:1116
zlib::Algorithms compression_algorithm() const
bool IsNfsSource()
Definition: mountpoint.h:195
CacheManager * cache_mgr()
Definition: mountpoint.h:205
const signature::SignatureManager * signature_mgr() const
Definition: repository.h:121
file_watcher::FileWatcher * resolv_conf_watcher()
Definition: mountpoint.h:507
unsigned chunk_idx
Definition: file_chunk.h:83
virtual bool Pin(const shash::Any &hash, const uint64_t size, const std::string &description, const bool is_catalog)=0
bool IsMemberOf(const pid_t pid, const std::string &membership)
virtual std::string GetValue()
Definition: cvmfs.cc:2106
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:145
void SpawnCleaner(unsigned interval_s)
Definition: glue_buffer.cc:170
static void ShutdownMountpoint()
Definition: cvmfs.cc:2411
static bool AssertOrLog(int t, const LogSource, const int, const char *,...)
Definition: exception.h:61
static bool IncAndCheckNoOpenFiles()
Definition: cvmfs.cc:208
unsigned FindChunkIdx(const uint64_t offset)
Definition: file_chunk.cc:23
perf::TelemetryAggregator * telemetry_aggr()
Definition: mountpoint.h:535
bool SendFuseFd(const std::string &socket_path)
Definition: cvmfs.cc:2040
perf::Counter * no_open_files()
Definition: mountpoint.h:237
AuthzSessionManager * authz_session_mgr()
Definition: mountpoint.h:499
LinkString symlink() const
void Insert(const Key &key, const Value &value)
Definition: smallhash.h:109
IoErrorInfo * io_error_info()
Definition: mountpoint.h:233
download::DownloadManager * download_mgr()
Definition: mountpoint.h:503
perf::Counter * n_fs_stat_stale()
Definition: mountpoint.h:230
void ReplaceCacheManager(CacheManager *new_cache_mgr)
Definition: fetch.h:124
static void SetCvmfsOperations(struct fuse_lowlevel_ops *cvmfs_operations)
Definition: cvmfs.cc:2003
bool simple_options_parsing
Definition: loader.h:189
static const int kLabelPinned
Definition: cache.h:81
perf::Counter * n_fs_forget()
Definition: mountpoint.h:222
Log2Histogram * hist_fs_readlink()
Definition: mountpoint.h:213
static int Init(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:2217
void Append(const char *chars, const unsigned length)
Definition: shortstring.h:80
ListenerHandle * RegisterUnpinListener(QuotaManager *quota_manager, CatalogManager *catalog_manager, const string &repository_name)
string StringifyInt(const int64_t value)
Definition: string.cc:78
SmallHashDynamic< uint64_t, uint32_t > inode2references
Definition: file_chunk.h:125
void Leave()
Definition: fence.h:41
uint64_t platform_monotonic_time()
static void cvmfs_readlink(fuse_req_t req, fuse_ino_t ino)
Definition: cvmfs.cc:824
size_t capacity() const
Definition: bigvector.h:122
static void ReplyNegative(const catalog::DirectoryEntry &dirent, fuse_req_t req)
Definition: cvmfs.cc:731
void Inc(class Counter *counter)
Definition: statistics.h:50
virtual int Close(int fd)=0
CacheManagerIds PeekState(void *state)
Definition: cache.h:207
bool GetValue(const std::string &key, std::string *value) const
Definition: options.cc:376
static void cvmfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
Definition: cvmfs.cc:1068
ChunkTables * chunk_tables()
Definition: mountpoint.h:502
const unsigned kLookupRawSymlink
Definition: catalog_mgr.h:42
pthread_mutex_t lock_directory_handles_
Definition: cvmfs.cc:160
static void cvmfs_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:883
OptionsManager * options_mgr_
Definition: cvmfs.cc:150
virtual bool GetPath(const uint64_t inode, PathString *path)=0
unsigned version
Definition: cvmfs.cc:197
shash::Algorithms hash_algorithm() const
glue::DentryTracker * dentry_tracker()
Definition: mountpoint.h:529
static int MainCacheManager(int argc, char **argv)
Definition: quota_posix.cc:950
perf::Counter * n_fs_dir_open()
Definition: mountpoint.h:221
Log2Histogram * hist_fs_readdir()
Definition: mountpoint.h:216
cvmfs::Fetcher * external_fetcher()
Definition: mountpoint.h:514
bool enforce_acls()
Definition: mountpoint.h:518
static const int kLabelVolatile
Definition: cache.h:82
bool IsInMaintenanceMode()
Definition: fuse_remount.h:65
static bool CheckVoms(const fuse_ctx &fctx)
Definition: cvmfs.cc:249
static void FillOpenFlags(const glue::PageCacheTracker::OpenDirectives od, struct fuse_file_info *fi)
Definition: cvmfs.cc:1092
void FreeState(const int fd_progress, void *state)
Definition: cache.cc:99
static FileSystem * Create(const FileSystemInfo &fs_info)
Definition: mountpoint.cc:166
bool IsEmpty() const
Definition: bigvector.h:72
bool cache_symlinks
Definition: cvmfs.cc:198
zlib::Algorithms zip_algorithm
Definition: cache.h:126
bool Contains(const Key &key) const
Definition: smallhash.h:102
Log2Histogram * hist_fs_open()
Definition: mountpoint.h:217
OpenDirectives Open(uint64_t inode, const shash::Any &hash, const struct stat &info)
Definition: glue_buffer.cc:317
pthread_mutex_t * lock()
Definition: mountpoint.h:459
std::string ToString() const
Definition: shortstring.h:141
QuotaManager * quota_mgr()
Definition: cache.h:193
static string GetErrorMsg()
Definition: cvmfs.cc:2399
static uint64_t GetDirentForPath(const PathString &path, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:405
int ConnectSocket(const std::string &path)
Definition: posix.cc:427
void Migrate(ChunkTables *old_tables,::ChunkTables *new_tables)
Definition: compat.cc:274
virtual void Spawn()
Definition: nfs_maps.h:36
Log2Histogram * hist_fs_lookup()
Definition: mountpoint.h:209
bool IsCompatibleFileType(unsigned mode) const
Definition: glue_buffer.h:85
bool TestBit(unsigned int bit, const T field)
Definition: algorithm.h:41
CVMFS_EXPORT void SetupLibcryptoMt()
Definition: crypto_util.cc:52
void Close(uint64_t inode)
Definition: glue_buffer.cc:399
string * g_boot_error
Definition: cvmfs.cc:2064
bool ListFileChunks(const PathString &path, const shash::Algorithms interpret_hashes_as, FileChunkList *chunks)
static void Fini()
Definition: cvmfs.cc:2440
perf::Counter * n_fs_lookup()
Definition: mountpoint.h:224
static void Spawn()
Definition: cvmfs.cc:2348
static bool UseWatchdog()
Definition: cvmfs.cc:228
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:80
OpenDirectives OpenDirect()
Definition: glue_buffer.cc:388
ShortString< kDefaultMaxPath, 0 > PathString
Definition: shortstring.h:217
uint32_t size() const
Definition: smallhash.h:302
uint64_t next_handle
Definition: file_chunk.h:126
shash::Any HashChunkList()
Definition: file_chunk.cc:49
size_t size() const
Definition: file_chunk.h:43
FuseInterruptCue(fuse_req_t *r)
Definition: cvmfs.cc:182
void UnregisterListener(ListenerHandle *handle)
Definition: mutex.h:42
bool Evict(const string &path)
Definition: cvmfs.cc:1828
std::vector< SavedState * > StateList
Definition: loader.h:126
perf::Counter * n_eio_02()
Definition: mountpoint.h:240
PathString GetParentPath(const PathString &path)
Definition: shortstring.cc:15
static unsigned CheckMaxOpenFiles()
Definition: cvmfs.cc:2191
FileSystem * file_system_
Definition: cvmfs.cc:125
perf::Counter * n_eio_03()
Definition: mountpoint.h:241
EvictRaii GetEvictRaii()
Definition: glue_buffer.h:1040
perf::Counter * n_eio_04()
Definition: mountpoint.h:242
void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode)
Definition: cvmfs.cc:222
bool Erase(const Key &key)
Definition: smallhash.h:115
bool LookupXattrs(const PathString &path, XattrList *xattrs)
perf::Counter * n_fs_lookup_negative()
Definition: mountpoint.h:225
StatfsCache * statfs_cache()
Definition: mountpoint.h:542
std::string path
Definition: cache.h:133
virtual uint64_t GetInode(const PathString &path)=0
void Spawn(const std::string &crash_dump_path)
Definition: monitor.cc:510
Log2Histogram * hist_fs_forget()
Definition: mountpoint.h:210
const int kNumReservedFd
Definition: cvmfs.cc:173
static void ReplyBufferSlice(const fuse_req_t req, const char *buffer, const size_t buffer_size, const off_t offset, const size_t max_size)
Definition: cvmfs.cc:1052
unsigned GetLength() const
Definition: shortstring.h:131
static const int kLabelExternal
Definition: cache.h:83
virtual void IncGeneration(const uint64_t by)=0
bool Lookup(const Key &key, Value *value) const
Definition: smallhash.h:73
inode_t MangleInode(const inode_t inode) const
Definition: catalog_mgr.h:202
static const int kLabelChunked
Definition: cache.h:84
bool Insert(const fuse_ino_t &inode, const PathString &path)
Definition: lru_md.h:84
BackoffThrottle * backoff_throttle()
Definition: mountpoint.h:500
Log2Histogram * hist_fs_getattr()
Definition: mountpoint.h:212
gid_t talk_socket_gid()
Definition: mountpoint.h:538
const char * c_str() const
Definition: shortstring.h:145
static bool GetPathForInode(const fuse_ino_t ino, PathString *path)
Definition: cvmfs.cc:454
static const unsigned int kBitDirectIo
Definition: glue_buffer.h:950
const char * GetChars() const
Definition: shortstring.h:123
static void RegisterMagicXattrs()
Definition: cvmfs.cc:2121
bool IsDefined(const std::string &key)
Definition: options.cc:370
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1060
virtual void Remove(const shash::Any &file)=0
glue::InodeTracker * inode_tracker()
Definition: mountpoint.h:524
bool Insert(const shash::Md5 &hash, const catalog::DirectoryEntry &dirent)
Definition: lru_md.h:121
perf::Counter * n_fs_stat()
Definition: mountpoint.h:229
static void size_t size
Definition: smalloc.h:54
virtual ~FuseInterruptCue()
Definition: cvmfs.cc:183
static void cvmfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
Definition: cvmfs.cc:515
#define ENOATTR
Definition: cvmfs.cc:25
virtual int64_t Pread(int fd, void *buf, uint64_t size, uint64_t offset)=0
SmallHashDynamic< uint64_t, FileChunkReflist > inode2chunks
Definition: file_chunk.h:124
static bool MaintenanceMode(const int fd_progress)
Definition: cvmfs.cc:2470
uint64_t * expiry_deadline()
Definition: mountpoint.h:456
void Migrate(ChunkTables *old_tables,::ChunkTables *new_tables)
Definition: compat.cc:228
FileChunkList * list
Definition: file_chunk.h:69
static FileSystem * InitSystemFs(const string &mount_path, const string &fqrn, FileSystem::FileSystemInfo fs_info)
Definition: cvmfs.cc:2136
void VfsGet(const InodeEx inode_ex, const PathString &path)
Definition: glue_buffer.h:684
const Item * AtPtr(const size_t index) const
Definition: bigvector.h:55
static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
Definition: cvmfs.cc:1674
Tracer * tracer()
Definition: mountpoint.h:540
perf::Counter * n_fs_statfs_cached()
Definition: mountpoint.h:232
bool FindPath(InodeEx *inode_ex, PathString *path)
Definition: glue_buffer.h:690
struct stat GetStatStructure() const
virtual bool HasCapability(Capabilities capability)=0
static void AddToDirListing(const fuse_req_t req, const char *name, const struct stat *stat_info, BigVector< char > *listing)
Definition: cvmfs.cc:856
size_t size() const
Definition: bigvector.h:121
download::DownloadManager * external_download_mgr()
Definition: mountpoint.h:504
perf::Counter * n_fs_statfs()
Definition: mountpoint.h:231
quota::ListenerHandle * unpin_listener_
Definition: cvmfs.cc:153
static MountPoint * Create(const std::string &fqrn, FileSystem *file_system, OptionsManager *options_mgr=NULL)
Definition: mountpoint.cc:1270
void Spawn()
Definition: talk.cc:843
fuse_req_t * req_ptr_
Definition: cvmfs.cc:186
perf::Counter * n_eio_06()
Definition: mountpoint.h:244
OptionsManager * options_mgr
Definition: mountpoint.h:139