CernVM-FS  2.9.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 <openssl/crypto.h>
43 #include <pthread.h>
44 #include <stddef.h>
45 #include <stdint.h>
46 #include <sys/errno.h>
47 #include <sys/file.h>
48 #include <sys/mount.h>
49 #include <sys/resource.h>
50 #include <sys/stat.h>
51 #include <sys/time.h>
52 #include <sys/types.h>
53 #include <sys/wait.h>
54 #include <unistd.h>
55 
56 #include <algorithm>
57 #include <cassert>
58 #include <cstdio>
59 #include <cstdlib>
60 #include <cstring>
61 #include <ctime>
62 #include <functional>
63 #include <map>
64 #include <new>
65 #include <string>
66 #include <vector>
67 
68 #include "atomic.h"
69 #include "authz/authz_session.h"
70 #include "auto_umount.h"
71 #include "backoff.h"
72 #include "cache.h"
73 #include "catalog_mgr_client.h"
74 #include "clientctx.h"
75 #include "compat.h"
76 #include "compression.h"
77 #include "directory_entry.h"
78 #include "download.h"
79 #include "duplex_fuse.h"
80 #include "fence.h"
81 #include "fetch.h"
82 #include "file_chunk.h"
83 #include "fuse_inode_gen.h"
84 #include "fuse_remount.h"
85 #include "globals.h"
86 #include "glue_buffer.h"
87 #include "hash.h"
88 #include "history_sqlite.h"
89 #include "loader.h"
90 #include "logging.h"
91 #include "lru_md.h"
92 #include "magic_xattr.h"
93 #include "manifest_fetch.h"
94 #include "monitor.h"
95 #include "mountpoint.h"
96 #include "nfs_maps.h"
97 #include "notification_client.h"
98 #include "options.h"
99 #include "platform.h"
100 #include "quota_listener.h"
101 #include "quota_posix.h"
102 #include "shortstring.h"
103 #include "signature.h"
104 #include "smalloc.h"
105 #include "sqlitemem.h"
106 #include "sqlitevfs.h"
107 #include "statistics.h"
108 #include "talk.h"
109 #include "tracer.h"
110 #include "util/exception.h"
111 #include "util_concurrency.h"
112 #include "uuid.h"
113 #include "wpad.h"
114 #include "xattr.h"
115 
116 using namespace std; // NOLINT
117 
118 namespace cvmfs {
119 
127 
128 
134  char *buffer;
136  // Not really used anymore. But directory listing needs to be migrated during
137  // hotpatch. If buffer is allocated by smmap, capacity is zero.
138  size_t size;
139  size_t capacity;
140 
141  DirectoryListing() : buffer(NULL), size(0), capacity(0) { }
142 };
143 
146 pid_t pid_ = 0;
149 
150 
151 typedef google::dense_hash_map<uint64_t, DirectoryListing,
155 pthread_mutex_t lock_directory_handles_ = PTHREAD_MUTEX_INITIALIZER;
157 
158 unsigned max_open_files_;
162 const int kNumReservedFd = 512;
163 
164 
165 static inline double GetKcacheTimeout() {
166  if (!fuse_remounter_->IsCaching())
167  return 0.0;
169 }
170 
171 
172 void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode) {
173  *drainout_mode = fuse_remounter_->IsInDrainoutMode();
174  *maintenance_mode = fuse_remounter_->IsInMaintenanceMode();
175 }
176 
177 
178 static bool UseWatchdog() {
179  if (loader_exports_ == NULL || loader_exports_->version < 2) {
180  return true; // spawn watchdog by default
181  // Note: with library versions before 2.1.8 it might not
182  // create stack traces properly in all cases
183  }
184 
186 }
187 
188 std::string PrintInodeGeneration() {
189  return "init-catalog-revision: " +
191  "current-catalog-revision: " +
193  "incarnation: " + StringifyInt(inode_generation_info_.incarnation) + " " +
195  + "\n";
196 }
197 
198 
199 static bool CheckVoms(const fuse_ctx &fctx) {
201  return true;
202  string mreq = mount_point_->membership_req();
203  LogCvmfs(kLogCvmfs, kLogDebug, "Got VOMS authz %s from filesystem "
204  "properties", mreq.c_str());
205 
206  if (fctx.uid == 0)
207  return true;
208 
209  return mount_point_->authz_session_mgr()->IsMemberOf(fctx.pid, mreq);
210 }
211 
212 
213 static bool GetDirentForInode(const fuse_ino_t ino,
214  catalog::DirectoryEntry *dirent)
215 {
216  // Lookup inode in cache
217  if (mount_point_->inode_cache()->Lookup(ino, dirent))
218  return true;
219 
220  // Look in the catalogs in 2 steps: lookup inode->path, lookup path
221  catalog::DirectoryEntry dirent_negative =
223  // Reset directory entry. If the function returns false and dirent is no
224  // the kDirentNegative, it was an I/O error
225  *dirent = catalog::DirectoryEntry();
226 
228 
229  if (file_system_->IsNfsSource()) {
230  // NFS mode
231  PathString path;
232  bool retval = file_system_->nfs_maps()->GetPath(ino, &path);
233  if (!retval) {
234  *dirent = dirent_negative;
235  return false;
236  }
237  if (catalog_mgr->LookupPath(path, catalog::kLookupSole, dirent)) {
238  // Fix inodes
239  dirent->set_inode(ino);
240  mount_point_->inode_cache()->Insert(ino, *dirent);
241  return true;
242  }
243  return false; // Not found in catalog or catalog load error
244  }
245 
246  // Non-NFS mode
247  PathString path;
248  if (ino == catalog_mgr->GetRootInode()) {
249  bool retval =
250  catalog_mgr->LookupPath(PathString(), catalog::kLookupSole, dirent);
251  assert(retval);
252  dirent->set_inode(ino);
253  mount_point_->inode_cache()->Insert(ino, *dirent);
254  return true;
255  }
256 
257  bool retval = mount_point_->inode_tracker()->FindPath(ino, &path);
258  if (!retval) {
259  // Can this ever happen?
261  "GetDirentForInode inode lookup failure %" PRId64, ino);
262  *dirent = dirent_negative;
263  return false;
264  }
265  if (catalog_mgr->LookupPath(path, catalog::kLookupSole, dirent)) {
266  // Fix inodes
267  dirent->set_inode(ino);
268  mount_point_->inode_cache()->Insert(ino, *dirent);
269  return true;
270  }
271 
272  // Can happen after reload of catalogs or on catalog load failure
273  LogCvmfs(kLogCvmfs, kLogDebug, "GetDirentForInode path lookup failure");
274  return false;
275 }
276 
277 
278 static bool GetDirentForPath(const PathString &path,
279  catalog::DirectoryEntry *dirent)
280 {
281  uint64_t live_inode = 0;
282  if (!file_system_->IsNfsSource())
283  live_inode = mount_point_->inode_tracker()->FindInode(path);
284 
285  shash::Md5 md5path(path.GetChars(), path.GetLength());
286  if (mount_point_->md5path_cache()->Lookup(md5path, dirent)) {
287  if (dirent->GetSpecial() == catalog::kDirentNegative)
288  return false;
289  if (!file_system_->IsNfsSource() && (live_inode != 0))
290  dirent->set_inode(live_inode);
291  return true;
292  }
293 
295 
296  // Lookup inode in catalog TODO: not twice md5 calculation
297  bool retval;
298  retval = catalog_mgr->LookupPath(path, catalog::kLookupSole, dirent);
299  if (retval) {
300  if (file_system_->IsNfsSource()) {
301  // Fix inode
302  dirent->set_inode(file_system_->nfs_maps()->GetInode(path));
303  } else {
304  if (live_inode != 0)
305  dirent->set_inode(live_inode);
306  }
307  mount_point_->md5path_cache()->Insert(md5path, *dirent);
308  return true;
309  }
310 
311  LogCvmfs(kLogCvmfs, kLogDebug, "GetDirentForPath, no entry");
312  // Only insert ENOENT results into negative cache. Otherwise it was an
313  // error loading nested catalogs
314  if (dirent->GetSpecial() == catalog::kDirentNegative)
316  return false;
317 }
318 
319 
320 static bool GetPathForInode(const fuse_ino_t ino, PathString *path) {
321  // Check the path cache first
322  if (mount_point_->path_cache()->Lookup(ino, path))
323  return true;
324 
325  if (file_system_->IsNfsSource()) {
326  // NFS mode, just a lookup
327  LogCvmfs(kLogCvmfs, kLogDebug, "MISS %d - lookup in NFS maps", ino);
328  if (file_system_->nfs_maps()->GetPath(ino, path)) {
329  mount_point_->path_cache()->Insert(ino, *path);
330  return true;
331  }
332  return false;
333  }
334 
335  if (ino == mount_point_->catalog_mgr()->GetRootInode())
336  return true;
337 
338  LogCvmfs(kLogCvmfs, kLogDebug, "MISS %d - looking in inode tracker", ino);
339  bool retval = mount_point_->inode_tracker()->FindPath(ino, path);
340  assert(retval);
341  mount_point_->path_cache()->Insert(ino, *path);
342  return true;
343 }
344 
345 static void DoTraceInode(const int event,
346  fuse_ino_t ino,
347  const std::string &msg)
348 {
349  PathString path;
350  bool found = GetPathForInode(ino, &path);
351  if (!found) {
353  "Tracing: Could not find path for inode %" PRIu64, uint64_t(ino));
354  mount_point_->tracer()->Trace(event, PathString("@UNKNOWN"), msg);
355  } else {
356  mount_point_->tracer()->Trace(event, path, msg);
357  }
358 }
359 
360 static void inline TraceInode(const int event,
361  fuse_ino_t ino,
362  const std::string &msg)
363 {
364  if (mount_point_->tracer()->IsActive()) DoTraceInode(event, ino, msg);
365 }
366 
372 static void cvmfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) {
374 
376  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
377  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
379 
382 
383  fuse_ino_t parent_fuse = parent;
384  parent = catalog_mgr->MangleInode(parent);
386  "cvmfs_lookup in parent inode: %" PRIu64 " for name: %s",
387  uint64_t(parent), name);
388 
389  PathString path;
390  PathString parent_path;
392  struct fuse_entry_param result;
393 
394  memset(&result, 0, sizeof(result));
395  double timeout = GetKcacheTimeout();
396  result.attr_timeout = timeout;
397  result.entry_timeout = timeout;
398 
399  // Special NFS lookups: . and ..
400  if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
401  if (GetDirentForInode(parent, &dirent)) {
402  if (strcmp(name, ".") == 0) {
403  goto lookup_reply_positive;
404  } else {
405  // Lookup for ".."
406  if (dirent.inode() == catalog_mgr->GetRootInode()) {
407  dirent.set_inode(1);
408  goto lookup_reply_positive;
409  }
410  if (!GetPathForInode(parent, &parent_path))
411  goto lookup_reply_negative;
412  if (GetDirentForPath(GetParentPath(parent_path), &dirent))
413  goto lookup_reply_positive;
414  }
415  }
416  // No entry for "." or no entry for ".."
417  if (dirent.GetSpecial() == catalog::kDirentNegative)
418  goto lookup_reply_negative;
419  else
420  goto lookup_reply_error;
421  assert(false);
422  }
423 
424  if (!GetPathForInode(parent, &parent_path)) {
425  LogCvmfs(kLogCvmfs, kLogDebug, "no path for parent inode found");
426  goto lookup_reply_negative;
427  }
428 
429  path.Assign(parent_path);
430  path.Append("/", 1);
431  path.Append(name, strlen(name));
432  mount_point_->tracer()->Trace(Tracer::kEventLookup, path, "lookup()");
433  if (!GetDirentForPath(path, &dirent)) {
434  if (dirent.GetSpecial() == catalog::kDirentNegative)
435  goto lookup_reply_negative;
436  else
437  goto lookup_reply_error;
438  }
439 
440  lookup_reply_positive:
441  if (!file_system_->IsNfsSource())
442  mount_point_->inode_tracker()->VfsGet(dirent.inode(), path);
444  result.ino = dirent.inode();
445  result.attr = dirent.GetStatStructure();
446  fuse_reply_entry(req, &result);
447  return;
448 
449  lookup_reply_negative:
450  // Will be a no-op if there is no fuse cache eviction
451  mount_point_->nentry_tracker()->Add(parent_fuse, name, timeout);
454  result.ino = 0;
455  fuse_reply_entry(req, &result);
456  return;
457 
458  lookup_reply_error:
460  fuse_reply_err(req, EIO);
461 }
462 
463 
467 static void cvmfs_forget(
468  fuse_req_t req,
469  fuse_ino_t ino,
470 #if CVMFS_USE_LIBFUSE == 2
471  unsigned long nlookup // NOLINT
472 #else
473  uint64_t nlookup
474 #endif
475 ) {
477 
479 
480  // The libfuse high-level library does the same
481  if (ino == FUSE_ROOT_ID) {
482  fuse_reply_none(req);
483  return;
484  }
485 
487  ino = mount_point_->catalog_mgr()->MangleInode(ino);
488  // This has been seen to deadlock on the debug log mutex on SL5. Problem of
489  // old kernel/fuse?
490 #if CVMFS_USE_LIBCVMFS == 2
491  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %u",
492  uint64_t(ino), nlookup);
493 #else
494  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %" PRIu64,
495  uint64_t(ino), nlookup);
496 #endif
497  if (!file_system_->IsNfsSource())
498  mount_point_->inode_tracker()->VfsPut(ino, nlookup);
500  fuse_reply_none(req);
501 }
502 
503 
504 #if (FUSE_VERSION >= 29)
505 static void cvmfs_forget_multi(
506  fuse_req_t req,
507  size_t count,
508  struct fuse_forget_data *forgets
509 ) {
511 
513  if (file_system_->IsNfsSource()) {
514  fuse_reply_none(req);
515  return;
516  }
517 
519  for (size_t i = 0; i < count; ++i) {
520  if (forgets[i].ino == FUSE_ROOT_ID) {
521  continue;
522  }
523 
524  uint64_t ino = mount_point_->catalog_mgr()->MangleInode(forgets[i].ino);
525  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %" PRIu64,
526  ino, forgets[i].nlookup);
527 
528  mount_point_->inode_tracker()->VfsPut(ino, forgets[i].nlookup);
529  }
531 
532  fuse_reply_none(req);
533 }
534 #endif // FUSE_VERSION >= 29
535 
536 
543 static void ReplyNegative(const catalog::DirectoryEntry &dirent,
544  fuse_req_t req)
545 {
546  if (dirent.GetSpecial() == catalog::kDirentNegative)
547  fuse_reply_err(req, ENOENT);
548  else
549  fuse_reply_err(req, EIO);
550 }
551 
552 
556 static void cvmfs_getattr(fuse_req_t req, fuse_ino_t ino,
557  struct fuse_file_info *fi)
558 {
560 
562  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
563  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
565 
567  ino = mount_point_->catalog_mgr()->MangleInode(ino);
568  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_getattr (stat) for inode: %" PRIu64,
569  uint64_t(ino));
570 
571  if (!CheckVoms(*fuse_ctx)) {
573  fuse_reply_err(req, EACCES);
574  return;
575  }
577  const bool found = GetDirentForInode(ino, &dirent);
578  TraceInode(Tracer::kEventGetAttr, ino, "getattr()");
580 
581  if (!found) {
582  ReplyNegative(dirent, req);
583  return;
584  }
585 
586  struct stat info = dirent.GetStatStructure();
587 
588  fuse_reply_attr(req, &info, GetKcacheTimeout());
589 }
590 
591 
595 static void cvmfs_readlink(fuse_req_t req, fuse_ino_t ino) {
597 
599  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
600  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
601 
603  ino = mount_point_->catalog_mgr()->MangleInode(ino);
604  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_readlink on inode: %" PRIu64,
605  uint64_t(ino));
606 
608  const bool found = GetDirentForInode(ino, &dirent);
609  TraceInode(Tracer::kEventReadlink, ino, "readlink()");
611 
612  if (!found) {
613  ReplyNegative(dirent, req);
614  return;
615  }
616 
617  if (!dirent.IsLink()) {
618  fuse_reply_err(req, EINVAL);
619  return;
620  }
621 
622  fuse_reply_readlink(req, dirent.symlink().c_str());
623 }
624 
625 
626 static void AddToDirListing(const fuse_req_t req,
627  const char *name, const struct stat *stat_info,
628  BigVector<char> *listing)
629 {
630  LogCvmfs(kLogCvmfs, kLogDebug, "Add to listing: %s, inode %" PRIu64,
631  name, uint64_t(stat_info->st_ino));
632  size_t remaining_size = listing->capacity() - listing->size();
633  const size_t entry_size = fuse_add_direntry(req, NULL, 0, name, stat_info, 0);
634 
635  while (entry_size > remaining_size) {
636  listing->DoubleCapacity();
637  remaining_size = listing->capacity() - listing->size();
638  }
639 
640  char *buffer;
641  bool large_alloc;
642  listing->ShareBuffer(&buffer, &large_alloc);
643  fuse_add_direntry(req, buffer + listing->size(),
644  remaining_size, name, stat_info,
645  listing->size() + entry_size);
646  listing->SetSize(listing->size() + entry_size);
647 }
648 
649 
653 static void cvmfs_opendir(fuse_req_t req, fuse_ino_t ino,
654  struct fuse_file_info *fi)
655 {
657 
658  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
659  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
661 
664  ino = catalog_mgr->MangleInode(ino);
665  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_opendir on inode: %" PRIu64,
666  uint64_t(ino));
667  if (!CheckVoms(*fuse_ctx)) {
669  fuse_reply_err(req, EACCES);
670  return;
671  }
672 
673  TraceInode(Tracer::kEventOpenDir, ino, "opendir()");
674  PathString path;
676  bool found = GetPathForInode(ino, &path);
677  if (!found) {
679  fuse_reply_err(req, ENOENT);
680  return;
681  }
682  found = GetDirentForInode(ino, &d);
683 
684  if (!found) {
686  ReplyNegative(d, req);
687  return;
688  }
689  if (!d.IsDirectory()) {
691  fuse_reply_err(req, ENOTDIR);
692  return;
693  }
694 
695  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_opendir on inode: %" PRIu64 ", path %s",
696  uint64_t(ino), path.c_str());
697 
698  // Build listing
699  BigVector<char> fuse_listing(512);
700 
701  // Add current directory link
702  struct stat info;
703  info = d.GetStatStructure();
704  AddToDirListing(req, ".", &info, &fuse_listing);
705 
706  // Add parent directory link
708  if (d.inode() != catalog_mgr->GetRootInode() &&
709  GetDirentForPath(GetParentPath(path), &p))
710  {
711  info = p.GetStatStructure();
712  AddToDirListing(req, "..", &info, &fuse_listing);
713  }
714 
715  // Add all names
716  catalog::StatEntryList listing_from_catalog;
717  bool retval = catalog_mgr->ListingStat(path, &listing_from_catalog);
718 
719  if (!retval) {
721  fuse_listing.Clear(); // Buffer is shared, empty manually
722  fuse_reply_err(req, EIO);
723  return;
724  }
725  for (unsigned i = 0; i < listing_from_catalog.size(); ++i) {
726  // Fix inodes
727  PathString entry_path;
728  entry_path.Assign(path);
729  entry_path.Append("/", 1);
730  entry_path.Append(listing_from_catalog.AtPtr(i)->name.GetChars(),
731  listing_from_catalog.AtPtr(i)->name.GetLength());
732 
733  catalog::DirectoryEntry entry_dirent;
734  if (!GetDirentForPath(entry_path, &entry_dirent)) {
735  LogCvmfs(kLogCvmfs, kLogDebug, "listing entry %s vanished, skipping",
736  entry_path.c_str());
737  continue;
738  }
739 
740  struct stat fixed_info = listing_from_catalog.AtPtr(i)->info;
741  fixed_info.st_ino = entry_dirent.inode();
742  AddToDirListing(req, listing_from_catalog.AtPtr(i)->name.c_str(),
743  &fixed_info, &fuse_listing);
744  }
746 
747  DirectoryListing stream_listing;
748  stream_listing.size = fuse_listing.size();
749  stream_listing.capacity = fuse_listing.capacity();
750  bool large_alloc;
751  fuse_listing.ShareBuffer(&stream_listing.buffer, &large_alloc);
752  if (large_alloc)
753  stream_listing.capacity = 0;
754 
755  // Save the directory listing and return a handle to the listing
756  {
759  "linking directory handle %d to dir inode: %" PRIu64,
760  next_directory_handle_, uint64_t(ino));
761  (*directory_handles_)[next_directory_handle_] = stream_listing;
762  fi->fh = next_directory_handle_;
764  }
767 
768 #if (FUSE_VERSION >= 30)
769 #ifdef CVMFS_ENABLE_FUSE3_CACHE_READDIR
770  // This affects only reads on the same open directory handle (e.g. multiple
771  // reads with rewinddir() between them). A new opendir on the same directory
772  // will trigger readdir calls independently of this setting.
773  fi->cache_readdir = 1;
774 #endif
775 #endif
776  fuse_reply_open(req, fi);
777 }
778 
779 
783 static void cvmfs_releasedir(fuse_req_t req, fuse_ino_t ino,
784  struct fuse_file_info *fi)
785 {
787 
788  ino = mount_point_->catalog_mgr()->MangleInode(ino);
789  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_releasedir on inode %" PRIu64
790  ", handle %d", uint64_t(ino), fi->fh);
791 
792  int reply = 0;
793 
794  {
796  DirectoryHandles::iterator iter_handle = directory_handles_->find(fi->fh);
797  if (iter_handle != directory_handles_->end()) {
798  if (iter_handle->second.capacity == 0)
799  smunmap(iter_handle->second.buffer);
800  else
801  free(iter_handle->second.buffer);
802  directory_handles_->erase(iter_handle);
804  } else {
805  reply = EINVAL;
806  }
807  }
808 
809  fuse_reply_err(req, reply);
810 }
811 
812 
816 static void ReplyBufferSlice(const fuse_req_t req, const char *buffer,
817  const size_t buffer_size, const off_t offset,
818  const size_t max_size)
819 {
820  if (offset < static_cast<int>(buffer_size)) {
821  fuse_reply_buf(req, buffer + offset,
822  std::min(static_cast<size_t>(buffer_size - offset), max_size));
823  } else {
824  fuse_reply_buf(req, NULL, 0);
825  }
826 }
827 
828 
832 static void cvmfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
833  off_t off, struct fuse_file_info *fi)
834 {
836 
838  "cvmfs_readdir on inode %" PRIu64 " reading %d bytes from offset %d",
839  uint64_t(mount_point_->catalog_mgr()->MangleInode(ino)), size, off);
840 
841  DirectoryListing listing;
842 
844  DirectoryHandles::const_iterator iter_handle =
845  directory_handles_->find(fi->fh);
846  if (iter_handle != directory_handles_->end()) {
847  listing = iter_handle->second;
848 
849  ReplyBufferSlice(req, listing.buffer, listing.size, off, size);
850  return;
851  }
852 
853  fuse_reply_err(req, EINVAL);
854 }
855 
856 
863 static void cvmfs_open(fuse_req_t req, fuse_ino_t ino,
864  struct fuse_file_info *fi)
865 {
867 
868  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
869  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
872  ino = catalog_mgr->MangleInode(ino);
873  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_open on inode: %" PRIu64,
874  uint64_t(ino));
875 
876  int fd = -1;
878  PathString path;
879 
880  bool found = GetPathForInode(ino, &path);
881  if (!found) {
883  fuse_reply_err(req, ENOENT);
884  return;
885  }
886  found = GetDirentForInode(ino, &dirent);
887  if (!found) {
889  ReplyNegative(dirent, req);
890  return;
891  }
892 
893  if (!CheckVoms(*fuse_ctx)) {
895  fuse_reply_err(req, EACCES);
896  return;
897  }
898 
899  mount_point_->tracer()->Trace(Tracer::kEventOpen, path, "open()");
900  // Don't check. Either done by the OS or one wants to purposefully work
901  // around wrong open flags
902  // if ((fi->flags & 3) != O_RDONLY) {
903  // fuse_reply_err(req, EROFS);
904  // return;
905  // }
906 #ifdef __APPLE__
907  if ((fi->flags & O_SHLOCK) || (fi->flags & O_EXLOCK)) {
909  fuse_reply_err(req, EOPNOTSUPP);
910  return;
911  }
912 #endif
913  if (fi->flags & O_EXCL) {
915  fuse_reply_err(req, EEXIST);
916  return;
917  }
918 
919  perf::Inc(file_system_->n_fs_open()); // Count actual open / fetch operations
920 
921  if (!dirent.IsChunkedFile()) {
923  } else {
925  "chunked file %s opened (download delayed to read() call)",
926  path.c_str());
927 
929  (static_cast<int>(max_open_files_))-kNumReservedFd)
930  {
933  LogCvmfs(kLogCvmfs, kLogSyslogErr, "open file descriptor limit exceeded");
934  fuse_reply_err(req, EMFILE);
935  return;
936  }
937 
938  // Figure out unique inode from annotated catalog
939  catalog::DirectoryEntry dirent_origin;
940  if (!catalog_mgr->LookupPath(path, catalog::kLookupSole, &dirent_origin)) {
943  "chunked file %s vanished unexpectedly", path.c_str());
944  fuse_reply_err(req, ENOENT);
945  return;
946  }
947  const uint64_t unique_inode = dirent_origin.inode();
948 
949  ChunkTables *chunk_tables = mount_point_->chunk_tables();
950  chunk_tables->Lock();
951  if (!chunk_tables->inode2chunks.Contains(unique_inode)) {
952  chunk_tables->Unlock();
953 
954  // Retrieve File chunks from the catalog
956  if (!catalog_mgr->ListFileChunks(path, dirent.hash_algorithm(),
957  chunks.weak_ref()) ||
958  chunks->IsEmpty())
959  {
961  LogCvmfs(kLogCvmfs, kLogDebug| kLogSyslogErr, "file %s is marked as "
962  "'chunked', but no chunks found.", path.c_str());
963  fuse_reply_err(req, EIO);
964  return;
965  }
967 
968  chunk_tables->Lock();
969  // Check again to avoid race
970  if (!chunk_tables->inode2chunks.Contains(unique_inode)) {
971  chunk_tables->inode2chunks.Insert(
972  unique_inode, FileChunkReflist(chunks.Release(), path,
973  dirent.compression_algorithm(),
974  dirent.IsExternalFile()));
975  chunk_tables->inode2references.Insert(unique_inode, 1);
976  } else {
977  uint32_t refctr;
978  bool retval =
979  chunk_tables->inode2references.Lookup(unique_inode, &refctr);
980  assert(retval);
981  chunk_tables->inode2references.Insert(unique_inode, refctr+1);
982  }
983  } else {
985  uint32_t refctr;
986  bool retval =
987  chunk_tables->inode2references.Lookup(unique_inode, &refctr);
988  assert(retval);
989  chunk_tables->inode2references.Insert(unique_inode, refctr+1);
990  }
991 
992  // Update the chunk handle list
994  "linking chunk handle %d to unique inode: %" PRIu64,
995  chunk_tables->next_handle, uint64_t(unique_inode));
996  chunk_tables->handle2fd.Insert(chunk_tables->next_handle, ChunkFd());
997  chunk_tables->handle2uniqino.Insert(chunk_tables->next_handle,
998  unique_inode);
999  // The same inode can refer to different revisions of a path. Don't cache.
1000  fi->keep_cache = 0;
1001  fi->direct_io = dirent.IsDirectIo();
1002  fi->fh = static_cast<uint64_t>(-chunk_tables->next_handle);
1003  ++chunk_tables->next_handle;
1004  chunk_tables->Unlock();
1005 
1006  fuse_reply_open(req, fi);
1007  return;
1008  }
1009 
1010  Fetcher *this_fetcher = dirent.IsExternalFile()
1012  : mount_point_->fetcher();
1013  fd = this_fetcher->Fetch(
1014  dirent.checksum(),
1015  dirent.size(),
1016  string(path.GetChars(), path.GetLength()),
1017  dirent.compression_algorithm(),
1021 
1022  if (fd >= 0) {
1024  (static_cast<int>(max_open_files_))-kNumReservedFd) {
1025  LogCvmfs(kLogCvmfs, kLogDebug, "file %s opened (fd %d)",
1026  path.c_str(), fd);
1027  // The same inode can refer to different revisions of a path. Don't cache.
1028  fi->keep_cache = 0;
1029  fi->direct_io = dirent.IsDirectIo();
1030  fi->fh = fd;
1031  fuse_reply_open(req, fi);
1032  return;
1033  } else {
1034  if (file_system_->cache_mgr()->Close(fd) == 0)
1036  LogCvmfs(kLogCvmfs, kLogSyslogErr, "open file descriptor limit exceeded");
1037  fuse_reply_err(req, EMFILE);
1038  return;
1039  }
1040  assert(false);
1041  }
1042 
1043  // fd < 0
1045  "failed to open inode: %" PRIu64 ", CAS key %s, error code %d",
1046  uint64_t(ino), dirent.checksum().ToString().c_str(), errno);
1047  if (errno == EMFILE) {
1048  fuse_reply_err(req, EMFILE);
1049  return;
1050  }
1051 
1053 
1055  fuse_reply_err(req, -fd);
1056 }
1057 
1058 
1062 static void cvmfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1063  struct fuse_file_info *fi)
1064 {
1066 
1068  "cvmfs_read inode: %" PRIu64 " reading %d bytes from offset %d "
1069  "fd %d", uint64_t(mount_point_->catalog_mgr()->MangleInode(ino)),
1070  size, off, fi->fh);
1072 
1073  // Get data chunk (<=128k guaranteed by Fuse)
1074  char *data = static_cast<char *>(alloca(size));
1075  unsigned int overall_bytes_fetched = 0;
1076 
1077  // Do we have a a chunked file?
1078  if (static_cast<int64_t>(fi->fh) < 0) {
1079  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1080  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
1081 
1082  const uint64_t chunk_handle =
1083  static_cast<uint64_t>(-static_cast<int64_t>(fi->fh));
1084  uint64_t unique_inode;
1085  ChunkFd chunk_fd;
1086  FileChunkReflist chunks;
1087  bool retval;
1088 
1089  // Fetch unique inode, chunk list and file descriptor
1090  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1091  chunk_tables->Lock();
1092  retval = chunk_tables->handle2uniqino.Lookup(chunk_handle, &unique_inode);
1093  if (!retval) {
1094  LogCvmfs(kLogCvmfs, kLogDebug, "no unique inode, fall back to fuse ino");
1095  unique_inode = ino;
1096  }
1097  retval = chunk_tables->inode2chunks.Lookup(unique_inode, &chunks);
1098  assert(retval);
1099  chunk_tables->Unlock();
1100 
1101  unsigned chunk_idx = chunks.FindChunkIdx(off);
1102 
1103  // Lock chunk handle
1104  pthread_mutex_t *handle_lock = chunk_tables->Handle2Lock(chunk_handle);
1105  MutexLockGuard m(handle_lock);
1106  chunk_tables->Lock();
1107  retval = chunk_tables->handle2fd.Lookup(chunk_handle, &chunk_fd);
1108  assert(retval);
1109  chunk_tables->Unlock();
1110 
1111  // Fetch all needed chunks and read the requested data
1112  off_t offset_in_chunk = off - chunks.list->AtPtr(chunk_idx)->offset();
1113  do {
1114  // Open file descriptor to chunk
1115  if ((chunk_fd.fd == -1) || (chunk_fd.chunk_idx != chunk_idx)) {
1116  if (chunk_fd.fd != -1) file_system_->cache_mgr()->Close(chunk_fd.fd);
1117  string verbose_path = "Part of " + chunks.path.ToString();
1118  if (chunks.external_data) {
1119  chunk_fd.fd = mount_point_->external_fetcher()->Fetch(
1120  chunks.list->AtPtr(chunk_idx)->content_hash(),
1121  chunks.list->AtPtr(chunk_idx)->size(),
1122  verbose_path,
1123  chunks.compression_alg,
1127  chunks.path.ToString(),
1128  chunks.list->AtPtr(chunk_idx)->offset());
1129  } else {
1130  chunk_fd.fd = mount_point_->fetcher()->Fetch(
1131  chunks.list->AtPtr(chunk_idx)->content_hash(),
1132  chunks.list->AtPtr(chunk_idx)->size(),
1133  verbose_path,
1134  chunks.compression_alg,
1138  }
1139  if (chunk_fd.fd < 0) {
1140  chunk_fd.fd = -1;
1141  chunk_tables->Lock();
1142  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1143  chunk_tables->Unlock();
1144  fuse_reply_err(req, EIO);
1145  return;
1146  }
1147  chunk_fd.chunk_idx = chunk_idx;
1148  }
1149 
1150  LogCvmfs(kLogCvmfs, kLogDebug, "reading from chunk fd %d",
1151  chunk_fd.fd);
1152  // Read data from chunk
1153  const size_t bytes_to_read = size - overall_bytes_fetched;
1154  const size_t remaining_bytes_in_chunk =
1155  chunks.list->AtPtr(chunk_idx)->size() - offset_in_chunk;
1156  size_t bytes_to_read_in_chunk =
1157  std::min(bytes_to_read, remaining_bytes_in_chunk);
1158  const int64_t bytes_fetched = file_system_->cache_mgr()->Pread(
1159  chunk_fd.fd,
1160  data + overall_bytes_fetched,
1161  bytes_to_read_in_chunk,
1162  offset_in_chunk);
1163 
1164  if (bytes_fetched < 0) {
1165  LogCvmfs(kLogCvmfs, kLogSyslogErr, "read err no %" PRId64 " (%s)",
1166  bytes_fetched, chunks.path.ToString().c_str());
1167  chunk_tables->Lock();
1168  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1169  chunk_tables->Unlock();
1170  fuse_reply_err(req, -bytes_fetched);
1171  return;
1172  }
1173  overall_bytes_fetched += bytes_fetched;
1174 
1175  // Proceed to the next chunk to keep on reading data
1176  ++chunk_idx;
1177  offset_in_chunk = 0;
1178  } while ((overall_bytes_fetched < size) &&
1179  (chunk_idx < chunks.list->size()));
1180 
1181  // Update chunk file descriptor
1182  chunk_tables->Lock();
1183  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1184  chunk_tables->Unlock();
1185  LogCvmfs(kLogCvmfs, kLogDebug, "released chunk file descriptor %d",
1186  chunk_fd.fd);
1187  } else {
1188  const int64_t fd = fi->fh;
1189  int64_t nbytes = file_system_->cache_mgr()->Pread(fd, data, size, off);
1190  if (nbytes < 0) {
1191  fuse_reply_err(req, -nbytes);
1192  return;
1193  }
1194  overall_bytes_fetched = nbytes;
1195  }
1196 
1197  // Push it to user
1198  fuse_reply_buf(req, data, overall_bytes_fetched);
1199  LogCvmfs(kLogCvmfs, kLogDebug, "pushed %d bytes to user",
1200  overall_bytes_fetched);
1201 }
1202 
1203 
1207 static void cvmfs_release(fuse_req_t req, fuse_ino_t ino,
1208  struct fuse_file_info *fi)
1209 {
1211 
1212  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1213  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_release on inode: %" PRIu64,
1214  uint64_t(ino));
1215  const int64_t fd = fi->fh;
1216 
1217  // do we have a chunked file?
1218  if (static_cast<int64_t>(fi->fh) < 0) {
1219  const uint64_t chunk_handle =
1220  static_cast<uint64_t>(-static_cast<int64_t>(fi->fh));
1221  LogCvmfs(kLogCvmfs, kLogDebug, "releasing chunk handle %" PRIu64,
1222  chunk_handle);
1223  uint64_t unique_inode;
1224  ChunkFd chunk_fd;
1225  FileChunkReflist chunks;
1226  uint32_t refctr;
1227  bool retval;
1228 
1229  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1230  chunk_tables->Lock();
1231  retval = chunk_tables->handle2uniqino.Lookup(chunk_handle, &unique_inode);
1232  if (!retval) {
1233  LogCvmfs(kLogCvmfs, kLogDebug, "no unique inode, fall back to fuse ino");
1234  unique_inode = ino;
1235  } else {
1236  chunk_tables->handle2uniqino.Erase(chunk_handle);
1237  }
1238  retval = chunk_tables->handle2fd.Lookup(chunk_handle, &chunk_fd);
1239  assert(retval);
1240  chunk_tables->handle2fd.Erase(chunk_handle);
1241 
1242  retval = chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1243  assert(retval);
1244  refctr--;
1245  if (refctr == 0) {
1246  LogCvmfs(kLogCvmfs, kLogDebug, "releasing chunk list for inode %" PRIu64,
1247  uint64_t(unique_inode));
1248  FileChunkReflist to_delete;
1249  retval = chunk_tables->inode2chunks.Lookup(unique_inode, &to_delete);
1250  assert(retval);
1251  chunk_tables->inode2references.Erase(unique_inode);
1252  chunk_tables->inode2chunks.Erase(unique_inode);
1253  delete to_delete.list;
1254  } else {
1255  chunk_tables->inode2references.Insert(unique_inode, refctr);
1256  }
1257  chunk_tables->Unlock();
1258 
1259  if (chunk_fd.fd != -1)
1260  file_system_->cache_mgr()->Close(chunk_fd.fd);
1262  } else {
1263  if (file_system_->cache_mgr()->Close(fd) == 0) {
1265  }
1266  }
1267  fuse_reply_err(req, 0);
1268 }
1269 
1270 
1271 static void cvmfs_statfs(fuse_req_t req, fuse_ino_t ino) {
1272  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1273  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_statfs on inode: %" PRIu64,
1274  uint64_t(ino));
1275 
1276  // If we return 0 it will cause the fs to be ignored in "df"
1277  struct statvfs info;
1278  memset(&info, 0, sizeof(info));
1279 
1280  TraceInode(Tracer::kEventStatFs, ino, "statfs()");
1281 
1282  // Unmanaged cache
1285  {
1286  fuse_reply_statfs(req, &info);
1287  return;
1288  }
1289 
1290  uint64_t available = 0;
1291  uint64_t size = file_system_->cache_mgr()->quota_mgr()->GetSize();
1292  uint64_t capacity = file_system_->cache_mgr()->quota_mgr()->GetCapacity();
1293  // Fuse/OS X doesn't like values < 512
1294  info.f_bsize = info.f_frsize = 512;
1295 
1296  if (capacity == (uint64_t)(-1)) {
1297  // Unknown capacity, set capacity = size
1298  info.f_blocks = size / info.f_bsize;
1299  } else {
1300  // Take values from LRU module
1301  info.f_blocks = capacity / info.f_bsize;
1302  available = capacity - size;
1303  }
1304 
1305  info.f_bfree = info.f_bavail = available / info.f_bsize;
1306 
1307  // Inodes / entries
1308  fuse_remounter_->fence()->Enter();
1309  uint64_t all_inodes = mount_point_->catalog_mgr()->all_inodes();
1310  uint64_t loaded_inode = mount_point_->catalog_mgr()->loaded_inodes();
1311  info.f_files = all_inodes;
1312  info.f_ffree = info.f_favail = all_inodes - loaded_inode;
1313  fuse_remounter_->fence()->Leave();
1314 
1315  fuse_reply_statfs(req, &info);
1316 }
1317 
1318 #ifdef __APPLE__
1319 static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1320  size_t size, uint32_t position)
1321 #else
1322 static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1323  size_t size)
1324 #endif
1325 {
1326  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1327  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
1328 
1329  fuse_remounter_->fence()->Enter();
1331  ino = catalog_mgr->MangleInode(ino);
1333  "cvmfs_getxattr on inode: %" PRIu64 " for xattr: %s",
1334  uint64_t(ino), name);
1335  if (!CheckVoms(*fuse_ctx)) {
1336  fuse_remounter_->fence()->Leave();
1337  fuse_reply_err(req, EACCES);
1338  return;
1339  }
1340  TraceInode(Tracer::kEventGetXAttr, ino, "getxattr()");
1341 
1342  const string attr = name;
1344  const bool found = GetDirentForInode(ino, &d);
1345  bool retval;
1346  XattrList xattrs;
1347 
1348  PathString path;
1349  retval = GetPathForInode(ino, &path);
1350  assert(retval);
1351  if (d.IsLink()) {
1352  catalog::LookupOptions lookup_options = static_cast<catalog::LookupOptions>(
1354  catalog::DirectoryEntry raw_symlink;
1355  retval = catalog_mgr->LookupPath(path, lookup_options, &raw_symlink);
1356  assert(retval);
1357  d.set_symlink(raw_symlink.symlink());
1358  }
1359  if (d.HasXattrs()) {
1360  retval = catalog_mgr->LookupXattrs(path, &xattrs);
1361  assert(retval);
1362  }
1363 
1364  bool magic_xattr_success = true;
1366  attr, path, &d));
1367  if (!magic_xattr.IsNull()) {
1368  magic_xattr_success = magic_xattr->PrepareValueFenced();
1369  }
1370 
1371  fuse_remounter_->fence()->Leave();
1372 
1373  if (!found) {
1374  ReplyNegative(d, req);
1375  return;
1376  }
1377 
1378  if (!magic_xattr_success) {
1379  fuse_reply_err(req, ENOATTR);
1380  return;
1381  }
1382 
1383  string attribute_value;
1384 
1385  if (!magic_xattr.IsNull()) {
1386  attribute_value = magic_xattr->GetValue();
1387  } else {
1388  if (!xattrs.Get(attr, &attribute_value)) {
1389  fuse_reply_err(req, ENOATTR);
1390  return;
1391  }
1392  }
1393 
1394  if (size == 0) {
1395  fuse_reply_xattr(req, attribute_value.length());
1396  } else if (size >= attribute_value.length()) {
1397  fuse_reply_buf(req, &attribute_value[0], attribute_value.length());
1398  } else {
1399  fuse_reply_err(req, ERANGE);
1400  }
1401 }
1402 
1403 
1404 static void cvmfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) {
1405  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1406  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
1407 
1408  fuse_remounter_->fence()->Enter();
1410  ino = catalog_mgr->MangleInode(ino);
1411  TraceInode(Tracer::kEventListAttr, ino, "listxattr()");
1413  "cvmfs_listxattr on inode: %" PRIu64 ", size %u [hide xattrs %d]",
1414  uint64_t(ino), size,
1416 
1418  const bool found = GetDirentForInode(ino, &d);
1419  XattrList xattrs;
1420  if (d.HasXattrs()) {
1421  PathString path;
1422  bool retval = GetPathForInode(ino, &path);
1423  assert(retval);
1424  retval = catalog_mgr->LookupXattrs(path, &xattrs);
1425  assert(retval);
1426  }
1427  fuse_remounter_->fence()->Leave();
1428 
1429  if (!found) {
1430  ReplyNegative(d, req);
1431  return;
1432  }
1433 
1434  string attribute_list;
1435  attribute_list = mount_point_->magic_xattr_mgr()->GetListString(&d);
1436  attribute_list = xattrs.ListKeysPosix(attribute_list);
1437 
1438  if (size == 0) {
1439  fuse_reply_xattr(req, attribute_list.length());
1440  } else if (size >= attribute_list.length()) {
1441  if (attribute_list.empty())
1442  fuse_reply_buf(req, NULL, 0);
1443  else
1444  fuse_reply_buf(req, &attribute_list[0], attribute_list.length());
1445  } else {
1446  fuse_reply_err(req, ERANGE);
1447  }
1448 }
1449 
1450 
1451 bool Evict(const string &path) {
1452  catalog::DirectoryEntry dirent;
1453  fuse_remounter_->fence()->Enter();
1454  const bool found = GetDirentForPath(PathString(path), &dirent);
1455  fuse_remounter_->fence()->Leave();
1456 
1457  if (!found || !dirent.IsRegular())
1458  return false;
1459  file_system_->cache_mgr()->quota_mgr()->Remove(dirent.checksum());
1460  return true;
1461 }
1462 
1463 
1464 bool Pin(const string &path) {
1465  catalog::DirectoryEntry dirent;
1466  fuse_remounter_->fence()->Enter();
1467  const bool found = GetDirentForPath(PathString(path), &dirent);
1468  if (!found || !dirent.IsRegular()) {
1469  fuse_remounter_->fence()->Leave();
1470  return false;
1471  }
1472 
1473  if (!dirent.IsChunkedFile()) {
1474  fuse_remounter_->fence()->Leave();
1475  } else {
1476  FileChunkList chunks;
1478  PathString(path), dirent.hash_algorithm(), &chunks);
1479  fuse_remounter_->fence()->Leave();
1480  for (unsigned i = 0; i < chunks.size(); ++i) {
1481  bool retval =
1483  chunks.AtPtr(i)->content_hash(),
1484  chunks.AtPtr(i)->size(),
1485  "Part of " + path,
1486  false);
1487  if (!retval)
1488  return false;
1489  int fd = -1;
1490  if (dirent.IsExternalFile()) {
1492  chunks.AtPtr(i)->content_hash(),
1493  chunks.AtPtr(i)->size(),
1494  "Part of " + path,
1495  dirent.compression_algorithm(),
1497  path,
1498  chunks.AtPtr(i)->offset());
1499  } else {
1500  fd = mount_point_->fetcher()->Fetch(
1501  chunks.AtPtr(i)->content_hash(),
1502  chunks.AtPtr(i)->size(),
1503  "Part of " + path,
1504  dirent.compression_algorithm(),
1506  }
1507  if (fd < 0) {
1508  return false;
1509  }
1510  file_system_->cache_mgr()->Close(fd);
1511  }
1512  return true;
1513  }
1514 
1515  bool retval = file_system_->cache_mgr()->quota_mgr()->Pin(
1516  dirent.checksum(), dirent.size(), path, false);
1517  if (!retval)
1518  return false;
1519  Fetcher *this_fetcher = dirent.IsExternalFile()
1521  : mount_point_->fetcher();
1522  int fd = this_fetcher->Fetch(
1523  dirent.checksum(), dirent.size(), path, dirent.compression_algorithm(),
1525  if (fd < 0) {
1526  return false;
1527  }
1528  file_system_->cache_mgr()->Close(fd);
1529  return true;
1530 }
1531 
1532 
1536 static void cvmfs_init(void *userdata, struct fuse_conn_info *conn) {
1537  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_init");
1538 
1539  // NFS support
1540 #ifdef CVMFS_NFS_SUPPORT
1541  conn->want |= FUSE_CAP_EXPORT_SUPPORT;
1542 #endif
1543 
1544  if (mount_point_->enforce_acls()) {
1545 #ifdef FUSE_CAP_POSIX_ACL
1546  if ((conn->capable & FUSE_CAP_POSIX_ACL) == 0) {
1548  "ACL support requested but missing fuse kernel support, "
1549  "aborting");
1550  }
1551  conn->want |= FUSE_CAP_POSIX_ACL;
1552  LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog, "enforcing ACLs");
1553 #else
1555  "ACL support requested but not available in this version of "
1556  "libfuse, aborting");
1557 #endif
1558  }
1559 }
1560 
1561 static void cvmfs_destroy(void *unused __attribute__((unused))) {
1562  // The debug log is already closed at this point
1563  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_destroy");
1564 }
1565 
1569 static void SetCvmfsOperations(struct fuse_lowlevel_ops *cvmfs_operations) {
1570  memset(cvmfs_operations, 0, sizeof(*cvmfs_operations));
1571 
1572  // Init/Fini
1573  cvmfs_operations->init = cvmfs_init;
1574  cvmfs_operations->destroy = cvmfs_destroy;
1575 
1576  cvmfs_operations->lookup = cvmfs_lookup;
1577  cvmfs_operations->getattr = cvmfs_getattr;
1578  cvmfs_operations->readlink = cvmfs_readlink;
1579  cvmfs_operations->open = cvmfs_open;
1580  cvmfs_operations->read = cvmfs_read;
1581  cvmfs_operations->release = cvmfs_release;
1582  cvmfs_operations->opendir = cvmfs_opendir;
1583  cvmfs_operations->readdir = cvmfs_readdir;
1584  cvmfs_operations->releasedir = cvmfs_releasedir;
1585  cvmfs_operations->statfs = cvmfs_statfs;
1586  cvmfs_operations->getxattr = cvmfs_getxattr;
1587  cvmfs_operations->listxattr = cvmfs_listxattr;
1588  cvmfs_operations->forget = cvmfs_forget;
1589 #if (FUSE_VERSION >= 29)
1590  cvmfs_operations->forget_multi = cvmfs_forget_multi;
1591 #endif
1592 }
1593 
1594 // Called by cvmfs_talk when switching into read-only cache mode
1596  if (cvmfs::unpin_listener_) {
1598  cvmfs::unpin_listener_ = NULL;
1599  }
1603  }
1604 }
1605 
1606 bool SendFuseFd(const std::string &socket_path) {
1607  int fuse_fd;
1608 #if (FUSE_VERSION >= 30)
1609  fuse_fd = fuse_session_fd(*reinterpret_cast<struct fuse_session**>(
1611 #else
1612  fuse_fd = fuse_chan_fd(*reinterpret_cast<struct fuse_chan**>(
1614 #endif
1615  assert(fuse_fd >= 0);
1616  int sock_fd = ConnectSocket(socket_path);
1617  if (sock_fd < 0) {
1618  LogCvmfs(kLogCvmfs, kLogDebug, "cannot connect to socket %s: %d",
1619  socket_path.c_str(), errno);
1620  return false;
1621  }
1622  bool retval = SendFd2Socket(sock_fd, fuse_fd);
1623  close(sock_fd);
1624  return retval;
1625 }
1626 
1627 } // namespace cvmfs
1628 
1629 
1630 string *g_boot_error = NULL;
1631 
1632 __attribute__((visibility("default")))
1633 loader::CvmfsExports *g_cvmfs_exports = NULL;
1634 
1641 
1642  virtual bool PrepareValueFenced() {
1643  catalogs_valid_until_ = cvmfs::fuse_remounter_->catalogs_valid_until();
1644  return true;
1645  }
1646 
1647  virtual std::string GetValue() {
1648  if (catalogs_valid_until_ == MountPoint::kIndefiniteDeadline) {
1649  return "never (fixed root catalog)";
1650  } else {
1651  time_t now = time(NULL);
1652  return StringifyInt( (catalogs_valid_until_ - now) / 60);
1653  }
1654  }
1655 };
1656 
1658  virtual std::string GetValue() {
1659  return StringifyInt(
1660  cvmfs::inode_generation_info_.inode_generation +
1662  }
1663 };
1664 
1666  virtual std::string GetValue() {
1668  }
1669 };
1670 
1672  virtual std::string GetValue() { return StringifyInt(cvmfs::pid_); }
1673 };
1674 
1676  virtual std::string GetValue() {
1677  time_t now = time(NULL);
1678  uint64_t uptime = now - cvmfs::loader_exports_->boot_time;
1679  return StringifyInt(uptime / 60);
1680  }
1681 };
1682 
1687 static void RegisterMagicXattrs() {
1689  mgr->Register("user.expires", new ExpiresMagicXattr());
1690  mgr->Register("user.inode_max", new InodeMaxMagicXattr());
1691  mgr->Register("user.pid", new PidMagicXattr());
1692  mgr->Register("user.maxfd", new MaxFdMagicXattr());
1693  mgr->Register("user.uptime", new UptimeMagicXattr());
1694 }
1695 
1701  const string &mount_path,
1702  const string &fqrn,
1704 {
1705  fs_info.wait_workspace = false;
1706  FileSystem *file_system = FileSystem::Create(fs_info);
1707 
1708  if (file_system->boot_status() == loader::kFailLockWorkspace) {
1709  string fqrn_from_xattr;
1710  int retval = platform_getxattr(mount_path, "user.fqrn", &fqrn_from_xattr);
1711  if (!retval) {
1712  // Cvmfs not mounted anymore, but another cvmfs process is still in
1713  // shutdown procedure. Try again and wait for lock
1714  delete file_system;
1715  fs_info.wait_workspace = true;
1716  file_system = FileSystem::Create(fs_info);
1717  } else {
1718  if (fqrn_from_xattr == fqrn) {
1720  "repository already mounted on %s", mount_path.c_str());
1722  } else {
1724  "CernVM-FS repository %s already mounted on %s",
1725  fqrn.c_str(), mount_path.c_str());
1727  }
1728  }
1729  }
1730 
1731  return file_system;
1732 }
1733 
1734 
1735 static void InitOptionsMgr(const loader::LoaderExports *loader_exports) {
1736  if (loader_exports->version >= 3 && loader_exports->simple_options_parsing) {
1738  new DefaultOptionsTemplateManager(loader_exports->repository_name));
1739  } else {
1741  new DefaultOptionsTemplateManager(loader_exports->repository_name));
1742  }
1743 
1744  if (loader_exports->config_files != "") {
1745  vector<string> tokens = SplitString(loader_exports->config_files, ':');
1746  for (unsigned i = 0, s = tokens.size(); i < s; ++i) {
1747  cvmfs::options_mgr_->ParsePath(tokens[i], false);
1748  }
1749  } else {
1751  }
1752 }
1753 
1754 
1755 static int Init(const loader::LoaderExports *loader_exports) {
1756  g_boot_error = new string("unknown error");
1757  cvmfs::loader_exports_ = loader_exports;
1758  InitOptionsMgr(loader_exports);
1759 
1761  fs_info.type = FileSystem::kFsFuse;
1762  fs_info.name = loader_exports->repository_name;
1763  fs_info.exe_path = loader_exports->program_name;
1764  fs_info.options_mgr = cvmfs::options_mgr_;
1765  fs_info.foreground = loader_exports->foreground;
1767  loader_exports->mount_point,
1768  loader_exports->repository_name,
1769  fs_info);
1770  if (!cvmfs::file_system_->IsValid()) {
1772  return cvmfs::file_system_->boot_status();
1773  }
1774 
1777  if (!cvmfs::mount_point_->IsValid()) {
1779  return cvmfs::mount_point_->boot_status();
1780  }
1781 
1783 
1785  cvmfs::directory_handles_->set_empty_key((uint64_t)(-1));
1786  cvmfs::directory_handles_->set_deleted_key((uint64_t)(-2));
1787 
1788  LogCvmfs(kLogCvmfs, kLogDebug, "fuse inode size is %d bits",
1789  sizeof(fuse_ino_t) * 8);
1790 
1795  LogCvmfs(kLogCvmfs, kLogDebug, "root inode is %" PRIu64,
1796  uint64_t(cvmfs::mount_point_->catalog_mgr()->GetRootInode()));
1797 
1798  void **channel_or_session = NULL;
1799  if (loader_exports->version >= 4) {
1800  channel_or_session = loader_exports->fuse_channel_or_session;
1801  }
1802 
1803  bool fuse_notify_invalidation = true;
1804  std::string buf;
1805  if (cvmfs::options_mgr_->GetValue("CVMFS_FUSE_NOTIFY_INVALIDATION",
1806  &buf)) {
1807  if (!cvmfs::options_mgr_->IsOn(buf)) {
1808  fuse_notify_invalidation = false;
1810  }
1811  }
1814  channel_or_session, fuse_notify_invalidation);
1815 
1816  // Monitor, check for maximum number of open files
1817  if (cvmfs::UseWatchdog()) {
1818  cvmfs::watchdog_ = Watchdog::Create("./stacktrace." +
1819  loader_exports->repository_name);
1820  if (cvmfs::watchdog_ == NULL) {
1821  *g_boot_error = "failed to initialize watchdog.";
1822  return loader::kFailMonitor;
1823  }
1824  }
1826 
1827  // Control & command interface
1829  cvmfs::mount_point_->talk_socket_path(),
1832  if ((cvmfs::mount_point_->talk_socket_uid() != 0) ||
1833  (cvmfs::mount_point_->talk_socket_gid() != 0))
1834  {
1835  uid_t tgt_uid = cvmfs::mount_point_->talk_socket_uid();
1836  gid_t tgt_gid = cvmfs::mount_point_->talk_socket_gid();
1837  int rvi = chown(cvmfs::mount_point_->talk_socket_path().c_str(),
1838  tgt_uid, tgt_gid);
1839  if (rvi != 0) {
1840  *g_boot_error = std::string("failed to set talk socket ownership - ")
1841  + "target " + StringifyInt(tgt_uid) + ":" + StringifyInt(tgt_uid)
1842  + ", user " + StringifyInt(geteuid()) + ":" + StringifyInt(getegid());
1843  return loader::kFailTalk;
1844  }
1845  }
1846  if (cvmfs::talk_mgr_ == NULL) {
1847  *g_boot_error = "failed to initialize talk socket (" +
1848  StringifyInt(errno) + ")";
1849  return loader::kFailTalk;
1850  }
1851 
1852  // Notification system client
1853  {
1855  if (options->IsDefined("CVMFS_NOTIFICATION_SERVER")) {
1856  std::string config;
1857  options->GetValue("CVMFS_NOTIFICATION_SERVER", &config);
1858  const std::string repo_name = cvmfs::mount_point_->fqrn();
1860  new NotificationClient(config, repo_name, cvmfs::fuse_remounter_,
1861  cvmfs::mount_point_->download_mgr(),
1863  }
1864  }
1865 
1866 
1867  auto_umount::SetMountpoint(loader_exports->mount_point);
1868 
1869  return loader::kFailOk;
1870 }
1871 
1872 
1876 static void Spawn() {
1877  // First thing: fork off the watchdog while we still have a single-threaded
1878  // well-defined state
1879  cvmfs::pid_ = getpid();
1880  if (cvmfs::watchdog_) {
1883  }
1884 
1886  if (cvmfs::mount_point_->nentry_tracker()->is_active()) {
1888  cvmfs::mount_point_->kcache_timeout_sec()); // Usually every minute
1889  }
1890 
1893  if (cvmfs::mount_point_->resolv_conf_watcher() != NULL)
1896  quota_mgr->Spawn();
1897  if (quota_mgr->HasCapability(QuotaManager::kCapListeners)) {
1899  quota_mgr,
1900  cvmfs::mount_point_->uuid()->uuid() + "-watchdog");
1902  quota_mgr,
1903  cvmfs::mount_point_->catalog_mgr(),
1904  cvmfs::mount_point_->uuid()->uuid() + "-unpin");
1905  }
1908 
1909  if (cvmfs::notification_client_ != NULL) {
1911  }
1912 
1913  if (cvmfs::file_system_->nfs_maps() != NULL)
1915 
1917 }
1918 
1919 
1920 static string GetErrorMsg() {
1921  if (g_boot_error)
1922  return *g_boot_error;
1923  return "";
1924 }
1925 
1926 
1932 static void ShutdownMountpoint() {
1933  delete cvmfs::talk_mgr_;
1934  cvmfs::talk_mgr_ = NULL;
1935 
1938 
1939  // The remonter has a reference to the mount point and the inode generation
1940  delete cvmfs::fuse_remounter_;
1941  cvmfs::fuse_remounter_ = NULL;
1942 
1943  // The unpin listener requires the catalog, so this must be unregistered
1944  // before the catalog manager is removed
1945  if (cvmfs::unpin_listener_ != NULL) {
1947  cvmfs::unpin_listener_ = NULL;
1948  }
1949  if (cvmfs::watchdog_listener_ != NULL) {
1952  }
1953 
1955  delete cvmfs::mount_point_;
1957  cvmfs::mount_point_ = NULL;
1958 }
1959 
1960 
1961 static void Fini() {
1963 
1964  delete cvmfs::file_system_;
1965  delete cvmfs::options_mgr_;
1966  cvmfs::file_system_ = NULL;
1967  cvmfs::options_mgr_ = NULL;
1968 
1969  delete cvmfs::watchdog_;
1970  cvmfs::watchdog_ = NULL;
1971 
1972  delete g_boot_error;
1973  g_boot_error = NULL;
1975 }
1976 
1977 
1978 static int AltProcessFlavor(int argc, char **argv) {
1979  if (strcmp(argv[1], "__cachemgr__") == 0) {
1980  return PosixQuotaManager::MainCacheManager(argc, argv);
1981  }
1982  if (strcmp(argv[1], "__wpad__") == 0) {
1983  return download::MainResolveProxyDescription(argc, argv);
1984  }
1985  return 1;
1986 }
1987 
1988 
1989 static bool MaintenanceMode(const int fd_progress) {
1990  SendMsg2Socket(fd_progress, "Entering maintenance mode\n");
1991  string msg_progress = "Draining out kernel caches (";
1993  msg_progress += "up to ";
1994  msg_progress += StringifyInt(static_cast<int>(
1995  cvmfs::mount_point_->kcache_timeout_sec())) +
1996  "s)\n";
1997  SendMsg2Socket(fd_progress, msg_progress);
1999  return true;
2000 }
2001 
2002 
2003 static bool SaveState(const int fd_progress, loader::StateList *saved_states) {
2004  string msg_progress;
2005 
2006  unsigned num_open_dirs = cvmfs::directory_handles_->size();
2007  if (num_open_dirs != 0) {
2008 #ifdef DEBUGMSG
2009  for (cvmfs::DirectoryHandles::iterator i =
2010  cvmfs::directory_handles_->begin(),
2011  iEnd = cvmfs::directory_handles_->end(); i != iEnd; ++i)
2012  {
2013  LogCvmfs(kLogCvmfs, kLogDebug, "saving dirhandle %d", i->first);
2014  }
2015 #endif
2016 
2017  msg_progress = "Saving open directory handles (" +
2018  StringifyInt(num_open_dirs) + " handles)\n";
2019  SendMsg2Socket(fd_progress, msg_progress);
2020 
2021  // TODO(jblomer): should rather be saved just in a malloc'd memory block
2022  cvmfs::DirectoryHandles *saved_handles =
2024  loader::SavedState *save_open_dirs = new loader::SavedState();
2025  save_open_dirs->state_id = loader::kStateOpenDirs;
2026  save_open_dirs->state = saved_handles;
2027  saved_states->push_back(save_open_dirs);
2028  }
2029 
2030  if (!cvmfs::file_system_->IsNfsSource()) {
2031  msg_progress = "Saving inode tracker\n";
2032  SendMsg2Socket(fd_progress, msg_progress);
2033  glue::InodeTracker *saved_inode_tracker =
2034  new glue::InodeTracker(*cvmfs::mount_point_->inode_tracker());
2035  loader::SavedState *state_glue_buffer = new loader::SavedState();
2036  state_glue_buffer->state_id = loader::kStateGlueBufferV4;
2037  state_glue_buffer->state = saved_inode_tracker;
2038  saved_states->push_back(state_glue_buffer);
2039  }
2040 
2041  msg_progress = "Saving negative entry cache\n";
2042  SendMsg2Socket(fd_progress, msg_progress);
2043  glue::NentryTracker *saved_nentry_cache =
2044  new glue::NentryTracker(*cvmfs::mount_point_->nentry_tracker());
2045  loader::SavedState *state_nentry_tracker = new loader::SavedState();
2046  state_nentry_tracker->state_id = loader::kStateNentryTracker;
2047  state_nentry_tracker->state = saved_nentry_cache;
2048  saved_states->push_back(state_nentry_tracker);
2049 
2050  msg_progress = "Saving chunk tables\n";
2051  SendMsg2Socket(fd_progress, msg_progress);
2052  ChunkTables *saved_chunk_tables = new ChunkTables(
2053  *cvmfs::mount_point_->chunk_tables());
2054  loader::SavedState *state_chunk_tables = new loader::SavedState();
2055  state_chunk_tables->state_id = loader::kStateOpenChunksV4;
2056  state_chunk_tables->state = saved_chunk_tables;
2057  saved_states->push_back(state_chunk_tables);
2058 
2059  msg_progress = "Saving inode generation\n";
2060  SendMsg2Socket(fd_progress, msg_progress);
2063  cvmfs::InodeGenerationInfo *saved_inode_generation =
2065  loader::SavedState *state_inode_generation = new loader::SavedState();
2066  state_inode_generation->state_id = loader::kStateInodeGeneration;
2067  state_inode_generation->state = saved_inode_generation;
2068  saved_states->push_back(state_inode_generation);
2069 
2070  // Close open file catalogs
2072 
2073  loader::SavedState *state_cache_mgr = new loader::SavedState();
2074  state_cache_mgr->state_id = loader::kStateOpenFiles;
2075  state_cache_mgr->state =
2076  cvmfs::file_system_->cache_mgr()->SaveState(fd_progress);
2077  saved_states->push_back(state_cache_mgr);
2078 
2079  msg_progress = "Saving open files counter\n";
2080  uint32_t *saved_num_fd =
2081  new uint32_t(cvmfs::file_system_->no_open_files()->Get());
2082  loader::SavedState *state_num_fd = new loader::SavedState();
2083  state_num_fd->state_id = loader::kStateOpenFilesCounter;
2084  state_num_fd->state = saved_num_fd;
2085  saved_states->push_back(state_num_fd);
2086 
2087  return true;
2088 }
2089 
2090 
2091 static bool RestoreState(const int fd_progress,
2092  const loader::StateList &saved_states)
2093 {
2094  for (unsigned i = 0, l = saved_states.size(); i < l; ++i) {
2095  if (saved_states[i]->state_id == loader::kStateOpenDirs) {
2096  SendMsg2Socket(fd_progress, "Restoring open directory handles... ");
2098  cvmfs::DirectoryHandles *saved_handles =
2099  (cvmfs::DirectoryHandles *)saved_states[i]->state;
2100  cvmfs::directory_handles_ = new cvmfs::DirectoryHandles(*saved_handles);
2103  cvmfs::DirectoryHandles::const_iterator i =
2104  cvmfs::directory_handles_->begin();
2105  for (; i != cvmfs::directory_handles_->end(); ++i) {
2106  if (i->first >= cvmfs::next_directory_handle_)
2107  cvmfs::next_directory_handle_ = i->first + 1;
2108  }
2109 
2110  SendMsg2Socket(fd_progress,
2111  StringifyInt(cvmfs::directory_handles_->size()) + " handles\n");
2112  }
2113 
2114  if (saved_states[i]->state_id == loader::kStateGlueBuffer) {
2115  SendMsg2Socket(fd_progress, "Migrating inode tracker (v1 to v4)... ");
2116  compat::inode_tracker::InodeTracker *saved_inode_tracker =
2117  (compat::inode_tracker::InodeTracker *)saved_states[i]->state;
2119  saved_inode_tracker, cvmfs::mount_point_->inode_tracker());
2120  SendMsg2Socket(fd_progress, " done\n");
2121  }
2122 
2123  if (saved_states[i]->state_id == loader::kStateGlueBufferV2) {
2124  SendMsg2Socket(fd_progress, "Migrating inode tracker (v2 to v4)... ");
2125  compat::inode_tracker_v2::InodeTracker *saved_inode_tracker =
2126  (compat::inode_tracker_v2::InodeTracker *)saved_states[i]->state;
2127  compat::inode_tracker_v2::Migrate(saved_inode_tracker,
2128  cvmfs::mount_point_->inode_tracker());
2129  SendMsg2Socket(fd_progress, " done\n");
2130  }
2131 
2132  if (saved_states[i]->state_id == loader::kStateGlueBufferV3) {
2133  SendMsg2Socket(fd_progress, "Migrating inode tracker (v3 to v4)... ");
2134  compat::inode_tracker_v3::InodeTracker *saved_inode_tracker =
2135  (compat::inode_tracker_v3::InodeTracker *)saved_states[i]->state;
2136  compat::inode_tracker_v3::Migrate(saved_inode_tracker,
2137  cvmfs::mount_point_->inode_tracker());
2138  SendMsg2Socket(fd_progress, " done\n");
2139  }
2140 
2141  if (saved_states[i]->state_id == loader::kStateGlueBufferV4) {
2142  SendMsg2Socket(fd_progress, "Restoring inode tracker... ");
2144  glue::InodeTracker *saved_inode_tracker =
2145  (glue::InodeTracker *)saved_states[i]->state;
2147  glue::InodeTracker(*saved_inode_tracker);
2148  SendMsg2Socket(fd_progress, " done\n");
2149  }
2150 
2151  if (saved_states[i]->state_id == loader::kStateNentryTracker) {
2152  SendMsg2Socket(fd_progress, "Restoring negative entry cache... ");
2154  glue::NentryTracker *saved_nentry_tracker =
2155  (glue::NentryTracker *)saved_states[i]->state;
2157  glue::NentryTracker(*saved_nentry_tracker);
2158  SendMsg2Socket(fd_progress, " done\n");
2159  }
2160 
2161  ChunkTables *chunk_tables = cvmfs::mount_point_->chunk_tables();
2162 
2163  if (saved_states[i]->state_id == loader::kStateOpenChunks) {
2164  SendMsg2Socket(fd_progress, "Migrating chunk tables (v1 to v4)... ");
2165  compat::chunk_tables::ChunkTables *saved_chunk_tables =
2166  (compat::chunk_tables::ChunkTables *)saved_states[i]->state;
2167  compat::chunk_tables::Migrate(saved_chunk_tables, chunk_tables);
2168  SendMsg2Socket(fd_progress,
2169  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2170  }
2171 
2172  if (saved_states[i]->state_id == loader::kStateOpenChunksV2) {
2173  SendMsg2Socket(fd_progress, "Migrating chunk tables (v2 to v4)... ");
2174  compat::chunk_tables_v2::ChunkTables *saved_chunk_tables =
2175  (compat::chunk_tables_v2::ChunkTables *)saved_states[i]->state;
2176  compat::chunk_tables_v2::Migrate(saved_chunk_tables, chunk_tables);
2177  SendMsg2Socket(fd_progress,
2178  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2179  }
2180 
2181  if (saved_states[i]->state_id == loader::kStateOpenChunksV3) {
2182  SendMsg2Socket(fd_progress, "Migrating chunk tables (v3 to v4)... ");
2183  compat::chunk_tables_v3::ChunkTables *saved_chunk_tables =
2184  (compat::chunk_tables_v3::ChunkTables *)saved_states[i]->state;
2185  compat::chunk_tables_v3::Migrate(saved_chunk_tables, chunk_tables);
2186  SendMsg2Socket(fd_progress,
2187  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2188  }
2189 
2190  if (saved_states[i]->state_id == loader::kStateOpenChunksV4) {
2191  SendMsg2Socket(fd_progress, "Restoring chunk tables... ");
2192  chunk_tables->~ChunkTables();
2193  ChunkTables *saved_chunk_tables = reinterpret_cast<ChunkTables *>(
2194  saved_states[i]->state);
2195  new (chunk_tables) ChunkTables(*saved_chunk_tables);
2196  SendMsg2Socket(fd_progress, " done\n");
2197  }
2198 
2199  if (saved_states[i]->state_id == loader::kStateInodeGeneration) {
2200  SendMsg2Socket(fd_progress, "Restoring inode generation... ");
2201  cvmfs::InodeGenerationInfo *old_info =
2202  (cvmfs::InodeGenerationInfo *)saved_states[i]->state;
2203  if (old_info->version == 1) {
2204  // Migration
2206  old_info->initial_revision;
2208  // Note: in the rare case of inode generation being 0 before, inode
2209  // can clash after reload before remount
2210  } else {
2211  cvmfs::inode_generation_info_ = *old_info;
2212  }
2214  SendMsg2Socket(fd_progress, " done\n");
2215  }
2216 
2217  if (saved_states[i]->state_id == loader::kStateOpenFilesCounter) {
2218  SendMsg2Socket(fd_progress, "Restoring open files counter... ");
2219  cvmfs::file_system_->no_open_files()->Set(*(reinterpret_cast<uint32_t *>(
2220  saved_states[i]->state)));
2221  SendMsg2Socket(fd_progress, " done\n");
2222  }
2223 
2224  if (saved_states[i]->state_id == loader::kStateOpenFiles) {
2225  int new_root_fd = cvmfs::file_system_->cache_mgr()->RestoreState(
2226  fd_progress, saved_states[i]->state);
2227  LogCvmfs(kLogCvmfs, kLogDebug, "new root file catalog descriptor @%d",
2228  new_root_fd);
2229  if (new_root_fd >= 0) {
2230  cvmfs::file_system_->RemapCatalogFd(0, new_root_fd);
2231  }
2232  }
2233  }
2234  if (cvmfs::mount_point_->inode_annotation()) {
2235  uint64_t saved_generation = cvmfs::inode_generation_info_.inode_generation;
2236  cvmfs::mount_point_->inode_annotation()->IncGeneration(saved_generation);
2237  }
2238 
2239  return true;
2240 }
2241 
2242 
2243 static void FreeSavedState(const int fd_progress,
2244  const loader::StateList &saved_states)
2245 {
2246  for (unsigned i = 0, l = saved_states.size(); i < l; ++i) {
2247  switch (saved_states[i]->state_id) {
2249  SendMsg2Socket(fd_progress, "Releasing saved open directory handles\n");
2250  delete static_cast<cvmfs::DirectoryHandles *>(saved_states[i]->state);
2251  break;
2254  fd_progress, "Releasing saved glue buffer (version 1)\n");
2255  delete static_cast<compat::inode_tracker::InodeTracker *>(
2256  saved_states[i]->state);
2257  break;
2260  fd_progress, "Releasing saved glue buffer (version 2)\n");
2261  delete static_cast<compat::inode_tracker_v2::InodeTracker *>(
2262  saved_states[i]->state);
2263  break;
2266  fd_progress, "Releasing saved glue buffer (version 3)\n");
2267  delete static_cast<compat::inode_tracker_v3::InodeTracker *>(
2268  saved_states[i]->state);
2269  break;
2271  SendMsg2Socket(fd_progress, "Releasing saved glue buffer\n");
2272  delete static_cast<glue::InodeTracker *>(saved_states[i]->state);
2273  break;
2275  SendMsg2Socket(fd_progress, "Releasing saved negative entry cache\n");
2276  delete static_cast<glue::NentryTracker *>(saved_states[i]->state);
2277  break;
2279  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 1)\n");
2280  delete static_cast<compat::chunk_tables::ChunkTables *>(
2281  saved_states[i]->state);
2282  break;
2284  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 2)\n");
2285  delete static_cast<compat::chunk_tables_v2::ChunkTables *>(
2286  saved_states[i]->state);
2287  break;
2289  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 3)\n");
2290  delete static_cast<compat::chunk_tables_v3::ChunkTables *>(
2291  saved_states[i]->state);
2292  break;
2294  SendMsg2Socket(fd_progress, "Releasing chunk tables\n");
2295  delete static_cast<ChunkTables *>(saved_states[i]->state);
2296  break;
2298  SendMsg2Socket(fd_progress, "Releasing saved inode generation info\n");
2299  delete static_cast<cvmfs::InodeGenerationInfo *>(
2300  saved_states[i]->state);
2301  break;
2304  fd_progress, saved_states[i]->state);
2305  break;
2307  SendMsg2Socket(fd_progress, "Releasing open files counter\n");
2308  delete static_cast<uint32_t *>(saved_states[i]->state);
2309  break;
2310  default:
2311  break;
2312  }
2313  }
2314 }
2315 
2316 
2317 static void __attribute__((constructor)) LibraryMain() {
2318  g_cvmfs_exports = new loader::CvmfsExports();
2319  g_cvmfs_exports->so_version = PACKAGE_VERSION;
2320  g_cvmfs_exports->fnAltProcessFlavor = AltProcessFlavor;
2321  g_cvmfs_exports->fnInit = Init;
2322  g_cvmfs_exports->fnSpawn = Spawn;
2323  g_cvmfs_exports->fnFini = Fini;
2324  g_cvmfs_exports->fnGetErrorMsg = GetErrorMsg;
2325  g_cvmfs_exports->fnMaintenanceMode = MaintenanceMode;
2326  g_cvmfs_exports->fnSaveState = SaveState;
2327  g_cvmfs_exports->fnRestoreState = RestoreState;
2328  g_cvmfs_exports->fnFreeSavedState = FreeSavedState;
2329  cvmfs::SetCvmfsOperations(&g_cvmfs_exports->cvmfs_operations);
2330 }
2331 
2332 
2333 static void __attribute__((destructor)) LibraryExit() {
2334  delete g_cvmfs_exports;
2335  g_cvmfs_exports = NULL;
2336 }
std::string repository_name
Definition: loader.h:176
OptionsManager * options_mgr()
Definition: mountpoint.h:203
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
uint32_t version
Definition: loader.h:171
bool IsCaching()
Definition: fuse_remount.h:60
void Dec(class Counter *counter)
Definition: statistics.h:49
NfsMaps * nfs_maps()
Definition: mountpoint.h:200
bool IsExternalFile() const
std::string mount_point
Definition: loader.h:177
bool IsInDrainoutMode()
Definition: fuse_remount.h:64
perf::Counter * n_io_error()
Definition: mountpoint.h:198
void UnregisterQuotaListener()
Definition: cvmfs.cc:1595
static const time_t kIndefiniteDeadline
Definition: mountpoint.h:395
virtual std::string GetValue()
Definition: cvmfs.cc:1647
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:556
std::string ListKeysPosix(const std::string &merge_with) const
Definition: xattr.cc:137
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:183
time_t catalogs_valid_until_
Definition: cvmfs.cc:1640
bool GetValue(const std::string &key, std::string *value)
Definition: options.cc:376
virtual void ParsePath(const std::string &config_file, const bool external)=0
void Enter()
Definition: fence.h:34
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:1062
static double GetKcacheTimeout()
Definition: cvmfs.cc:165
void SpawnCleaner(unsigned interval_s)
Definition: glue_buffer.cc:166
void EnterMaintenanceMode()
void set_inode(const inode_t inode)
InodeGenerationInfo inode_generation_info_
Definition: cvmfs.cc:126
loader::Failures boot_status()
Definition: mountpoint.h:74
static void FreeSavedState(const int fd_progress, const loader::StateList &saved_states)
Definition: cvmfs.cc:2243
bool IsDirectory() const
static void cvmfs_statfs(fuse_req_t req, fuse_ino_t ino)
Definition: cvmfs.cc:1271
void set_boot_status(loader::Failures code)
Definition: mountpoint.h:81
static void DoTraceInode(const int event, fuse_ino_t ino, const std::string &msg)
Definition: cvmfs.cc:345
cvmfs::Fetcher * fetcher()
Definition: mountpoint.h:418
void Migrate(ChunkTables *old_tables,::ChunkTables *new_tables)
Definition: compat.cc:182
void ShareBuffer(Item **duplicate, bool *large_alloc)
Definition: bigvector.h:76
static void cvmfs_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:783
bool IsChunkedFile() const
FuseRemounter * fuse_remounter_
Definition: cvmfs.cc:125
static Watchdog * Create(const std::string &crash_dump_path)
Definition: monitor.cc:59
vector< string > SplitString(const string &str, const char delim, const unsigned max_chunks)
Definition: string.cc:287
uid_t talk_socket_uid()
Definition: mountpoint.h:440
int RestoreState(const int fd_progress, void *state)
Definition: cache.cc:194
void Register(const std::string &name, BaseMagicXattr *magic_xattr)
Definition: magic_xattr.cc:118
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:153
#define PANIC(...)
Definition: exception.h:26
void Spawn()
Definition: tracer.cc:212
SpecialDirents GetSpecial() const
virtual void Spawn()=0
static int AltProcessFlavor(int argc, char **argv)
Definition: cvmfs.cc:1978
uint64_t size() const
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:245
double kcache_timeout_sec()
Definition: mountpoint.h:431
void Assign(const char *chars, const unsigned length)
Definition: shortstring.h:53
static void cvmfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
Definition: cvmfs.cc:467
std::string PrintInodeGeneration()
Definition: cvmfs.cc:188
zlib::Algorithms compression_alg
Definition: file_chunk.h:71
int MainResolveProxyDescription(int argc, char **argv)
Definition: wpad.cc:271
perf::Counter * n_fs_readlink()
Definition: mountpoint.h:196
std::string fqrn() const
Definition: mountpoint.h:420
void SetMountpoint(const string &mountpoint)
Definition: auto_umount.cc:28
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:1207
BaseMagicXattr * GetLocked(const std::string &name, PathString path, catalog::DirectoryEntry *d)
Definition: magic_xattr.cc:102
Watchdog * watchdog_
Definition: cvmfs.cc:124
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:430
NotificationClient * notification_client_
Definition: cvmfs.cc:123
void * SaveState(const int fd_progress)
Definition: cache.cc:221
DirectoryHandles * directory_handles_
Definition: cvmfs.cc:154
StateId state_id
Definition: loader.h:121
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:2003
void Spawn()
Definition: monitor.cc:376
inode_t inode() const
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:687
bool ListingStat(const PathString &path, StatEntryList *listing)
assert((mem||(size==0))&&"Out Of Memory")
void ** fuse_channel_or_session
Definition: loader.h:194
MountPoint * mount_point_
Definition: cvmfs.cc:121
MagicXattrManager * magic_xattr_mgr()
Definition: mountpoint.h:423
std::string program_name
Definition: loader.h:179
Log2Histogram * hist_fs_read()
Definition: mountpoint.h:187
bool IsDirectIo() const
bool SendFd2Socket(int socket_fd, int passing_fd)
Definition: posix.cc:696
bool LookupPath(const PathString &path, const LookupOptions options, DirectoryEntry *entry)
std::string GetParentPath(const std::string &path)
Definition: posix.cc:129
static bool RestoreState(const int fd_progress, const loader::StateList &saved_states)
Definition: cvmfs.cc:2091
virtual uint64_t GetSize()=0
perf::Counter * n_fs_read()
Definition: mountpoint.h:195
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:432
shash::Any checksum() const
void ParseDefault(const std::string &fqrn)
Definition: options.cc:282
SmallHashDynamic< uint64_t, ChunkFd > handle2fd
Definition: file_chunk.h:120
static bool GetDirentForPath(const PathString &path, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:278
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:112
bool has_membership_req()
Definition: mountpoint.h:424
virtual bool PrepareValueFenced()
Definition: cvmfs.cc:1642
virtual std::string GetValue()
Definition: cvmfs.cc:1658
struct cvmcache_object_info __attribute__
Definition: atomic.h:24
void RemapCatalogFd(int from, int to)
Definition: mountpoint.cc:1050
bool Pin(const string &path)
Definition: cvmfs.cc:1464
static void cvmfs_destroy(void *unused __attribute__((unused)))
Definition: cvmfs.cc:1561
static TalkManager * Create(const std::string &socket_path, MountPoint *mount_point, FuseRemounter *remounter)
Definition: talk.cc:78
unsigned max_open_files_
Definition: cvmfs.cc:158
static bool HasFuseNotifyInval()
Definition: fuse_evict.cc:53
perf::Counter * n_fs_open()
Definition: mountpoint.h:194
static void cvmfs_init(void *userdata, struct fuse_conn_info *conn)
Definition: cvmfs.cc:1536
TalkManager * talk_mgr_
Definition: cvmfs.cc:122
virtual uint64_t GetCapacity()=0
std::string membership_req()
Definition: mountpoint.h:433
void Throttle()
Definition: backoff.cc:50
std::string GetListString(catalog::DirectoryEntry *dirent)
Definition: magic_xattr.cc:67
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:156
void Unlock()
Definition: file_chunk.h:106
static void InitOptionsMgr(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:1735
Fence * fence()
Definition: fuse_remount.h:67
pid_t pid_
Definition: cvmfs.cc:146
PathString path
Definition: file_chunk.h:70
static bool GetDirentForInode(const fuse_ino_t ino, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:213
bool IsLink() const
BigVector< FileChunk > FileChunkList
Definition: file_chunk.h:51
virtual void Spawn()=0
bool HasXattrs() const
virtual std::string GetValue()
Definition: cvmfs.cc:1676
static void TraceInode(const int event, fuse_ino_t ino, const std::string &msg)
Definition: cvmfs.cc:360
bool Get(const std::string &key, std::string *value) const
Definition: xattr.cc:108
catalog::ClientCatalogManager * catalog_mgr()
Definition: mountpoint.h:409
void Set(const int64_t val)
Definition: statistics.h:33
Log2Histogram * hist_fs_forget_multi()
Definition: mountpoint.h:180
static void cvmfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Definition: cvmfs.cc:1404
bool IsRegular() const
void DoubleCapacity()
Definition: bigvector.h:82
bool platform_getxattr(const std::string &path, const std::string &name, std::string *value)
Log2Histogram * hist_fs_release()
Definition: mountpoint.h:188
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:574
ListenerHandle * RegisterWatchdogListener(QuotaManager *quota_manager, const string &repository_name)
const loader::LoaderExports * loader_exports_
Definition: cvmfs.cc:144
virtual inode_t GetGeneration()=0
std::string config_files
Definition: loader.h:178
perf::Counter * no_open_dirs()
Definition: mountpoint.h:201
catalog::InodeAnnotation * inode_annotation()
Definition: mountpoint.h:426
void VfsPut(const uint64_t inode, const uint32_t by)
Definition: glue_buffer.h:540
Log2Histogram * hist_fs_releasedir()
Definition: mountpoint.h:184
quota::ListenerHandle * watchdog_listener_
Definition: cvmfs.cc:147
void SetSize(const size_t new_size)
Definition: bigvector.h:95
std::string boot_error()
Definition: mountpoint.h:75
off_t offset() const
Definition: file_chunk.h:42
lru::PathCache * path_cache()
Definition: mountpoint.h:435
glue::NentryTracker * nentry_tracker()
Definition: mountpoint.h:434
virtual std::string GetValue()
Definition: cvmfs.cc:1666
static void cvmfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:863
zlib::Algorithms compression_algorithm() const
unsigned GetMaxOpenFiles()
Definition: monitor.cc:600
bool IsNfsSource()
Definition: mountpoint.h:168
CacheManager * cache_mgr()
Definition: mountpoint.h:174
const signature::SignatureManager * signature_mgr() const
Definition: repository.h:119
file_watcher::FileWatcher * resolv_conf_watcher()
Definition: mountpoint.h:415
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:1672
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:146
static void ShutdownMountpoint()
Definition: cvmfs.cc:1932
unsigned FindChunkIdx(const uint64_t offset)
Definition: file_chunk.cc:23
bool SendFuseFd(const std::string &socket_path)
Definition: cvmfs.cc:1606
perf::Counter * no_open_files()
Definition: mountpoint.h:202
AuthzSessionManager * authz_session_mgr()
Definition: mountpoint.h:407
LinkString symlink() const
void Insert(const Key &key, const Value &value)
Definition: smallhash.h:88
download::DownloadManager * download_mgr()
Definition: mountpoint.h:411
bool hide_magic_xattrs()
Definition: magic_xattr.h:147
static void SetCvmfsOperations(struct fuse_lowlevel_ops *cvmfs_operations)
Definition: cvmfs.cc:1569
bool simple_options_parsing
Definition: loader.h:187
perf::Counter * n_fs_forget()
Definition: mountpoint.h:191
Log2Histogram * hist_fs_readlink()
Definition: mountpoint.h:182
static int Init(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:1755
void Append(const char *chars, const unsigned length)
Definition: shortstring.h:70
ListenerHandle * RegisterUnpinListener(QuotaManager *quota_manager, CatalogManager *catalog_manager, const string &repository_name)
string StringifyInt(const int64_t value)
Definition: string.cc:77
SmallHashDynamic< uint64_t, uint32_t > inode2references
Definition: file_chunk.h:125
void Leave()
Definition: fence.h:41
static void cvmfs_readlink(fuse_req_t req, fuse_ino_t ino)
Definition: cvmfs.cc:595
size_t capacity() const
Definition: bigvector.h:101
static void ReplyNegative(const catalog::DirectoryEntry &dirent, fuse_req_t req)
Definition: cvmfs.cc:543
void Inc(class Counter *counter)
Definition: statistics.h:50
virtual int Close(int fd)=0
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:832
ChunkTables * chunk_tables()
Definition: mountpoint.h:410
pthread_mutex_t lock_directory_handles_
Definition: cvmfs.cc:155
static void cvmfs_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:653
OptionsManager * options_mgr_
Definition: cvmfs.cc:145
virtual bool GetPath(const uint64_t inode, PathString *path)=0
shash::Algorithms hash_algorithm() const
static int MainCacheManager(int argc, char **argv)
Definition: quota_posix.cc:952
perf::Counter * n_fs_dir_open()
Definition: mountpoint.h:190
Log2Histogram * hist_fs_readdir()
Definition: mountpoint.h:185
cvmfs::Fetcher * external_fetcher()
Definition: mountpoint.h:421
bool enforce_acls()
Definition: mountpoint.h:425
bool IsInMaintenanceMode()
Definition: fuse_remount.h:65
static bool CheckVoms(const fuse_ctx &fctx)
Definition: cvmfs.cc:199
void FreeState(const int fd_progress, void *state)
Definition: cache.cc:100
static FileSystem * Create(const FileSystemInfo &fs_info)
Definition: mountpoint.cc:144
bool IsEmpty() const
Definition: bigvector.h:67
bool Contains(const Key &key) const
Definition: smallhash.h:81
Log2Histogram * hist_fs_open()
Definition: mountpoint.h:186
void Add(const uint64_t inode_parent, const char *name, uint64_t timeout_s)
Definition: glue_buffer.h:682
bool FindPath(const uint64_t inode, PathString *path)
Definition: glue_buffer.h:556
std::string ToString() const
Definition: shortstring.h:113
QuotaManager * quota_mgr()
Definition: cache.h:198
static string GetErrorMsg()
Definition: cvmfs.cc:1920
int ConnectSocket(const std::string &path)
Definition: posix.cc:456
void Migrate(ChunkTables *old_tables,::ChunkTables *new_tables)
Definition: compat.cc:274
virtual void Spawn()
Definition: nfs_maps.h:36
void RegisterOnCrash(void(*CleanupOnCrash)(void))
Definition: monitor.cc:239
Log2Histogram * hist_fs_lookup()
Definition: mountpoint.h:178
string * g_boot_error
Definition: cvmfs.cc:1630
bool ListFileChunks(const PathString &path, const shash::Algorithms interpret_hashes_as, FileChunkList *chunks)
static void Fini()
Definition: cvmfs.cc:1961
perf::Counter * n_fs_lookup()
Definition: mountpoint.h:192
static void Spawn()
Definition: cvmfs.cc:1876
static bool UseWatchdog()
Definition: cvmfs.cc:178
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:83
ShortString< kDefaultMaxPath, 0 > PathString
Definition: shortstring.h:189
uint32_t size() const
Definition: smallhash.h:278
uint64_t next_handle
Definition: file_chunk.h:126
size_t size() const
Definition: file_chunk.h:43
void UnregisterListener(ListenerHandle *handle)
bool Evict(const string &path)
Definition: cvmfs.cc:1451
std::vector< SavedState * > StateList
Definition: loader.h:124
FileSystem * file_system_
Definition: cvmfs.cc:120
virtual bool PrepareValueFenced()
Definition: magic_xattr.h:51
void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode)
Definition: cvmfs.cc:172
bool LookupXattrs(const PathString &path, XattrList *xattrs)
perf::Counter * n_fs_lookup_negative()
Definition: mountpoint.h:193
virtual uint64_t GetInode(const PathString &path)=0
Log2Histogram * hist_fs_forget()
Definition: mountpoint.h:179
const int kNumReservedFd
Definition: cvmfs.cc:162
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:816
void VfsGet(const uint64_t inode, const PathString &path)
Definition: glue_buffer.h:536
unsigned GetLength() const
Definition: shortstring.h:103
virtual void IncGeneration(const uint64_t by)=0
bool Lookup(const Key &key, Value *value) const
Definition: smallhash.h:72
inode_t MangleInode(const inode_t inode) const
Definition: catalog_mgr.h:199
bool Insert(const fuse_ino_t &inode, const PathString &path)
Definition: lru_md.h:84
BackoffThrottle * backoff_throttle()
Definition: mountpoint.h:408
Log2Histogram * hist_fs_getattr()
Definition: mountpoint.h:181
gid_t talk_socket_gid()
Definition: mountpoint.h:441
const char * c_str() const
Definition: shortstring.h:117
static bool GetPathForInode(const fuse_ino_t ino, PathString *path)
Definition: cvmfs.cc:320
const char * GetChars() const
Definition: shortstring.h:96
static void RegisterMagicXattrs()
Definition: cvmfs.cc:1687
bool IsDefined(const std::string &key)
Definition: options.cc:370
virtual void Remove(const shash::Any &file)=0
glue::InodeTracker * inode_tracker()
Definition: mountpoint.h:429
bool Insert(const shash::Md5 &hash, const catalog::DirectoryEntry &dirent)
Definition: lru_md.h:121
perf::Counter * n_fs_stat()
Definition: mountpoint.h:197
static void size_t size
Definition: smalloc.h:47
static void cvmfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
Definition: cvmfs.cc:372
#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
void Erase(const Key &key)
Definition: smallhash.h:94
static bool MaintenanceMode(const int fd_progress)
Definition: cvmfs.cc:1989
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:1700
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:1322
Tracer * tracer()
Definition: mountpoint.h:443
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:626
size_t size() const
Definition: bigvector.h:100
download::DownloadManager * external_download_mgr()
Definition: mountpoint.h:412
int Fetch(const shash::Any &id, const uint64_t size, const std::string &name, const zlib::Algorithms compression_algorithm, const CacheManager::ObjectType object_type, const std::string &alt_url="", off_t range_offset=-1)
Definition: fetch.cc:81
quota::ListenerHandle * unpin_listener_
Definition: cvmfs.cc:148
static MountPoint * Create(const std::string &fqrn, FileSystem *file_system, OptionsManager *options_mgr=NULL)
Definition: mountpoint.cc:1136
void Spawn()
Definition: talk.cc:828
OptionsManager * options_mgr
Definition: mountpoint.h:136