CernVM-FS  2.10.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/algorithm.h"
111 #include "util/exception.h"
112 #include "util_concurrency.h"
113 #include "uuid.h"
114 #include "wpad.h"
115 #include "xattr.h"
116 
117 using namespace std; // NOLINT
118 
119 namespace cvmfs {
120 
128 
129 
135  char *buffer;
137  // Not really used anymore. But directory listing needs to be migrated during
138  // hotpatch. If buffer is allocated by smmap, capacity is zero.
139  size_t size;
140  size_t capacity;
141 
142  DirectoryListing() : buffer(NULL), size(0), capacity(0) { }
143 };
144 
147 pid_t pid_ = 0;
150 
151 
152 typedef google::dense_hash_map<uint64_t, DirectoryListing,
156 pthread_mutex_t lock_directory_handles_ = PTHREAD_MUTEX_INITIALIZER;
158 
159 unsigned max_open_files_;
163 const int kNumReservedFd = 512;
164 
165 
166 static inline double GetKcacheTimeout() {
167  if (!fuse_remounter_->IsCaching())
168  return 0.0;
170 }
171 
172 
173 void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode) {
174  *drainout_mode = fuse_remounter_->IsInDrainoutMode();
175  *maintenance_mode = fuse_remounter_->IsInMaintenanceMode();
176 }
177 
178 
179 static bool UseWatchdog() {
180  if (loader_exports_ == NULL || loader_exports_->version < 2) {
181  return true; // spawn watchdog by default
182  // Note: with library versions before 2.1.8 it might not
183  // create stack traces properly in all cases
184  }
185 
187 }
188 
189 std::string PrintInodeGeneration() {
190  return "init-catalog-revision: " +
192  "current-catalog-revision: " +
194  "incarnation: " + StringifyInt(inode_generation_info_.incarnation) + " " +
196  + "\n";
197 }
198 
199 
200 static bool CheckVoms(const fuse_ctx &fctx) {
202  return true;
203  string mreq = mount_point_->membership_req();
204  LogCvmfs(kLogCvmfs, kLogDebug, "Got VOMS authz %s from filesystem "
205  "properties", mreq.c_str());
206 
207  if (fctx.uid == 0)
208  return true;
209 
210  return mount_point_->authz_session_mgr()->IsMemberOf(fctx.pid, mreq);
211 }
212 
213 
214 static bool GetDirentForInode(const fuse_ino_t ino,
215  catalog::DirectoryEntry *dirent)
216 {
217  // Lookup inode in cache
218  if (mount_point_->inode_cache()->Lookup(ino, dirent))
219  return true;
220 
221  // Look in the catalogs in 2 steps: lookup inode->path, lookup path
222  catalog::DirectoryEntry dirent_negative =
224  // Reset directory entry. If the function returns false and dirent is no
225  // the kDirentNegative, it was an I/O error
226  *dirent = catalog::DirectoryEntry();
227 
229 
230  if (file_system_->IsNfsSource()) {
231  // NFS mode
232  PathString path;
233  bool retval = file_system_->nfs_maps()->GetPath(ino, &path);
234  if (!retval) {
235  *dirent = dirent_negative;
236  return false;
237  }
238  if (catalog_mgr->LookupPath(path, catalog::kLookupSole, dirent)) {
239  // Fix inodes
240  dirent->set_inode(ino);
241  mount_point_->inode_cache()->Insert(ino, *dirent);
242  return true;
243  }
244  return false; // Not found in catalog or catalog load error
245  }
246 
247  // Non-NFS mode
248  PathString path;
249  if (ino == catalog_mgr->GetRootInode()) {
250  bool retval =
251  catalog_mgr->LookupPath(PathString(), catalog::kLookupSole, dirent);
252  assert(retval);
253  dirent->set_inode(ino);
254  mount_point_->inode_cache()->Insert(ino, *dirent);
255  return true;
256  }
257 
258  bool retval = mount_point_->inode_tracker()->FindPath(ino, &path);
259  if (!retval) {
260  // Can this ever happen?
262  "GetDirentForInode inode lookup failure %" PRId64, ino);
263  *dirent = dirent_negative;
264  return false;
265  }
266  if (catalog_mgr->LookupPath(path, catalog::kLookupSole, dirent)) {
267  // Fix inodes
268  dirent->set_inode(ino);
269  mount_point_->inode_cache()->Insert(ino, *dirent);
270  return true;
271  }
272 
273  // Can happen after reload of catalogs or on catalog load failure
274  LogCvmfs(kLogCvmfs, kLogDebug, "GetDirentForInode path lookup failure");
275  return false;
276 }
277 
278 
279 static bool GetDirentForPath(const PathString &path,
280  catalog::DirectoryEntry *dirent)
281 {
282  uint64_t live_inode = 0;
283  if (!file_system_->IsNfsSource())
284  live_inode = mount_point_->inode_tracker()->FindInode(path);
285 
286  shash::Md5 md5path(path.GetChars(), path.GetLength());
287  if (mount_point_->md5path_cache()->Lookup(md5path, dirent)) {
288  if (dirent->GetSpecial() == catalog::kDirentNegative)
289  return false;
290  if (!file_system_->IsNfsSource() && (live_inode != 0))
291  dirent->set_inode(live_inode);
292  return true;
293  }
294 
296 
297  // Lookup inode in catalog TODO: not twice md5 calculation
298  bool retval;
299  retval = catalog_mgr->LookupPath(path, catalog::kLookupSole, dirent);
300  if (retval) {
301  if (file_system_->IsNfsSource()) {
302  // Fix inode
303  dirent->set_inode(file_system_->nfs_maps()->GetInode(path));
304  } else {
305  if (live_inode != 0)
306  dirent->set_inode(live_inode);
307  }
308  mount_point_->md5path_cache()->Insert(md5path, *dirent);
309  return true;
310  }
311 
312  LogCvmfs(kLogCvmfs, kLogDebug, "GetDirentForPath, no entry");
313  // Only insert ENOENT results into negative cache. Otherwise it was an
314  // error loading nested catalogs
315  if (dirent->GetSpecial() == catalog::kDirentNegative)
317  return false;
318 }
319 
320 
321 static bool GetPathForInode(const fuse_ino_t ino, PathString *path) {
322  // Check the path cache first
323  if (mount_point_->path_cache()->Lookup(ino, path))
324  return true;
325 
326  if (file_system_->IsNfsSource()) {
327  // NFS mode, just a lookup
328  LogCvmfs(kLogCvmfs, kLogDebug, "MISS %d - lookup in NFS maps", ino);
329  if (file_system_->nfs_maps()->GetPath(ino, path)) {
330  mount_point_->path_cache()->Insert(ino, *path);
331  return true;
332  }
333  return false;
334  }
335 
336  if (ino == mount_point_->catalog_mgr()->GetRootInode())
337  return true;
338 
339  LogCvmfs(kLogCvmfs, kLogDebug, "MISS %d - looking in inode tracker", ino);
340  bool retval = mount_point_->inode_tracker()->FindPath(ino, path);
341  assert(retval);
342  mount_point_->path_cache()->Insert(ino, *path);
343  return true;
344 }
345 
346 static void DoTraceInode(const int event,
347  fuse_ino_t ino,
348  const std::string &msg)
349 {
350  PathString path;
351  bool found = GetPathForInode(ino, &path);
352  if (!found) {
354  "Tracing: Could not find path for inode %" PRIu64, uint64_t(ino));
355  mount_point_->tracer()->Trace(event, PathString("@UNKNOWN"), msg);
356  } else {
357  mount_point_->tracer()->Trace(event, path, msg);
358  }
359 }
360 
361 static void inline TraceInode(const int event,
362  fuse_ino_t ino,
363  const std::string &msg)
364 {
365  if (mount_point_->tracer()->IsActive()) DoTraceInode(event, ino, msg);
366 }
367 
373 static void cvmfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) {
375 
377  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
378  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
380 
383 
384  fuse_ino_t parent_fuse = parent;
385  parent = catalog_mgr->MangleInode(parent);
387  "cvmfs_lookup in parent inode: %" PRIu64 " for name: %s",
388  uint64_t(parent), name);
389 
390  PathString path;
391  PathString parent_path;
393  struct fuse_entry_param result;
394 
395  memset(&result, 0, sizeof(result));
396  double timeout = GetKcacheTimeout();
397  result.attr_timeout = timeout;
398  result.entry_timeout = timeout;
399 
400  // Special NFS lookups: . and ..
401  if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
402  if (GetDirentForInode(parent, &dirent)) {
403  if (strcmp(name, ".") == 0) {
404  goto lookup_reply_positive;
405  } else {
406  // Lookup for ".."
407  if (dirent.inode() == catalog_mgr->GetRootInode()) {
408  dirent.set_inode(1);
409  goto lookup_reply_positive;
410  }
411  if (!GetPathForInode(parent, &parent_path))
412  goto lookup_reply_negative;
413  if (GetDirentForPath(GetParentPath(parent_path), &dirent))
414  goto lookup_reply_positive;
415  }
416  }
417  // No entry for "." or no entry for ".."
418  if (dirent.GetSpecial() == catalog::kDirentNegative)
419  goto lookup_reply_negative;
420  else
421  goto lookup_reply_error;
422  assert(false);
423  }
424 
425  if (!GetPathForInode(parent, &parent_path)) {
426  LogCvmfs(kLogCvmfs, kLogDebug, "no path for parent inode found");
427  goto lookup_reply_negative;
428  }
429 
430  path.Assign(parent_path);
431  path.Append("/", 1);
432  path.Append(name, strlen(name));
433  mount_point_->tracer()->Trace(Tracer::kEventLookup, path, "lookup()");
434  if (!GetDirentForPath(path, &dirent)) {
435  if (dirent.GetSpecial() == catalog::kDirentNegative)
436  goto lookup_reply_negative;
437  else
438  goto lookup_reply_error;
439  }
440 
441  lookup_reply_positive:
442  if (!file_system_->IsNfsSource())
443  mount_point_->inode_tracker()->VfsGet(dirent.inode(), path);
445  result.ino = dirent.inode();
446  result.attr = dirent.GetStatStructure();
447  fuse_reply_entry(req, &result);
448  return;
449 
450  lookup_reply_negative:
451  // Will be a no-op if there is no fuse cache eviction
452  mount_point_->nentry_tracker()->Add(parent_fuse, name, timeout);
455  result.ino = 0;
456  fuse_reply_entry(req, &result);
457  return;
458 
459  lookup_reply_error:
461  fuse_reply_err(req, EIO);
462 }
463 
464 
468 static void cvmfs_forget(
469  fuse_req_t req,
470  fuse_ino_t ino,
471 #if CVMFS_USE_LIBFUSE == 2
472  unsigned long nlookup // NOLINT
473 #else
474  uint64_t nlookup
475 #endif
476 ) {
478 
480 
481  // The libfuse high-level library does the same
482  if (ino == FUSE_ROOT_ID) {
483  fuse_reply_none(req);
484  return;
485  }
486 
488  ino = mount_point_->catalog_mgr()->MangleInode(ino);
489  // This has been seen to deadlock on the debug log mutex on SL5. Problem of
490  // old kernel/fuse?
491 #if CVMFS_USE_LIBCVMFS == 2
492  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %u",
493  uint64_t(ino), nlookup);
494 #else
495  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %" PRIu64,
496  uint64_t(ino), nlookup);
497 #endif
498  if (!file_system_->IsNfsSource()) {
499  bool removed =
500  mount_point_->inode_tracker()->GetVfsPutRaii().VfsPut(ino, nlookup);
501  if (removed)
503  }
505  fuse_reply_none(req);
506 }
507 
508 
509 #if (FUSE_VERSION >= 29)
510 static void cvmfs_forget_multi(
511  fuse_req_t req,
512  size_t count,
513  struct fuse_forget_data *forgets
514 ) {
516 
518  if (file_system_->IsNfsSource()) {
519  fuse_reply_none(req);
520  return;
521  }
522 
524  {
525  glue::InodeTracker::VfsPutRaii vfs_put_raii =
529  for (size_t i = 0; i < count; ++i) {
530  if (forgets[i].ino == FUSE_ROOT_ID) {
531  continue;
532  }
533 
534  uint64_t ino = mount_point_->catalog_mgr()->MangleInode(forgets[i].ino);
535  LogCvmfs(kLogCvmfs, kLogDebug, "forget on inode %" PRIu64 " by %" PRIu64,
536  ino, forgets[i].nlookup);
537 
538  bool removed = vfs_put_raii.VfsPut(ino, forgets[i].nlookup);
539  if (removed)
540  evict_raii.Evict(ino);
541  }
542  }
544 
545  fuse_reply_none(req);
546 }
547 #endif // FUSE_VERSION >= 29
548 
549 
556 static void ReplyNegative(const catalog::DirectoryEntry &dirent,
557  fuse_req_t req)
558 {
559  if (dirent.GetSpecial() == catalog::kDirentNegative)
560  fuse_reply_err(req, ENOENT);
561  else
562  fuse_reply_err(req, EIO);
563 }
564 
565 
569 static void cvmfs_getattr(fuse_req_t req, fuse_ino_t ino,
570  struct fuse_file_info *fi)
571 {
573 
575  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
576  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
578 
580  ino = mount_point_->catalog_mgr()->MangleInode(ino);
581  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_getattr (stat) for inode: %" PRIu64,
582  uint64_t(ino));
583 
584  if (!CheckVoms(*fuse_ctx)) {
586  fuse_reply_err(req, EACCES);
587  return;
588  }
590  const bool found = GetDirentForInode(ino, &dirent);
591  TraceInode(Tracer::kEventGetAttr, ino, "getattr()");
593 
594  if (!found) {
595  ReplyNegative(dirent, req);
596  return;
597  }
598 
599  struct stat info = dirent.GetStatStructure();
600 
601  fuse_reply_attr(req, &info, GetKcacheTimeout());
602 }
603 
604 
608 static void cvmfs_readlink(fuse_req_t req, fuse_ino_t ino) {
610 
612  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
613  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
614 
616  ino = mount_point_->catalog_mgr()->MangleInode(ino);
617  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_readlink on inode: %" PRIu64,
618  uint64_t(ino));
619 
621  const bool found = GetDirentForInode(ino, &dirent);
622  TraceInode(Tracer::kEventReadlink, ino, "readlink()");
624 
625  if (!found) {
626  ReplyNegative(dirent, req);
627  return;
628  }
629 
630  if (!dirent.IsLink()) {
631  fuse_reply_err(req, EINVAL);
632  return;
633  }
634 
635  fuse_reply_readlink(req, dirent.symlink().c_str());
636 }
637 
638 
639 static void AddToDirListing(const fuse_req_t req,
640  const char *name, const struct stat *stat_info,
641  BigVector<char> *listing)
642 {
643  LogCvmfs(kLogCvmfs, kLogDebug, "Add to listing: %s, inode %" PRIu64,
644  name, uint64_t(stat_info->st_ino));
645  size_t remaining_size = listing->capacity() - listing->size();
646  const size_t entry_size = fuse_add_direntry(req, NULL, 0, name, stat_info, 0);
647 
648  while (entry_size > remaining_size) {
649  listing->DoubleCapacity();
650  remaining_size = listing->capacity() - listing->size();
651  }
652 
653  char *buffer;
654  bool large_alloc;
655  listing->ShareBuffer(&buffer, &large_alloc);
656  fuse_add_direntry(req, buffer + listing->size(),
657  remaining_size, name, stat_info,
658  listing->size() + entry_size);
659  listing->SetSize(listing->size() + entry_size);
660 }
661 
662 
666 static void cvmfs_opendir(fuse_req_t req, fuse_ino_t ino,
667  struct fuse_file_info *fi)
668 {
670 
671  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
672  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
674 
677  ino = catalog_mgr->MangleInode(ino);
678  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_opendir on inode: %" PRIu64,
679  uint64_t(ino));
680  if (!CheckVoms(*fuse_ctx)) {
682  fuse_reply_err(req, EACCES);
683  return;
684  }
685 
686  TraceInode(Tracer::kEventOpenDir, ino, "opendir()");
687  PathString path;
689  bool found = GetPathForInode(ino, &path);
690  if (!found) {
692  fuse_reply_err(req, ENOENT);
693  return;
694  }
695  found = GetDirentForInode(ino, &d);
696 
697  if (!found) {
699  ReplyNegative(d, req);
700  return;
701  }
702  if (!d.IsDirectory()) {
704  fuse_reply_err(req, ENOTDIR);
705  return;
706  }
707 
708  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_opendir on inode: %" PRIu64 ", path %s",
709  uint64_t(ino), path.c_str());
710 
711  // Build listing
712  BigVector<char> fuse_listing(512);
713 
714  // Add current directory link
715  struct stat info;
716  info = d.GetStatStructure();
717  AddToDirListing(req, ".", &info, &fuse_listing);
718 
719  // Add parent directory link
721  if (d.inode() != catalog_mgr->GetRootInode() &&
722  GetDirentForPath(GetParentPath(path), &p))
723  {
724  info = p.GetStatStructure();
725  AddToDirListing(req, "..", &info, &fuse_listing);
726  }
727 
728  // Add all names
729  catalog::StatEntryList listing_from_catalog;
730  bool retval = catalog_mgr->ListingStat(path, &listing_from_catalog);
731 
732  if (!retval) {
734  fuse_listing.Clear(); // Buffer is shared, empty manually
735  fuse_reply_err(req, EIO);
736  return;
737  }
738  for (unsigned i = 0; i < listing_from_catalog.size(); ++i) {
739  // Fix inodes
740  PathString entry_path;
741  entry_path.Assign(path);
742  entry_path.Append("/", 1);
743  entry_path.Append(listing_from_catalog.AtPtr(i)->name.GetChars(),
744  listing_from_catalog.AtPtr(i)->name.GetLength());
745 
746  catalog::DirectoryEntry entry_dirent;
747  if (!GetDirentForPath(entry_path, &entry_dirent)) {
748  LogCvmfs(kLogCvmfs, kLogDebug, "listing entry %s vanished, skipping",
749  entry_path.c_str());
750  continue;
751  }
752 
753  struct stat fixed_info = listing_from_catalog.AtPtr(i)->info;
754  fixed_info.st_ino = entry_dirent.inode();
755  AddToDirListing(req, listing_from_catalog.AtPtr(i)->name.c_str(),
756  &fixed_info, &fuse_listing);
757  }
759 
760  DirectoryListing stream_listing;
761  stream_listing.size = fuse_listing.size();
762  stream_listing.capacity = fuse_listing.capacity();
763  bool large_alloc;
764  fuse_listing.ShareBuffer(&stream_listing.buffer, &large_alloc);
765  if (large_alloc)
766  stream_listing.capacity = 0;
767 
768  // Save the directory listing and return a handle to the listing
769  {
772  "linking directory handle %d to dir inode: %" PRIu64,
773  next_directory_handle_, uint64_t(ino));
774  (*directory_handles_)[next_directory_handle_] = stream_listing;
775  fi->fh = next_directory_handle_;
777  }
780 
781 #if (FUSE_VERSION >= 30)
782 #ifdef CVMFS_ENABLE_FUSE3_CACHE_READDIR
783  // This affects only reads on the same open directory handle (e.g. multiple
784  // reads with rewinddir() between them). A new opendir on the same directory
785  // will trigger readdir calls independently of this setting.
786  fi->cache_readdir = 1;
787 #endif
788 #endif
789  fuse_reply_open(req, fi);
790 }
791 
792 
796 static void cvmfs_releasedir(fuse_req_t req, fuse_ino_t ino,
797  struct fuse_file_info *fi)
798 {
800 
801  ino = mount_point_->catalog_mgr()->MangleInode(ino);
802  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_releasedir on inode %" PRIu64
803  ", handle %d", uint64_t(ino), fi->fh);
804 
805  int reply = 0;
806 
807  {
809  DirectoryHandles::iterator iter_handle = directory_handles_->find(fi->fh);
810  if (iter_handle != directory_handles_->end()) {
811  if (iter_handle->second.capacity == 0)
812  smunmap(iter_handle->second.buffer);
813  else
814  free(iter_handle->second.buffer);
815  directory_handles_->erase(iter_handle);
817  } else {
818  reply = EINVAL;
819  }
820  }
821 
822  fuse_reply_err(req, reply);
823 }
824 
825 
829 static void ReplyBufferSlice(const fuse_req_t req, const char *buffer,
830  const size_t buffer_size, const off_t offset,
831  const size_t max_size)
832 {
833  if (offset < static_cast<int>(buffer_size)) {
834  fuse_reply_buf(req, buffer + offset,
835  std::min(static_cast<size_t>(buffer_size - offset), max_size));
836  } else {
837  fuse_reply_buf(req, NULL, 0);
838  }
839 }
840 
841 
845 static void cvmfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
846  off_t off, struct fuse_file_info *fi)
847 {
849 
851  "cvmfs_readdir on inode %" PRIu64 " reading %d bytes from offset %d",
852  uint64_t(mount_point_->catalog_mgr()->MangleInode(ino)), size, off);
853 
854  DirectoryListing listing;
855 
857  DirectoryHandles::const_iterator iter_handle =
858  directory_handles_->find(fi->fh);
859  if (iter_handle != directory_handles_->end()) {
860  listing = iter_handle->second;
861 
862  ReplyBufferSlice(req, listing.buffer, listing.size, off, size);
863  return;
864  }
865 
866  fuse_reply_err(req, EINVAL);
867 }
868 
870  struct fuse_file_info *fi)
871 {
873  fi->keep_cache = od.keep_cache;
874  fi->direct_io = od.direct_io;
875  if (fi->direct_io)
877 }
878 
879 
886 static void cvmfs_open(fuse_req_t req, fuse_ino_t ino,
887  struct fuse_file_info *fi)
888 {
890 
891  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
892  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
895  ino = catalog_mgr->MangleInode(ino);
896  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_open on inode: %" PRIu64,
897  uint64_t(ino));
898 
899  int fd = -1;
901  PathString path;
902 
903  bool found = GetPathForInode(ino, &path);
904  if (!found) {
906  fuse_reply_err(req, ENOENT);
907  return;
908  }
909  found = GetDirentForInode(ino, &dirent);
910  if (!found) {
912  ReplyNegative(dirent, req);
913  return;
914  }
915 
916  if (!CheckVoms(*fuse_ctx)) {
918  fuse_reply_err(req, EACCES);
919  return;
920  }
921 
922  mount_point_->tracer()->Trace(Tracer::kEventOpen, path, "open()");
923  // Don't check. Either done by the OS or one wants to purposefully work
924  // around wrong open flags
925  // if ((fi->flags & 3) != O_RDONLY) {
926  // fuse_reply_err(req, EROFS);
927  // return;
928  // }
929 #ifdef __APPLE__
930  if ((fi->flags & O_SHLOCK) || (fi->flags & O_EXLOCK)) {
932  fuse_reply_err(req, EOPNOTSUPP);
933  return;
934  }
935 #endif
936  if (fi->flags & O_EXCL) {
938  fuse_reply_err(req, EEXIST);
939  return;
940  }
941 
942  perf::Inc(file_system_->n_fs_open()); // Count actual open / fetch operations
943 
945  if (!dirent.IsChunkedFile()) {
946  if (dirent.IsDirectIo()) {
947  open_directives = mount_point_->page_cache_tracker()->OpenDirect();
948  } else {
949  open_directives =
950  mount_point_->page_cache_tracker()->Open(ino, dirent.checksum());
951  }
953  } else {
955  "chunked file %s opened (download delayed to read() call)",
956  path.c_str());
957 
959  (static_cast<int>(max_open_files_))-kNumReservedFd)
960  {
963  LogCvmfs(kLogCvmfs, kLogSyslogErr, "open file descriptor limit exceeded");
964  fuse_reply_err(req, EMFILE);
965  return;
966  }
967 
968  // Figure out unique inode from annotated catalog
969  catalog::DirectoryEntry dirent_origin;
970  if (!catalog_mgr->LookupPath(path, catalog::kLookupSole, &dirent_origin)) {
973  "chunked file %s vanished unexpectedly", path.c_str());
974  fuse_reply_err(req, ENOENT);
975  return;
976  }
977  const uint64_t unique_inode = dirent_origin.inode();
978 
979  ChunkTables *chunk_tables = mount_point_->chunk_tables();
980  chunk_tables->Lock();
981  if (!chunk_tables->inode2chunks.Contains(unique_inode)) {
982  chunk_tables->Unlock();
983 
984  // Retrieve File chunks from the catalog
986  if (!catalog_mgr->ListFileChunks(path, dirent.hash_algorithm(),
987  chunks.weak_ref()) ||
988  chunks->IsEmpty())
989  {
991  LogCvmfs(kLogCvmfs, kLogDebug| kLogSyslogErr, "file %s is marked as "
992  "'chunked', but no chunks found.", path.c_str());
993  fuse_reply_err(req, EIO);
994  return;
995  }
997 
998  chunk_tables->Lock();
999  // Check again to avoid race
1000  if (!chunk_tables->inode2chunks.Contains(unique_inode)) {
1001  chunk_tables->inode2chunks.Insert(
1002  unique_inode, FileChunkReflist(chunks.Release(), path,
1003  dirent.compression_algorithm(),
1004  dirent.IsExternalFile()));
1005  chunk_tables->inode2references.Insert(unique_inode, 1);
1006  } else {
1007  uint32_t refctr;
1008  bool retval =
1009  chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1010  assert(retval);
1011  chunk_tables->inode2references.Insert(unique_inode, refctr+1);
1012  }
1013  } else {
1014  fuse_remounter_->fence()->Leave();
1015  uint32_t refctr;
1016  bool retval =
1017  chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1018  assert(retval);
1019  chunk_tables->inode2references.Insert(unique_inode, refctr+1);
1020  }
1021 
1022  // Update the chunk handle list
1024  "linking chunk handle %d to unique inode: %" PRIu64,
1025  chunk_tables->next_handle, uint64_t(unique_inode));
1026  chunk_tables->handle2fd.Insert(chunk_tables->next_handle, ChunkFd());
1027  chunk_tables->handle2uniqino.Insert(chunk_tables->next_handle,
1028  unique_inode);
1029 
1030  // Generate artificial content hash as hash over chunk hashes
1031  // TODO(jblomer): we may want to cache the result in the chunk tables
1032  FileChunkReflist chunk_reflist;
1033  bool retval =
1034  chunk_tables->inode2chunks.Lookup(unique_inode, &chunk_reflist);
1035  assert(retval);
1036 
1037  fi->fh = chunk_tables->next_handle;
1038  if (dirent.IsDirectIo()) {
1039  open_directives = mount_point_->page_cache_tracker()->OpenDirect();
1040  } else {
1041  open_directives = mount_point_->page_cache_tracker()->Open(
1042  ino, chunk_reflist.HashChunkList());
1043  }
1044  FillOpenFlags(open_directives, fi);
1045  fi->fh = static_cast<uint64_t>(-static_cast<int64_t>(fi->fh));
1046  ++chunk_tables->next_handle;
1047  chunk_tables->Unlock();
1048 
1049  fuse_reply_open(req, fi);
1050  return;
1051  }
1052 
1053  Fetcher *this_fetcher = dirent.IsExternalFile()
1055  : mount_point_->fetcher();
1056  fd = this_fetcher->Fetch(
1057  dirent.checksum(),
1058  dirent.size(),
1059  string(path.GetChars(), path.GetLength()),
1060  dirent.compression_algorithm(),
1064 
1065  if (fd >= 0) {
1067  (static_cast<int>(max_open_files_))-kNumReservedFd) {
1068  LogCvmfs(kLogCvmfs, kLogDebug, "file %s opened (fd %d)",
1069  path.c_str(), fd);
1070  fi->fh = fd;
1071  FillOpenFlags(open_directives, fi);
1072  fuse_reply_open(req, fi);
1073  return;
1074  } else {
1075  if (file_system_->cache_mgr()->Close(fd) == 0)
1077  LogCvmfs(kLogCvmfs, kLogSyslogErr, "open file descriptor limit exceeded");
1078  fuse_reply_err(req, EMFILE);
1079  return;
1080  }
1081  assert(false);
1082  }
1083 
1084  // fd < 0
1086  "failed to open inode: %" PRIu64 ", CAS key %s, error code %d",
1087  uint64_t(ino), dirent.checksum().ToString().c_str(), errno);
1088  if (errno == EMFILE) {
1089  fuse_reply_err(req, EMFILE);
1090  return;
1091  }
1092 
1094 
1096  fuse_reply_err(req, -fd);
1097 }
1098 
1099 
1103 static void cvmfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1104  struct fuse_file_info *fi)
1105 {
1107 
1109  "cvmfs_read inode: %" PRIu64 " reading %d bytes from offset %d "
1110  "fd %d", uint64_t(mount_point_->catalog_mgr()->MangleInode(ino)),
1111  size, off, fi->fh);
1113 
1114  // Get data chunk (<=128k guaranteed by Fuse)
1115  char *data = static_cast<char *>(alloca(size));
1116  unsigned int overall_bytes_fetched = 0;
1117 
1118  int64_t fd = static_cast<int64_t>(fi->fh);
1119  uint64_t abs_fd = (fd < 0) ? -fd : fd;
1121 
1122  // Do we have a a chunked file?
1123  if (fd < 0) {
1124  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1125  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
1126 
1127  const uint64_t chunk_handle = abs_fd;
1128  uint64_t unique_inode;
1129  ChunkFd chunk_fd;
1130  FileChunkReflist chunks;
1131  bool retval;
1132 
1133  // Fetch unique inode, chunk list and file descriptor
1134  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1135  chunk_tables->Lock();
1136  retval = chunk_tables->handle2uniqino.Lookup(chunk_handle, &unique_inode);
1137  if (!retval) {
1138  LogCvmfs(kLogCvmfs, kLogDebug, "no unique inode, fall back to fuse ino");
1139  unique_inode = ino;
1140  }
1141  retval = chunk_tables->inode2chunks.Lookup(unique_inode, &chunks);
1142  assert(retval);
1143  chunk_tables->Unlock();
1144 
1145  unsigned chunk_idx = chunks.FindChunkIdx(off);
1146 
1147  // Lock chunk handle
1148  pthread_mutex_t *handle_lock = chunk_tables->Handle2Lock(chunk_handle);
1149  MutexLockGuard m(handle_lock);
1150  chunk_tables->Lock();
1151  retval = chunk_tables->handle2fd.Lookup(chunk_handle, &chunk_fd);
1152  assert(retval);
1153  chunk_tables->Unlock();
1154 
1155  // Fetch all needed chunks and read the requested data
1156  off_t offset_in_chunk = off - chunks.list->AtPtr(chunk_idx)->offset();
1157  do {
1158  // Open file descriptor to chunk
1159  if ((chunk_fd.fd == -1) || (chunk_fd.chunk_idx != chunk_idx)) {
1160  if (chunk_fd.fd != -1) file_system_->cache_mgr()->Close(chunk_fd.fd);
1161  string verbose_path = "Part of " + chunks.path.ToString();
1162  if (chunks.external_data) {
1163  chunk_fd.fd = mount_point_->external_fetcher()->Fetch(
1164  chunks.list->AtPtr(chunk_idx)->content_hash(),
1165  chunks.list->AtPtr(chunk_idx)->size(),
1166  verbose_path,
1167  chunks.compression_alg,
1171  chunks.path.ToString(),
1172  chunks.list->AtPtr(chunk_idx)->offset());
1173  } else {
1174  chunk_fd.fd = mount_point_->fetcher()->Fetch(
1175  chunks.list->AtPtr(chunk_idx)->content_hash(),
1176  chunks.list->AtPtr(chunk_idx)->size(),
1177  verbose_path,
1178  chunks.compression_alg,
1182  }
1183  if (chunk_fd.fd < 0) {
1184  chunk_fd.fd = -1;
1185  chunk_tables->Lock();
1186  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1187  chunk_tables->Unlock();
1188  fuse_reply_err(req, EIO);
1189  return;
1190  }
1191  chunk_fd.chunk_idx = chunk_idx;
1192  }
1193 
1194  LogCvmfs(kLogCvmfs, kLogDebug, "reading from chunk fd %d",
1195  chunk_fd.fd);
1196  // Read data from chunk
1197  const size_t bytes_to_read = size - overall_bytes_fetched;
1198  const size_t remaining_bytes_in_chunk =
1199  chunks.list->AtPtr(chunk_idx)->size() - offset_in_chunk;
1200  size_t bytes_to_read_in_chunk =
1201  std::min(bytes_to_read, remaining_bytes_in_chunk);
1202  const int64_t bytes_fetched = file_system_->cache_mgr()->Pread(
1203  chunk_fd.fd,
1204  data + overall_bytes_fetched,
1205  bytes_to_read_in_chunk,
1206  offset_in_chunk);
1207 
1208  if (bytes_fetched < 0) {
1209  LogCvmfs(kLogCvmfs, kLogSyslogErr, "read err no %" PRId64 " (%s)",
1210  bytes_fetched, chunks.path.ToString().c_str());
1211  chunk_tables->Lock();
1212  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1213  chunk_tables->Unlock();
1214  fuse_reply_err(req, -bytes_fetched);
1215  return;
1216  }
1217  overall_bytes_fetched += bytes_fetched;
1218 
1219  // Proceed to the next chunk to keep on reading data
1220  ++chunk_idx;
1221  offset_in_chunk = 0;
1222  } while ((overall_bytes_fetched < size) &&
1223  (chunk_idx < chunks.list->size()));
1224 
1225  // Update chunk file descriptor
1226  chunk_tables->Lock();
1227  chunk_tables->handle2fd.Insert(chunk_handle, chunk_fd);
1228  chunk_tables->Unlock();
1229  LogCvmfs(kLogCvmfs, kLogDebug, "released chunk file descriptor %d",
1230  chunk_fd.fd);
1231  } else {
1232  int64_t nbytes = file_system_->cache_mgr()->Pread(abs_fd, data, size, off);
1233  if (nbytes < 0) {
1234  fuse_reply_err(req, -nbytes);
1235  return;
1236  }
1237  overall_bytes_fetched = nbytes;
1238  }
1239 
1240  // Push it to user
1241  fuse_reply_buf(req, data, overall_bytes_fetched);
1242  LogCvmfs(kLogCvmfs, kLogDebug, "pushed %d bytes to user",
1243  overall_bytes_fetched);
1244 }
1245 
1246 
1250 static void cvmfs_release(fuse_req_t req, fuse_ino_t ino,
1251  struct fuse_file_info *fi)
1252 {
1254 
1255  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1256  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_release on inode: %" PRIu64,
1257  uint64_t(ino));
1258  int64_t fd = static_cast<int64_t>(fi->fh);
1259  uint64_t abs_fd = (fd < 0) ? -fd : fd;
1263 
1264  // do we have a chunked file?
1265  if (fd < 0) {
1266  const uint64_t chunk_handle = abs_fd;
1267  LogCvmfs(kLogCvmfs, kLogDebug, "releasing chunk handle %" PRIu64,
1268  chunk_handle);
1269  uint64_t unique_inode;
1270  ChunkFd chunk_fd;
1271  FileChunkReflist chunks;
1272  uint32_t refctr;
1273  bool retval;
1274 
1275  ChunkTables *chunk_tables = mount_point_->chunk_tables();
1276  chunk_tables->Lock();
1277  retval = chunk_tables->handle2uniqino.Lookup(chunk_handle, &unique_inode);
1278  if (!retval) {
1279  LogCvmfs(kLogCvmfs, kLogDebug, "no unique inode, fall back to fuse ino");
1280  unique_inode = ino;
1281  } else {
1282  chunk_tables->handle2uniqino.Erase(chunk_handle);
1283  }
1284  retval = chunk_tables->handle2fd.Lookup(chunk_handle, &chunk_fd);
1285  assert(retval);
1286  chunk_tables->handle2fd.Erase(chunk_handle);
1287 
1288  retval = chunk_tables->inode2references.Lookup(unique_inode, &refctr);
1289  assert(retval);
1290  refctr--;
1291  if (refctr == 0) {
1292  LogCvmfs(kLogCvmfs, kLogDebug, "releasing chunk list for inode %" PRIu64,
1293  uint64_t(unique_inode));
1294  FileChunkReflist to_delete;
1295  retval = chunk_tables->inode2chunks.Lookup(unique_inode, &to_delete);
1296  assert(retval);
1297  chunk_tables->inode2references.Erase(unique_inode);
1298  chunk_tables->inode2chunks.Erase(unique_inode);
1299  delete to_delete.list;
1300  } else {
1301  chunk_tables->inode2references.Insert(unique_inode, refctr);
1302  }
1303  chunk_tables->Unlock();
1304 
1305  if (chunk_fd.fd != -1)
1306  file_system_->cache_mgr()->Close(chunk_fd.fd);
1308  } else {
1309  if (file_system_->cache_mgr()->Close(abs_fd) == 0) {
1311  }
1312  }
1313  fuse_reply_err(req, 0);
1314 }
1315 
1316 
1317 static void cvmfs_statfs(fuse_req_t req, fuse_ino_t ino) {
1318  ino = mount_point_->catalog_mgr()->MangleInode(ino);
1319  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_statfs on inode: %" PRIu64,
1320  uint64_t(ino));
1321 
1322  // If we return 0 it will cause the fs to be ignored in "df"
1323  struct statvfs info;
1324  memset(&info, 0, sizeof(info));
1325 
1326  TraceInode(Tracer::kEventStatFs, ino, "statfs()");
1327 
1328  // Unmanaged cache
1331  {
1332  fuse_reply_statfs(req, &info);
1333  return;
1334  }
1335 
1336  uint64_t available = 0;
1337  uint64_t size = file_system_->cache_mgr()->quota_mgr()->GetSize();
1338  uint64_t capacity = file_system_->cache_mgr()->quota_mgr()->GetCapacity();
1339  // Fuse/OS X doesn't like values < 512
1340  info.f_bsize = info.f_frsize = 512;
1341 
1342  if (capacity == (uint64_t)(-1)) {
1343  // Unknown capacity, set capacity = size
1344  info.f_blocks = size / info.f_bsize;
1345  } else {
1346  // Take values from LRU module
1347  info.f_blocks = capacity / info.f_bsize;
1348  available = capacity - size;
1349  }
1350 
1351  info.f_bfree = info.f_bavail = available / info.f_bsize;
1352 
1353  // Inodes / entries
1354  fuse_remounter_->fence()->Enter();
1355  uint64_t all_inodes = mount_point_->catalog_mgr()->all_inodes();
1356  uint64_t loaded_inode = mount_point_->catalog_mgr()->loaded_inodes();
1357  info.f_files = all_inodes;
1358  info.f_ffree = info.f_favail = all_inodes - loaded_inode;
1359  fuse_remounter_->fence()->Leave();
1360 
1361  fuse_reply_statfs(req, &info);
1362 }
1363 
1364 #ifdef __APPLE__
1365 static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1366  size_t size, uint32_t position)
1367 #else
1368 static void cvmfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1369  size_t size)
1370 #endif
1371 {
1372  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1373  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
1374 
1375  fuse_remounter_->fence()->Enter();
1377  ino = catalog_mgr->MangleInode(ino);
1379  "cvmfs_getxattr on inode: %" PRIu64 " for xattr: %s",
1380  uint64_t(ino), name);
1381  if (!CheckVoms(*fuse_ctx)) {
1382  fuse_remounter_->fence()->Leave();
1383  fuse_reply_err(req, EACCES);
1384  return;
1385  }
1386  TraceInode(Tracer::kEventGetXAttr, ino, "getxattr()");
1387 
1388  const string attr = name;
1390  const bool found = GetDirentForInode(ino, &d);
1391  bool retval;
1392  XattrList xattrs;
1393 
1394  PathString path;
1395  retval = GetPathForInode(ino, &path);
1396  assert(retval);
1397  if (d.IsLink()) {
1398  catalog::LookupOptions lookup_options = static_cast<catalog::LookupOptions>(
1400  catalog::DirectoryEntry raw_symlink;
1401  retval = catalog_mgr->LookupPath(path, lookup_options, &raw_symlink);
1402  assert(retval);
1403  d.set_symlink(raw_symlink.symlink());
1404  }
1405  if (d.HasXattrs()) {
1406  retval = catalog_mgr->LookupXattrs(path, &xattrs);
1407  assert(retval);
1408  }
1409 
1410  bool magic_xattr_success = true;
1412  attr, path, &d));
1413  if (!magic_xattr.IsNull()) {
1414  magic_xattr_success = magic_xattr->PrepareValueFenced();
1415  }
1416 
1417  fuse_remounter_->fence()->Leave();
1418 
1419  if (!found) {
1420  ReplyNegative(d, req);
1421  return;
1422  }
1423 
1424  if (!magic_xattr_success) {
1425  fuse_reply_err(req, ENOATTR);
1426  return;
1427  }
1428 
1429  string attribute_value;
1430 
1431  if (!magic_xattr.IsNull()) {
1432  attribute_value = magic_xattr->GetValue();
1433  } else {
1434  if (!xattrs.Get(attr, &attribute_value)) {
1435  fuse_reply_err(req, ENOATTR);
1436  return;
1437  }
1438  }
1439 
1440  if (size == 0) {
1441  fuse_reply_xattr(req, attribute_value.length());
1442  } else if (size >= attribute_value.length()) {
1443  fuse_reply_buf(req, &attribute_value[0], attribute_value.length());
1444  } else {
1445  fuse_reply_err(req, ERANGE);
1446  }
1447 }
1448 
1449 
1450 static void cvmfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) {
1451  const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
1452  ClientCtxGuard ctx_guard(fuse_ctx->uid, fuse_ctx->gid, fuse_ctx->pid);
1453 
1454  fuse_remounter_->fence()->Enter();
1456  ino = catalog_mgr->MangleInode(ino);
1457  TraceInode(Tracer::kEventListAttr, ino, "listxattr()");
1459  "cvmfs_listxattr on inode: %" PRIu64 ", size %u [visibility %d]",
1460  uint64_t(ino), size,
1462 
1464  const bool found = GetDirentForInode(ino, &d);
1465  XattrList xattrs;
1466  if (d.HasXattrs()) {
1467  PathString path;
1468  bool retval = GetPathForInode(ino, &path);
1469  assert(retval);
1470  retval = catalog_mgr->LookupXattrs(path, &xattrs);
1471  assert(retval);
1472  }
1473  fuse_remounter_->fence()->Leave();
1474 
1475  if (!found) {
1476  ReplyNegative(d, req);
1477  return;
1478  }
1479 
1480  string attribute_list;
1481  attribute_list = mount_point_->magic_xattr_mgr()->GetListString(&d);
1482  attribute_list = xattrs.ListKeysPosix(attribute_list);
1483 
1484  if (size == 0) {
1485  fuse_reply_xattr(req, attribute_list.length());
1486  } else if (size >= attribute_list.length()) {
1487  if (attribute_list.empty())
1488  fuse_reply_buf(req, NULL, 0);
1489  else
1490  fuse_reply_buf(req, &attribute_list[0], attribute_list.length());
1491  } else {
1492  fuse_reply_err(req, ERANGE);
1493  }
1494 }
1495 
1496 
1497 bool Evict(const string &path) {
1498  catalog::DirectoryEntry dirent;
1499  fuse_remounter_->fence()->Enter();
1500  const bool found = GetDirentForPath(PathString(path), &dirent);
1501  fuse_remounter_->fence()->Leave();
1502 
1503  if (!found || !dirent.IsRegular())
1504  return false;
1505  file_system_->cache_mgr()->quota_mgr()->Remove(dirent.checksum());
1506  return true;
1507 }
1508 
1509 
1510 bool Pin(const string &path) {
1511  catalog::DirectoryEntry dirent;
1512  fuse_remounter_->fence()->Enter();
1513  const bool found = GetDirentForPath(PathString(path), &dirent);
1514  if (!found || !dirent.IsRegular()) {
1515  fuse_remounter_->fence()->Leave();
1516  return false;
1517  }
1518 
1519  if (!dirent.IsChunkedFile()) {
1520  fuse_remounter_->fence()->Leave();
1521  } else {
1522  FileChunkList chunks;
1524  PathString(path), dirent.hash_algorithm(), &chunks);
1525  fuse_remounter_->fence()->Leave();
1526  for (unsigned i = 0; i < chunks.size(); ++i) {
1527  bool retval =
1529  chunks.AtPtr(i)->content_hash(),
1530  chunks.AtPtr(i)->size(),
1531  "Part of " + path,
1532  false);
1533  if (!retval)
1534  return false;
1535  int fd = -1;
1536  if (dirent.IsExternalFile()) {
1538  chunks.AtPtr(i)->content_hash(),
1539  chunks.AtPtr(i)->size(),
1540  "Part of " + path,
1541  dirent.compression_algorithm(),
1543  path,
1544  chunks.AtPtr(i)->offset());
1545  } else {
1546  fd = mount_point_->fetcher()->Fetch(
1547  chunks.AtPtr(i)->content_hash(),
1548  chunks.AtPtr(i)->size(),
1549  "Part of " + path,
1550  dirent.compression_algorithm(),
1552  }
1553  if (fd < 0) {
1554  return false;
1555  }
1556  file_system_->cache_mgr()->Close(fd);
1557  }
1558  return true;
1559  }
1560 
1561  bool retval = file_system_->cache_mgr()->quota_mgr()->Pin(
1562  dirent.checksum(), dirent.size(), path, false);
1563  if (!retval)
1564  return false;
1565  Fetcher *this_fetcher = dirent.IsExternalFile()
1567  : mount_point_->fetcher();
1568  int fd = this_fetcher->Fetch(
1569  dirent.checksum(), dirent.size(), path, dirent.compression_algorithm(),
1571  if (fd < 0) {
1572  return false;
1573  }
1574  file_system_->cache_mgr()->Close(fd);
1575  return true;
1576 }
1577 
1578 
1582 static void cvmfs_init(void *userdata, struct fuse_conn_info *conn) {
1583  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_init");
1584 
1585  // NFS support
1586 #ifdef CVMFS_NFS_SUPPORT
1587  conn->want |= FUSE_CAP_EXPORT_SUPPORT;
1588 #endif
1589 
1590  if (mount_point_->enforce_acls()) {
1591 #ifdef FUSE_CAP_POSIX_ACL
1592  if ((conn->capable & FUSE_CAP_POSIX_ACL) == 0) {
1594  "ACL support requested but missing fuse kernel support, "
1595  "aborting");
1596  }
1597  conn->want |= FUSE_CAP_POSIX_ACL;
1598  LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog, "enforcing ACLs");
1599 #else
1601  "ACL support requested but not available in this version of "
1602  "libfuse, aborting");
1603 #endif
1604  }
1605 }
1606 
1607 static void cvmfs_destroy(void *unused __attribute__((unused))) {
1608  // The debug log is already closed at this point
1609  LogCvmfs(kLogCvmfs, kLogDebug, "cvmfs_destroy");
1610 }
1611 
1615 static void SetCvmfsOperations(struct fuse_lowlevel_ops *cvmfs_operations) {
1616  memset(cvmfs_operations, 0, sizeof(*cvmfs_operations));
1617 
1618  // Init/Fini
1619  cvmfs_operations->init = cvmfs_init;
1620  cvmfs_operations->destroy = cvmfs_destroy;
1621 
1622  cvmfs_operations->lookup = cvmfs_lookup;
1623  cvmfs_operations->getattr = cvmfs_getattr;
1624  cvmfs_operations->readlink = cvmfs_readlink;
1625  cvmfs_operations->open = cvmfs_open;
1626  cvmfs_operations->read = cvmfs_read;
1627  cvmfs_operations->release = cvmfs_release;
1628  cvmfs_operations->opendir = cvmfs_opendir;
1629  cvmfs_operations->readdir = cvmfs_readdir;
1630  cvmfs_operations->releasedir = cvmfs_releasedir;
1631  cvmfs_operations->statfs = cvmfs_statfs;
1632  cvmfs_operations->getxattr = cvmfs_getxattr;
1633  cvmfs_operations->listxattr = cvmfs_listxattr;
1634  cvmfs_operations->forget = cvmfs_forget;
1635 #if (FUSE_VERSION >= 29)
1636  cvmfs_operations->forget_multi = cvmfs_forget_multi;
1637 #endif
1638 }
1639 
1640 // Called by cvmfs_talk when switching into read-only cache mode
1642  if (cvmfs::unpin_listener_) {
1644  cvmfs::unpin_listener_ = NULL;
1645  }
1649  }
1650 }
1651 
1652 bool SendFuseFd(const std::string &socket_path) {
1653  int fuse_fd;
1654 #if (FUSE_VERSION >= 30)
1655  fuse_fd = fuse_session_fd(*reinterpret_cast<struct fuse_session**>(
1657 #else
1658  fuse_fd = fuse_chan_fd(*reinterpret_cast<struct fuse_chan**>(
1660 #endif
1661  assert(fuse_fd >= 0);
1662  int sock_fd = ConnectSocket(socket_path);
1663  if (sock_fd < 0) {
1664  LogCvmfs(kLogCvmfs, kLogDebug, "cannot connect to socket %s: %d",
1665  socket_path.c_str(), errno);
1666  return false;
1667  }
1668  bool retval = SendFd2Socket(sock_fd, fuse_fd);
1669  close(sock_fd);
1670  return retval;
1671 }
1672 
1673 } // namespace cvmfs
1674 
1675 
1676 string *g_boot_error = NULL;
1677 
1678 __attribute__((visibility("default")))
1679 loader::CvmfsExports *g_cvmfs_exports = NULL;
1680 
1687 
1688  virtual bool PrepareValueFenced() {
1689  catalogs_valid_until_ = cvmfs::fuse_remounter_->catalogs_valid_until();
1690  return true;
1691  }
1692 
1693  virtual std::string GetValue() {
1694  if (catalogs_valid_until_ == MountPoint::kIndefiniteDeadline) {
1695  return "never (fixed root catalog)";
1696  } else {
1697  time_t now = time(NULL);
1698  return StringifyInt( (catalogs_valid_until_ - now) / 60);
1699  }
1700  }
1701 };
1702 
1704  virtual std::string GetValue() {
1705  return StringifyInt(
1706  cvmfs::inode_generation_info_.inode_generation +
1708  }
1709 };
1710 
1712  virtual std::string GetValue() {
1714  }
1715 };
1716 
1718  virtual std::string GetValue() { return StringifyInt(cvmfs::pid_); }
1719 };
1720 
1722  virtual std::string GetValue() {
1723  time_t now = time(NULL);
1724  uint64_t uptime = now - cvmfs::loader_exports_->boot_time;
1725  return StringifyInt(uptime / 60);
1726  }
1727 };
1728 
1733 static void RegisterMagicXattrs() {
1735  mgr->Register("user.expires", new ExpiresMagicXattr());
1736  mgr->Register("user.inode_max", new InodeMaxMagicXattr());
1737  mgr->Register("user.pid", new PidMagicXattr());
1738  mgr->Register("user.maxfd", new MaxFdMagicXattr());
1739  mgr->Register("user.uptime", new UptimeMagicXattr());
1740 }
1741 
1747  const string &mount_path,
1748  const string &fqrn,
1750 {
1751  fs_info.wait_workspace = false;
1752  FileSystem *file_system = FileSystem::Create(fs_info);
1753 
1754  if (file_system->boot_status() == loader::kFailLockWorkspace) {
1755  string fqrn_from_xattr;
1756  int retval = platform_getxattr(mount_path, "user.fqrn", &fqrn_from_xattr);
1757  if (!retval) {
1758  // Cvmfs not mounted anymore, but another cvmfs process is still in
1759  // shutdown procedure. Try again and wait for lock
1760  delete file_system;
1761  fs_info.wait_workspace = true;
1762  file_system = FileSystem::Create(fs_info);
1763  } else {
1764  if (fqrn_from_xattr == fqrn) {
1766  "repository already mounted on %s", mount_path.c_str());
1768  } else {
1770  "CernVM-FS repository %s already mounted on %s",
1771  fqrn.c_str(), mount_path.c_str());
1773  }
1774  }
1775  }
1776 
1777  return file_system;
1778 }
1779 
1780 
1781 static void InitOptionsMgr(const loader::LoaderExports *loader_exports) {
1782  if (loader_exports->version >= 3 && loader_exports->simple_options_parsing) {
1784  new DefaultOptionsTemplateManager(loader_exports->repository_name));
1785  } else {
1787  new DefaultOptionsTemplateManager(loader_exports->repository_name));
1788  }
1789 
1790  if (loader_exports->config_files != "") {
1791  vector<string> tokens = SplitString(loader_exports->config_files, ':');
1792  for (unsigned i = 0, s = tokens.size(); i < s; ++i) {
1793  cvmfs::options_mgr_->ParsePath(tokens[i], false);
1794  }
1795  } else {
1797  }
1798 }
1799 
1800 
1801 static int Init(const loader::LoaderExports *loader_exports) {
1802  g_boot_error = new string("unknown error");
1803  cvmfs::loader_exports_ = loader_exports;
1804  InitOptionsMgr(loader_exports);
1805 
1807  fs_info.type = FileSystem::kFsFuse;
1808  fs_info.name = loader_exports->repository_name;
1809  fs_info.exe_path = loader_exports->program_name;
1810  fs_info.options_mgr = cvmfs::options_mgr_;
1811  fs_info.foreground = loader_exports->foreground;
1813  loader_exports->mount_point,
1814  loader_exports->repository_name,
1815  fs_info);
1816  if (!cvmfs::file_system_->IsValid()) {
1818  return cvmfs::file_system_->boot_status();
1819  }
1820 
1823  if (!cvmfs::mount_point_->IsValid()) {
1825  return cvmfs::mount_point_->boot_status();
1826  }
1827 
1829 
1831  cvmfs::directory_handles_->set_empty_key((uint64_t)(-1));
1832  cvmfs::directory_handles_->set_deleted_key((uint64_t)(-2));
1833 
1834  LogCvmfs(kLogCvmfs, kLogDebug, "fuse inode size is %d bits",
1835  sizeof(fuse_ino_t) * 8);
1836 
1841  LogCvmfs(kLogCvmfs, kLogDebug, "root inode is %" PRIu64,
1842  uint64_t(cvmfs::mount_point_->catalog_mgr()->GetRootInode()));
1843 
1844  void **channel_or_session = NULL;
1845  if (loader_exports->version >= 4) {
1846  channel_or_session = loader_exports->fuse_channel_or_session;
1847  }
1848 
1849  bool fuse_notify_invalidation = true;
1850  std::string buf;
1851  if (cvmfs::options_mgr_->GetValue("CVMFS_FUSE_NOTIFY_INVALIDATION",
1852  &buf)) {
1853  if (!cvmfs::options_mgr_->IsOn(buf)) {
1854  fuse_notify_invalidation = false;
1856  }
1857  }
1860  channel_or_session, fuse_notify_invalidation);
1861 
1862  // Monitor, check for maximum number of open files
1863  if (cvmfs::UseWatchdog()) {
1864  cvmfs::watchdog_ = Watchdog::Create("./stacktrace." +
1865  loader_exports->repository_name);
1866  if (cvmfs::watchdog_ == NULL) {
1867  *g_boot_error = "failed to initialize watchdog.";
1868  return loader::kFailMonitor;
1869  }
1870  }
1872 
1873  // Control & command interface
1875  cvmfs::mount_point_->talk_socket_path(),
1878  if ((cvmfs::mount_point_->talk_socket_uid() != 0) ||
1879  (cvmfs::mount_point_->talk_socket_gid() != 0))
1880  {
1881  uid_t tgt_uid = cvmfs::mount_point_->talk_socket_uid();
1882  gid_t tgt_gid = cvmfs::mount_point_->talk_socket_gid();
1883  int rvi = chown(cvmfs::mount_point_->talk_socket_path().c_str(),
1884  tgt_uid, tgt_gid);
1885  if (rvi != 0) {
1886  *g_boot_error = std::string("failed to set talk socket ownership - ")
1887  + "target " + StringifyInt(tgt_uid) + ":" + StringifyInt(tgt_uid)
1888  + ", user " + StringifyInt(geteuid()) + ":" + StringifyInt(getegid());
1889  return loader::kFailTalk;
1890  }
1891  }
1892  if (cvmfs::talk_mgr_ == NULL) {
1893  *g_boot_error = "failed to initialize talk socket (" +
1894  StringifyInt(errno) + ")";
1895  return loader::kFailTalk;
1896  }
1897 
1898  // Notification system client
1899  {
1901  if (options->IsDefined("CVMFS_NOTIFICATION_SERVER")) {
1902  std::string config;
1903  options->GetValue("CVMFS_NOTIFICATION_SERVER", &config);
1904  const std::string repo_name = cvmfs::mount_point_->fqrn();
1906  new NotificationClient(config, repo_name, cvmfs::fuse_remounter_,
1907  cvmfs::mount_point_->download_mgr(),
1909  }
1910  }
1911 
1912 
1913  auto_umount::SetMountpoint(loader_exports->mount_point);
1914 
1915  return loader::kFailOk;
1916 }
1917 
1918 
1922 static void Spawn() {
1923  // First thing: fork off the watchdog while we still have a single-threaded
1924  // well-defined state
1925  cvmfs::pid_ = getpid();
1926  if (cvmfs::watchdog_) {
1929  }
1930 
1932  if (cvmfs::mount_point_->nentry_tracker()->is_active()) {
1934  cvmfs::mount_point_->kcache_timeout_sec()); // Usually every minute
1935  }
1936 
1939  if (cvmfs::mount_point_->resolv_conf_watcher() != NULL)
1942  quota_mgr->Spawn();
1943  if (quota_mgr->HasCapability(QuotaManager::kCapListeners)) {
1945  quota_mgr,
1946  cvmfs::mount_point_->uuid()->uuid() + "-watchdog");
1948  quota_mgr,
1949  cvmfs::mount_point_->catalog_mgr(),
1950  cvmfs::mount_point_->uuid()->uuid() + "-unpin");
1951  }
1954 
1955  if (cvmfs::notification_client_ != NULL) {
1957  }
1958 
1959  if (cvmfs::file_system_->nfs_maps() != NULL)
1961 
1963 }
1964 
1965 
1966 static string GetErrorMsg() {
1967  if (g_boot_error)
1968  return *g_boot_error;
1969  return "";
1970 }
1971 
1972 
1978 static void ShutdownMountpoint() {
1979  delete cvmfs::talk_mgr_;
1980  cvmfs::talk_mgr_ = NULL;
1981 
1984 
1985  // The remonter has a reference to the mount point and the inode generation
1986  delete cvmfs::fuse_remounter_;
1987  cvmfs::fuse_remounter_ = NULL;
1988 
1989  // The unpin listener requires the catalog, so this must be unregistered
1990  // before the catalog manager is removed
1991  if (cvmfs::unpin_listener_ != NULL) {
1993  cvmfs::unpin_listener_ = NULL;
1994  }
1995  if (cvmfs::watchdog_listener_ != NULL) {
1998  }
1999 
2001  delete cvmfs::mount_point_;
2003  cvmfs::mount_point_ = NULL;
2004 }
2005 
2006 
2007 static void Fini() {
2009 
2010  delete cvmfs::file_system_;
2011  delete cvmfs::options_mgr_;
2012  cvmfs::file_system_ = NULL;
2013  cvmfs::options_mgr_ = NULL;
2014 
2015  delete cvmfs::watchdog_;
2016  cvmfs::watchdog_ = NULL;
2017 
2018  delete g_boot_error;
2019  g_boot_error = NULL;
2021 }
2022 
2023 
2024 static int AltProcessFlavor(int argc, char **argv) {
2025  if (strcmp(argv[1], "__cachemgr__") == 0) {
2026  return PosixQuotaManager::MainCacheManager(argc, argv);
2027  }
2028  if (strcmp(argv[1], "__wpad__") == 0) {
2029  return download::MainResolveProxyDescription(argc, argv);
2030  }
2031  return 1;
2032 }
2033 
2034 
2035 static bool MaintenanceMode(const int fd_progress) {
2036  SendMsg2Socket(fd_progress, "Entering maintenance mode\n");
2037  string msg_progress = "Draining out kernel caches (";
2039  msg_progress += "up to ";
2040  msg_progress += StringifyInt(static_cast<int>(
2041  cvmfs::mount_point_->kcache_timeout_sec())) +
2042  "s)\n";
2043  SendMsg2Socket(fd_progress, msg_progress);
2045  return true;
2046 }
2047 
2048 
2049 static bool SaveState(const int fd_progress, loader::StateList *saved_states) {
2050  string msg_progress;
2051 
2052  unsigned num_open_dirs = cvmfs::directory_handles_->size();
2053  if (num_open_dirs != 0) {
2054 #ifdef DEBUGMSG
2055  for (cvmfs::DirectoryHandles::iterator i =
2056  cvmfs::directory_handles_->begin(),
2057  iEnd = cvmfs::directory_handles_->end(); i != iEnd; ++i)
2058  {
2059  LogCvmfs(kLogCvmfs, kLogDebug, "saving dirhandle %d", i->first);
2060  }
2061 #endif
2062 
2063  msg_progress = "Saving open directory handles (" +
2064  StringifyInt(num_open_dirs) + " handles)\n";
2065  SendMsg2Socket(fd_progress, msg_progress);
2066 
2067  // TODO(jblomer): should rather be saved just in a malloc'd memory block
2068  cvmfs::DirectoryHandles *saved_handles =
2070  loader::SavedState *save_open_dirs = new loader::SavedState();
2071  save_open_dirs->state_id = loader::kStateOpenDirs;
2072  save_open_dirs->state = saved_handles;
2073  saved_states->push_back(save_open_dirs);
2074  }
2075 
2076  if (!cvmfs::file_system_->IsNfsSource()) {
2077  msg_progress = "Saving inode tracker\n";
2078  SendMsg2Socket(fd_progress, msg_progress);
2079  glue::InodeTracker *saved_inode_tracker =
2080  new glue::InodeTracker(*cvmfs::mount_point_->inode_tracker());
2081  loader::SavedState *state_glue_buffer = new loader::SavedState();
2082  state_glue_buffer->state_id = loader::kStateGlueBufferV4;
2083  state_glue_buffer->state = saved_inode_tracker;
2084  saved_states->push_back(state_glue_buffer);
2085  }
2086 
2087  msg_progress = "Saving negative entry cache\n";
2088  SendMsg2Socket(fd_progress, msg_progress);
2089  glue::NentryTracker *saved_nentry_cache =
2090  new glue::NentryTracker(*cvmfs::mount_point_->nentry_tracker());
2091  loader::SavedState *state_nentry_tracker = new loader::SavedState();
2092  state_nentry_tracker->state_id = loader::kStateNentryTracker;
2093  state_nentry_tracker->state = saved_nentry_cache;
2094  saved_states->push_back(state_nentry_tracker);
2095 
2096  msg_progress = "Saving page cache entry tracker\n";
2097  SendMsg2Socket(fd_progress, msg_progress);
2098  glue::PageCacheTracker *saved_page_cache_tracker =
2099  new glue::PageCacheTracker(*cvmfs::mount_point_->page_cache_tracker());
2100  loader::SavedState *state_page_cache_tracker = new loader::SavedState();
2101  state_page_cache_tracker->state_id = loader::kStatePageCacheTracker;
2102  state_page_cache_tracker->state = saved_page_cache_tracker;
2103  saved_states->push_back(state_page_cache_tracker);
2104 
2105  msg_progress = "Saving chunk tables\n";
2106  SendMsg2Socket(fd_progress, msg_progress);
2107  ChunkTables *saved_chunk_tables = new ChunkTables(
2108  *cvmfs::mount_point_->chunk_tables());
2109  loader::SavedState *state_chunk_tables = new loader::SavedState();
2110  state_chunk_tables->state_id = loader::kStateOpenChunksV4;
2111  state_chunk_tables->state = saved_chunk_tables;
2112  saved_states->push_back(state_chunk_tables);
2113 
2114  msg_progress = "Saving inode generation\n";
2115  SendMsg2Socket(fd_progress, msg_progress);
2118  cvmfs::InodeGenerationInfo *saved_inode_generation =
2120  loader::SavedState *state_inode_generation = new loader::SavedState();
2121  state_inode_generation->state_id = loader::kStateInodeGeneration;
2122  state_inode_generation->state = saved_inode_generation;
2123  saved_states->push_back(state_inode_generation);
2124 
2125  // Close open file catalogs
2127 
2128  loader::SavedState *state_cache_mgr = new loader::SavedState();
2129  state_cache_mgr->state_id = loader::kStateOpenFiles;
2130  state_cache_mgr->state =
2131  cvmfs::file_system_->cache_mgr()->SaveState(fd_progress);
2132  saved_states->push_back(state_cache_mgr);
2133 
2134  msg_progress = "Saving open files counter\n";
2135  uint32_t *saved_num_fd =
2136  new uint32_t(cvmfs::file_system_->no_open_files()->Get());
2137  loader::SavedState *state_num_fd = new loader::SavedState();
2138  state_num_fd->state_id = loader::kStateOpenFilesCounter;
2139  state_num_fd->state = saved_num_fd;
2140  saved_states->push_back(state_num_fd);
2141 
2142  return true;
2143 }
2144 
2145 
2146 static bool RestoreState(const int fd_progress,
2147  const loader::StateList &saved_states)
2148 {
2149  // If we have no saved version of the page cache tracker, it is unsafe
2150  // to start using it. The page cache tracker has to run for the entire
2151  // lifetime of the mountpoint or not at all.
2153 
2154  for (unsigned i = 0, l = saved_states.size(); i < l; ++i) {
2155  if (saved_states[i]->state_id == loader::kStateOpenDirs) {
2156  SendMsg2Socket(fd_progress, "Restoring open directory handles... ");
2158  cvmfs::DirectoryHandles *saved_handles =
2159  (cvmfs::DirectoryHandles *)saved_states[i]->state;
2160  cvmfs::directory_handles_ = new cvmfs::DirectoryHandles(*saved_handles);
2163  cvmfs::DirectoryHandles::const_iterator i =
2164  cvmfs::directory_handles_->begin();
2165  for (; i != cvmfs::directory_handles_->end(); ++i) {
2166  if (i->first >= cvmfs::next_directory_handle_)
2167  cvmfs::next_directory_handle_ = i->first + 1;
2168  }
2169 
2170  SendMsg2Socket(fd_progress,
2171  StringifyInt(cvmfs::directory_handles_->size()) + " handles\n");
2172  }
2173 
2174  if (saved_states[i]->state_id == loader::kStateGlueBuffer) {
2175  SendMsg2Socket(fd_progress, "Migrating inode tracker (v1 to v4)... ");
2176  compat::inode_tracker::InodeTracker *saved_inode_tracker =
2177  (compat::inode_tracker::InodeTracker *)saved_states[i]->state;
2179  saved_inode_tracker, cvmfs::mount_point_->inode_tracker());
2180  SendMsg2Socket(fd_progress, " done\n");
2181  }
2182 
2183  if (saved_states[i]->state_id == loader::kStateGlueBufferV2) {
2184  SendMsg2Socket(fd_progress, "Migrating inode tracker (v2 to v4)... ");
2185  compat::inode_tracker_v2::InodeTracker *saved_inode_tracker =
2186  (compat::inode_tracker_v2::InodeTracker *)saved_states[i]->state;
2187  compat::inode_tracker_v2::Migrate(saved_inode_tracker,
2188  cvmfs::mount_point_->inode_tracker());
2189  SendMsg2Socket(fd_progress, " done\n");
2190  }
2191 
2192  if (saved_states[i]->state_id == loader::kStateGlueBufferV3) {
2193  SendMsg2Socket(fd_progress, "Migrating inode tracker (v3 to v4)... ");
2194  compat::inode_tracker_v3::InodeTracker *saved_inode_tracker =
2195  (compat::inode_tracker_v3::InodeTracker *)saved_states[i]->state;
2196  compat::inode_tracker_v3::Migrate(saved_inode_tracker,
2197  cvmfs::mount_point_->inode_tracker());
2198  SendMsg2Socket(fd_progress, " done\n");
2199  }
2200 
2201  if (saved_states[i]->state_id == loader::kStateGlueBufferV4) {
2202  SendMsg2Socket(fd_progress, "Restoring inode tracker... ");
2204  glue::InodeTracker *saved_inode_tracker =
2205  (glue::InodeTracker *)saved_states[i]->state;
2207  glue::InodeTracker(*saved_inode_tracker);
2208  SendMsg2Socket(fd_progress, " done\n");
2209  }
2210 
2211  if (saved_states[i]->state_id == loader::kStateNentryTracker) {
2212  SendMsg2Socket(fd_progress, "Restoring negative entry cache... ");
2214  glue::NentryTracker *saved_nentry_tracker =
2215  (glue::NentryTracker *)saved_states[i]->state;
2217  glue::NentryTracker(*saved_nentry_tracker);
2218  SendMsg2Socket(fd_progress, " done\n");
2219  }
2220 
2221  if (saved_states[i]->state_id == loader::kStatePageCacheTracker) {
2222  SendMsg2Socket(fd_progress, "Restoring page cache entry tracker... ");
2224  glue::PageCacheTracker *saved_page_cache_tracker =
2225  (glue::PageCacheTracker *)saved_states[i]->state;
2227  glue::PageCacheTracker(*saved_page_cache_tracker);
2228  SendMsg2Socket(fd_progress, " done\n");
2229  }
2230 
2231  ChunkTables *chunk_tables = cvmfs::mount_point_->chunk_tables();
2232 
2233  if (saved_states[i]->state_id == loader::kStateOpenChunks) {
2234  SendMsg2Socket(fd_progress, "Migrating chunk tables (v1 to v4)... ");
2235  compat::chunk_tables::ChunkTables *saved_chunk_tables =
2236  (compat::chunk_tables::ChunkTables *)saved_states[i]->state;
2237  compat::chunk_tables::Migrate(saved_chunk_tables, chunk_tables);
2238  SendMsg2Socket(fd_progress,
2239  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2240  }
2241 
2242  if (saved_states[i]->state_id == loader::kStateOpenChunksV2) {
2243  SendMsg2Socket(fd_progress, "Migrating chunk tables (v2 to v4)... ");
2244  compat::chunk_tables_v2::ChunkTables *saved_chunk_tables =
2245  (compat::chunk_tables_v2::ChunkTables *)saved_states[i]->state;
2246  compat::chunk_tables_v2::Migrate(saved_chunk_tables, chunk_tables);
2247  SendMsg2Socket(fd_progress,
2248  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2249  }
2250 
2251  if (saved_states[i]->state_id == loader::kStateOpenChunksV3) {
2252  SendMsg2Socket(fd_progress, "Migrating chunk tables (v3 to v4)... ");
2253  compat::chunk_tables_v3::ChunkTables *saved_chunk_tables =
2254  (compat::chunk_tables_v3::ChunkTables *)saved_states[i]->state;
2255  compat::chunk_tables_v3::Migrate(saved_chunk_tables, chunk_tables);
2256  SendMsg2Socket(fd_progress,
2257  StringifyInt(chunk_tables->handle2fd.size()) + " handles\n");
2258  }
2259 
2260  if (saved_states[i]->state_id == loader::kStateOpenChunksV4) {
2261  SendMsg2Socket(fd_progress, "Restoring chunk tables... ");
2262  chunk_tables->~ChunkTables();
2263  ChunkTables *saved_chunk_tables = reinterpret_cast<ChunkTables *>(
2264  saved_states[i]->state);
2265  new (chunk_tables) ChunkTables(*saved_chunk_tables);
2266  SendMsg2Socket(fd_progress, " done\n");
2267  }
2268 
2269  if (saved_states[i]->state_id == loader::kStateInodeGeneration) {
2270  SendMsg2Socket(fd_progress, "Restoring inode generation... ");
2271  cvmfs::InodeGenerationInfo *old_info =
2272  (cvmfs::InodeGenerationInfo *)saved_states[i]->state;
2273  if (old_info->version == 1) {
2274  // Migration
2276  old_info->initial_revision;
2278  // Note: in the rare case of inode generation being 0 before, inode
2279  // can clash after reload before remount
2280  } else {
2281  cvmfs::inode_generation_info_ = *old_info;
2282  }
2284  SendMsg2Socket(fd_progress, " done\n");
2285  }
2286 
2287  if (saved_states[i]->state_id == loader::kStateOpenFilesCounter) {
2288  SendMsg2Socket(fd_progress, "Restoring open files counter... ");
2289  cvmfs::file_system_->no_open_files()->Set(*(reinterpret_cast<uint32_t *>(
2290  saved_states[i]->state)));
2291  SendMsg2Socket(fd_progress, " done\n");
2292  }
2293 
2294  if (saved_states[i]->state_id == loader::kStateOpenFiles) {
2295  int new_root_fd = cvmfs::file_system_->cache_mgr()->RestoreState(
2296  fd_progress, saved_states[i]->state);
2297  LogCvmfs(kLogCvmfs, kLogDebug, "new root file catalog descriptor @%d",
2298  new_root_fd);
2299  if (new_root_fd >= 0) {
2300  cvmfs::file_system_->RemapCatalogFd(0, new_root_fd);
2301  }
2302  }
2303  }
2304  if (cvmfs::mount_point_->inode_annotation()) {
2305  uint64_t saved_generation = cvmfs::inode_generation_info_.inode_generation;
2306  cvmfs::mount_point_->inode_annotation()->IncGeneration(saved_generation);
2307  }
2308 
2309  return true;
2310 }
2311 
2312 
2313 static void FreeSavedState(const int fd_progress,
2314  const loader::StateList &saved_states)
2315 {
2316  for (unsigned i = 0, l = saved_states.size(); i < l; ++i) {
2317  switch (saved_states[i]->state_id) {
2319  SendMsg2Socket(fd_progress, "Releasing saved open directory handles\n");
2320  delete static_cast<cvmfs::DirectoryHandles *>(saved_states[i]->state);
2321  break;
2324  fd_progress, "Releasing saved glue buffer (version 1)\n");
2325  delete static_cast<compat::inode_tracker::InodeTracker *>(
2326  saved_states[i]->state);
2327  break;
2330  fd_progress, "Releasing saved glue buffer (version 2)\n");
2331  delete static_cast<compat::inode_tracker_v2::InodeTracker *>(
2332  saved_states[i]->state);
2333  break;
2336  fd_progress, "Releasing saved glue buffer (version 3)\n");
2337  delete static_cast<compat::inode_tracker_v3::InodeTracker *>(
2338  saved_states[i]->state);
2339  break;
2341  SendMsg2Socket(fd_progress, "Releasing saved glue buffer\n");
2342  delete static_cast<glue::InodeTracker *>(saved_states[i]->state);
2343  break;
2345  SendMsg2Socket(fd_progress, "Releasing saved negative entry cache\n");
2346  delete static_cast<glue::NentryTracker *>(saved_states[i]->state);
2347  break;
2349  SendMsg2Socket(fd_progress, "Releasing saved page cache entry cache\n");
2350  delete static_cast<glue::PageCacheTracker *>(saved_states[i]->state);
2351  break;
2353  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 1)\n");
2354  delete static_cast<compat::chunk_tables::ChunkTables *>(
2355  saved_states[i]->state);
2356  break;
2358  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 2)\n");
2359  delete static_cast<compat::chunk_tables_v2::ChunkTables *>(
2360  saved_states[i]->state);
2361  break;
2363  SendMsg2Socket(fd_progress, "Releasing chunk tables (version 3)\n");
2364  delete static_cast<compat::chunk_tables_v3::ChunkTables *>(
2365  saved_states[i]->state);
2366  break;
2368  SendMsg2Socket(fd_progress, "Releasing chunk tables\n");
2369  delete static_cast<ChunkTables *>(saved_states[i]->state);
2370  break;
2372  SendMsg2Socket(fd_progress, "Releasing saved inode generation info\n");
2373  delete static_cast<cvmfs::InodeGenerationInfo *>(
2374  saved_states[i]->state);
2375  break;
2378  fd_progress, saved_states[i]->state);
2379  break;
2381  SendMsg2Socket(fd_progress, "Releasing open files counter\n");
2382  delete static_cast<uint32_t *>(saved_states[i]->state);
2383  break;
2384  default:
2385  break;
2386  }
2387  }
2388 }
2389 
2390 
2391 static void __attribute__((constructor)) LibraryMain() {
2392  g_cvmfs_exports = new loader::CvmfsExports();
2393  g_cvmfs_exports->so_version = PACKAGE_VERSION;
2394  g_cvmfs_exports->fnAltProcessFlavor = AltProcessFlavor;
2395  g_cvmfs_exports->fnInit = Init;
2396  g_cvmfs_exports->fnSpawn = Spawn;
2397  g_cvmfs_exports->fnFini = Fini;
2398  g_cvmfs_exports->fnGetErrorMsg = GetErrorMsg;
2399  g_cvmfs_exports->fnMaintenanceMode = MaintenanceMode;
2400  g_cvmfs_exports->fnSaveState = SaveState;
2401  g_cvmfs_exports->fnRestoreState = RestoreState;
2402  g_cvmfs_exports->fnFreeSavedState = FreeSavedState;
2403  cvmfs::SetCvmfsOperations(&g_cvmfs_exports->cvmfs_operations);
2404 }
2405 
2406 
2407 static void __attribute__((destructor)) LibraryExit() {
2408  delete g_cvmfs_exports;
2409  g_cvmfs_exports = NULL;
2410 }
VfsPutRaii GetVfsPutRaii()
Definition: glue_buffer.h:572
std::string repository_name
Definition: loader.h:177
OptionsManager * options_mgr()
Definition: mountpoint.h:224
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
uint32_t version
Definition: loader.h:172
bool IsCaching()
Definition: fuse_remount.h:60
void Dec(class Counter *counter)
Definition: statistics.h:49
NfsMaps * nfs_maps()
Definition: mountpoint.h:221
bool IsExternalFile() const
std::string mount_point
Definition: loader.h:178
bool IsInDrainoutMode()
Definition: fuse_remount.h:64
void UnregisterQuotaListener()
Definition: cvmfs.cc:1641
static const time_t kIndefiniteDeadline
Definition: mountpoint.h:416
virtual std::string GetValue()
Definition: cvmfs.cc:1693
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:569
std::string ListKeysPosix(const std::string &merge_with) const
Definition: xattr.cc:137
FileSystem * file_system()
Definition: mountpoint.h:443
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:204
time_t catalogs_valid_until_
Definition: cvmfs.cc:1686
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:1103
static double GetKcacheTimeout()
Definition: cvmfs.cc:166
void SpawnCleaner(unsigned interval_s)
Definition: glue_buffer.cc:167
void EnterMaintenanceMode()
void set_inode(const inode_t inode)
InodeGenerationInfo inode_generation_info_
Definition: cvmfs.cc:127
loader::Failures boot_status()
Definition: mountpoint.h:75
static void FreeSavedState(const int fd_progress, const loader::StateList &saved_states)
Definition: cvmfs.cc:2313
bool IsDirectory() const
static void cvmfs_statfs(fuse_req_t req, fuse_ino_t ino)
Definition: cvmfs.cc:1317
void set_boot_status(loader::Failures code)
Definition: mountpoint.h:82
static void DoTraceInode(const int event, fuse_ino_t ino, const std::string &msg)
Definition: cvmfs.cc:346
cvmfs::Fetcher * fetcher()
Definition: mountpoint.h:439
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:796
bool IsChunkedFile() const
FuseRemounter * fuse_remounter_
Definition: cvmfs.cc:126
static Watchdog * Create(const std::string &crash_dump_path)
Definition: monitor.cc:60
vector< string > SplitString(const string &str, const char delim, const unsigned max_chunks)
Definition: string.cc:288
uid_t talk_socket_uid()
Definition: mountpoint.h:462
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:124
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:154
#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:2024
uint64_t size() const
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:248
double kcache_timeout_sec()
Definition: mountpoint.h:452
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:468
std::string PrintInodeGeneration()
Definition: cvmfs.cc:189
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:217
std::string fqrn() const
Definition: mountpoint.h:441
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:1250
BaseMagicXattr * GetLocked(const std::string &name, PathString path, catalog::DirectoryEntry *d)
Definition: magic_xattr.cc:108
Watchdog * watchdog_
Definition: cvmfs.cc:125
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:451
NotificationClient * notification_client_
Definition: cvmfs.cc:124
void * SaveState(const int fd_progress)
Definition: cache.cc:221
DirectoryHandles * directory_handles_
Definition: cvmfs.cc:155
StateId state_id
Definition: loader.h:122
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:2049
void Spawn()
Definition: monitor.cc:387
inode_t inode() const
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:691
bool ListingStat(const PathString &path, StatEntryList *listing)
assert((mem||(size==0))&&"Out Of Memory")
void ** fuse_channel_or_session
Definition: loader.h:195
MountPoint * mount_point_
Definition: cvmfs.cc:122
MagicXattrManager * magic_xattr_mgr()
Definition: mountpoint.h:444
std::string program_name
Definition: loader.h:180
Log2Histogram * hist_fs_read()
Definition: mountpoint.h:208
bool IsDirectIo() const
bool SendFd2Socket(int socket_fd, int passing_fd)
Definition: posix.cc:700
bool LookupPath(const PathString &path, const LookupOptions options, DirectoryEntry *entry)
std::string GetParentPath(const std::string &path)
Definition: posix.cc:130
static bool RestoreState(const int fd_progress, const loader::StateList &saved_states)
Definition: cvmfs.cc:2146
virtual uint64_t GetSize()=0
perf::Counter * n_fs_read()
Definition: mountpoint.h:216
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:453
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:503
static bool GetDirentForPath(const PathString &path, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:279
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:112
bool has_membership_req()
Definition: mountpoint.h:445
virtual bool PrepareValueFenced()
Definition: cvmfs.cc:1688
virtual std::string GetValue()
Definition: cvmfs.cc:1704
struct cvmcache_object_info __attribute__
Definition: atomic.h:24
void RemapCatalogFd(int from, int to)
Definition: mountpoint.cc:1069
bool Pin(const string &path)
Definition: cvmfs.cc:1510
static void cvmfs_destroy(void *unused __attribute__((unused)))
Definition: cvmfs.cc:1607
static TalkManager * Create(const std::string &socket_path, MountPoint *mount_point, FuseRemounter *remounter)
Definition: talk.cc:78
unsigned max_open_files_
Definition: cvmfs.cc:159
static bool HasFuseNotifyInval()
Definition: fuse_evict.cc:53
perf::Counter * n_fs_open()
Definition: mountpoint.h:215
static void cvmfs_init(void *userdata, struct fuse_conn_info *conn)
Definition: cvmfs.cc:1582
TalkManager * talk_mgr_
Definition: cvmfs.cc:123
virtual uint64_t GetCapacity()=0
std::string membership_req()
Definition: mountpoint.h:454
void Throttle()
Definition: backoff.cc:50
std::string GetListString(catalog::DirectoryEntry *dirent)
Definition: magic_xattr.cc:69
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:157
void Unlock()
Definition: file_chunk.h:106
static void InitOptionsMgr(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:1781
Fence * fence()
Definition: fuse_remount.h:67
OpenDirectives Open(uint64_t inode, const shash::Any &hash)
Definition: glue_buffer.cc:313
pid_t pid_
Definition: cvmfs.cc:147
PathString path
Definition: file_chunk.h:70
static bool GetDirentForInode(const fuse_ino_t ino, catalog::DirectoryEntry *dirent)
Definition: cvmfs.cc:214
glue::PageCacheTracker * page_cache_tracker()
Definition: mountpoint.h:456
bool IsLink() const
void SetBit(unsigned int bit, T *field)
Definition: algorithm.h:30
BigVector< FileChunk > FileChunkList
Definition: file_chunk.h:51
virtual void Spawn()=0
bool HasXattrs() const
virtual std::string GetValue()
Definition: cvmfs.cc:1722
static void TraceInode(const int event, fuse_ino_t ino, const std::string &msg)
Definition: cvmfs.cc:361
bool Get(const std::string &key, std::string *value) const
Definition: xattr.cc:108
catalog::ClientCatalogManager * catalog_mgr()
Definition: mountpoint.h:430
void Set(const int64_t val)
Definition: statistics.h:33
Log2Histogram * hist_fs_forget_multi()
Definition: mountpoint.h:201
static void cvmfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Definition: cvmfs.cc:1450
bool IsRegular() const
void ClearBit(unsigned int bit, T *field)
Definition: algorithm.h:35
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:209
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:592
ListenerHandle * RegisterWatchdogListener(QuotaManager *quota_manager, const string &repository_name)
const loader::LoaderExports * loader_exports_
Definition: cvmfs.cc:145
EVisibility visibility()
Definition: magic_xattr.h:154
virtual inode_t GetGeneration()=0
std::string config_files
Definition: loader.h:179
perf::Counter * no_open_dirs()
Definition: mountpoint.h:222
catalog::InodeAnnotation * inode_annotation()
Definition: mountpoint.h:447
Log2Histogram * hist_fs_releasedir()
Definition: mountpoint.h:205
quota::ListenerHandle * watchdog_listener_
Definition: cvmfs.cc:148
void SetSize(const size_t new_size)
Definition: bigvector.h:95
std::string boot_error()
Definition: mountpoint.h:76
off_t offset() const
Definition: file_chunk.h:42
lru::PathCache * path_cache()
Definition: mountpoint.h:457
glue::NentryTracker * nentry_tracker()
Definition: mountpoint.h:455
virtual std::string GetValue()
Definition: cvmfs.cc:1712
static void cvmfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:886
zlib::Algorithms compression_algorithm() const
unsigned GetMaxOpenFiles()
Definition: monitor.cc:643
bool IsNfsSource()
Definition: mountpoint.h:189
CacheManager * cache_mgr()
Definition: mountpoint.h:195
const signature::SignatureManager * signature_mgr() const
Definition: repository.h:121
file_watcher::FileWatcher * resolv_conf_watcher()
Definition: mountpoint.h:436
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:1718
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:146
static void ShutdownMountpoint()
Definition: cvmfs.cc:1978
unsigned FindChunkIdx(const uint64_t offset)
Definition: file_chunk.cc:23
bool SendFuseFd(const std::string &socket_path)
Definition: cvmfs.cc:1652
perf::Counter * no_open_files()
Definition: mountpoint.h:223
AuthzSessionManager * authz_session_mgr()
Definition: mountpoint.h:428
LinkString symlink() const
void Insert(const Key &key, const Value &value)
Definition: smallhash.h:89
IoErrorInfo * io_error_info()
Definition: mountpoint.h:219
download::DownloadManager * download_mgr()
Definition: mountpoint.h:432
static void SetCvmfsOperations(struct fuse_lowlevel_ops *cvmfs_operations)
Definition: cvmfs.cc:1615
bool simple_options_parsing
Definition: loader.h:188
perf::Counter * n_fs_forget()
Definition: mountpoint.h:212
Log2Histogram * hist_fs_readlink()
Definition: mountpoint.h:203
static int Init(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:1801
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:78
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:608
size_t capacity() const
Definition: bigvector.h:101
static void ReplyNegative(const catalog::DirectoryEntry &dirent, fuse_req_t req)
Definition: cvmfs.cc:556
void Inc(class Counter *counter)
Definition: statistics.h:50
virtual int Close(int fd)=0
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:845
ChunkTables * chunk_tables()
Definition: mountpoint.h:431
pthread_mutex_t lock_directory_handles_
Definition: cvmfs.cc:156
static void cvmfs_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
Definition: cvmfs.cc:666
OptionsManager * options_mgr_
Definition: cvmfs.cc:146
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:211
Log2Histogram * hist_fs_readdir()
Definition: mountpoint.h:206
cvmfs::Fetcher * external_fetcher()
Definition: mountpoint.h:442
bool enforce_acls()
Definition: mountpoint.h:446
bool IsInMaintenanceMode()
Definition: fuse_remount.h:65
static bool CheckVoms(const fuse_ctx &fctx)
Definition: cvmfs.cc:200
static void FillOpenFlags(const glue::PageCacheTracker::OpenDirectives od, struct fuse_file_info *fi)
Definition: cvmfs.cc:869
void FreeState(const int fd_progress, void *state)
Definition: cache.cc:100
static FileSystem * Create(const FileSystemInfo &fs_info)
Definition: mountpoint.cc:164
bool IsEmpty() const
Definition: bigvector.h:67
bool Contains(const Key &key) const
Definition: smallhash.h:82
Log2Histogram * hist_fs_open()
Definition: mountpoint.h:207
void Add(const uint64_t inode_parent, const char *name, uint64_t timeout_s)
Definition: glue_buffer.h:700
bool FindPath(const uint64_t inode, PathString *path)
Definition: glue_buffer.h:574
std::string ToString() const
Definition: shortstring.h:114
QuotaManager * quota_mgr()
Definition: cache.h:198
static string GetErrorMsg()
Definition: cvmfs.cc:1966
int ConnectSocket(const std::string &path)
Definition: posix.cc:459
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:240
Log2Histogram * hist_fs_lookup()
Definition: mountpoint.h:199
bool TestBit(unsigned int bit, const T field)
Definition: algorithm.h:40
void Close(uint64_t inode)
Definition: glue_buffer.cc:390
string * g_boot_error
Definition: cvmfs.cc:1676
bool ListFileChunks(const PathString &path, const shash::Algorithms interpret_hashes_as, FileChunkList *chunks)
static void Fini()
Definition: cvmfs.cc:2007
perf::Counter * n_fs_lookup()
Definition: mountpoint.h:213
static void Spawn()
Definition: cvmfs.cc:1922
static bool UseWatchdog()
Definition: cvmfs.cc:179
void Migrate(InodeTracker *old_tracker, glue::InodeTracker *new_tracker)
Definition: compat.cc:83
OpenDirectives OpenDirect()
Definition: glue_buffer.cc:379
ShortString< kDefaultMaxPath, 0 > PathString
Definition: shortstring.h:190
uint32_t size() const
Definition: smallhash.h:280
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
void UnregisterListener(ListenerHandle *handle)
Definition: mutex.h:42
bool Evict(const string &path)
Definition: cvmfs.cc:1497
std::vector< SavedState * > StateList
Definition: loader.h:125
FileSystem * file_system_
Definition: cvmfs.cc:121
EvictRaii GetEvictRaii()
Definition: glue_buffer.h:865
virtual bool PrepareValueFenced()
Definition: magic_xattr.h:52
void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode)
Definition: cvmfs.cc:173
bool Erase(const Key &key)
Definition: smallhash.h:95
bool LookupXattrs(const PathString &path, XattrList *xattrs)
perf::Counter * n_fs_lookup_negative()
Definition: mountpoint.h:214
virtual uint64_t GetInode(const PathString &path)=0
Log2Histogram * hist_fs_forget()
Definition: mountpoint.h:200
const int kNumReservedFd
Definition: cvmfs.cc:163
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:829
void VfsGet(const uint64_t inode, const PathString &path)
Definition: glue_buffer.h:568
unsigned GetLength() const
Definition: shortstring.h:104
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:199
bool Insert(const fuse_ino_t &inode, const PathString &path)
Definition: lru_md.h:84
BackoffThrottle * backoff_throttle()
Definition: mountpoint.h:429
Log2Histogram * hist_fs_getattr()
Definition: mountpoint.h:202
gid_t talk_socket_gid()
Definition: mountpoint.h:463
const char * c_str() const
Definition: shortstring.h:118
static bool GetPathForInode(const fuse_ino_t ino, PathString *path)
Definition: cvmfs.cc:321
static const unsigned int kBitDirectIo
Definition: glue_buffer.h:791
const char * GetChars() const
Definition: shortstring.h:96
static void RegisterMagicXattrs()
Definition: cvmfs.cc:1733
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:450
bool Insert(const shash::Md5 &hash, const catalog::DirectoryEntry &dirent)
Definition: lru_md.h:121
perf::Counter * n_fs_stat()
Definition: mountpoint.h:218
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:373
#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:2035
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:1746
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:1368
Tracer * tracer()
Definition: mountpoint.h:465
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:639
size_t size() const
Definition: bigvector.h:100
download::DownloadManager * external_download_mgr()
Definition: mountpoint.h:433
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:149
static MountPoint * Create(const std::string &fqrn, FileSystem *file_system, OptionsManager *options_mgr=NULL)
Definition: mountpoint.cc:1155
void Spawn()
Definition: talk.cc:843
OptionsManager * options_mgr
Definition: mountpoint.h:137