GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/mountpoint.cc Lines: 690 947 72.9 %
Date: 2019-02-03 02:48:13 Branches: 450 827 54.4 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
#include "cvmfs_config.h"
5
#include "mountpoint.h"
6
7
#include <errno.h>
8
#include <fcntl.h>
9
#ifndef CVMFS_LIBCVMFS
10
#include <fuse/fuse_lowlevel.h>
11
#endif
12
#include <inttypes.h>
13
#include <stdint.h>
14
#include <unistd.h>
15
16
#include <algorithm>
17
#include <cassert>
18
#include <climits>
19
#include <cstring>
20
#include <vector>
21
22
#ifndef CVMFS_LIBCVMFS
23
#ifdef FUSE_CAP_EXPORT_SUPPORT
24
#define CVMFS_NFS_SUPPORT
25
#else
26
#warning "No NFS support, Fuse too old"
27
#endif
28
#endif
29
30
#include "authz/authz_curl.h"
31
#include "authz/authz_fetch.h"
32
#include "authz/authz_session.h"
33
#include "backoff.h"
34
#include "cache.h"
35
#include "cache_extern.h"
36
#include "cache_posix.h"
37
#include "cache_ram.h"
38
#include "cache_tiered.h"
39
#include "catalog.h"
40
#include "catalog_mgr_client.h"
41
#include "clientctx.h"
42
#include "download.h"
43
#include "duplex_sqlite3.h"
44
#include "fetch.h"
45
#include "file_chunk.h"
46
#include "globals.h"
47
#include "glue_buffer.h"
48
#include "google/protobuf/stubs/common.h"
49
#include "history.h"
50
#include "history_sqlite.h"
51
#include "logging.h"
52
#include "lru_md.h"
53
#include "manifest.h"
54
#include "manifest_fetch.h"
55
#include "nfs_maps.h"
56
#ifdef CVMFS_NFS_SUPPORT
57
#include "nfs_maps_leveldb.h"
58
#include "nfs_maps_sqlite.h"
59
#endif
60
#include "options.h"
61
#include "platform.h"
62
#include "quota_posix.h"
63
#include "resolv_conf_event_handler.h"
64
#include "signature.h"
65
#include "sqlitemem.h"
66
#include "sqlitevfs.h"
67
#include "statistics.h"
68
#include "tracer.h"
69
#include "util/pointer.h"
70
#include "util/posix.h"
71
#include "util/string.h"
72
#include "util_concurrency.h"
73
#include "uuid.h"
74
#include "wpad.h"
75
76
using namespace std;  // NOLINT
77
78
79
bool FileSystem::g_alive = false;
80
const char *FileSystem::kDefaultCacheBase = "/var/lib/cvmfs";
81
const char *FileSystem::kDefaultCacheMgrInstance = "default";
82
83
84
/**
85
 * A cache instance name is part of a bash parameter and can only contain
86
 * certain characters.
87
 */
88
39
bool FileSystem::CheckInstanceName(const std::string &instance) {
89
39
  if (instance.length() > 24)
90
2
    return false;
91
37
  sanitizer::CacheInstanceSanitizer instance_sanitizer;
92
37
  if (!instance_sanitizer.IsValid(instance)) {
93
    boot_error_ = "invalid instance name (" + instance + "), " +
94
4
                  "only characters a-z, A-Z, 0-9, _ are allowed";
95
4
    boot_status_ = loader::kFailCacheDir;
96
4
    return false;
97
  }
98
33
  return true;
99
}
100
101
102
/**
103
 * Not all possible combinations of cache flags / modes are valid.
104
 */
105
148
bool FileSystem::CheckPosixCacheSettings(
106
  const FileSystem::PosixCacheSettings &settings)
107
{
108

148
  if (settings.is_alien && settings.is_shared) {
109
    boot_error_ = "Failure: shared local disk cache and alien cache mutually "
110
10
                  "exclusive. Please turn off shared local disk cache.";
111
10
    boot_status_ = loader::kFailOptions;
112
10
    return false;
113
  }
114

138
  if (settings.is_alien && settings.is_managed) {
115
    boot_error_ = "Failure: quota management and alien cache mutually "
116
7
                  "exclusive. Please turn off quota limit.";
117
7
    boot_status_ = loader::kFailOptions;
118
7
    return false;
119
  }
120
121
131
  if (type_ == kFsLibrary) {
122

28
    if (settings.is_shared || settings.is_managed) {
123
      boot_error_ = "Failure: libcvmfs supports only unmanaged exclusive cache "
124
4
                    "or alien cache.";
125
4
      boot_status_ = loader::kFailOptions;
126
4
      return false;
127
    }
128
  }
129
130

127
  if (settings.cache_base_defined && settings.cache_dir_defined) {
131
    boot_error_ =
132
4
      "'CVMFS_CACHE_BASE' and 'CVMFS_CACHE_DIR' are mutually exclusive";
133
4
    boot_status_ = loader::kFailOptions;
134
4
    return false;
135
  }
136
137
123
  return true;
138
}
139
140
141
/**
142
 * Creation of state and manager classes.  The destructor should mirror this
143
 * method.
144
 */
145
137
FileSystem *FileSystem::Create(const FileSystem::FileSystemInfo &fs_info) {
146
  UniquePtr<FileSystem>
147
137
    file_system(new FileSystem(fs_info));
148
149
137
  file_system->SetupLogging();
150
  LogCvmfs(kLogCvmfs, kLogDebug, "Options:\n%s",
151
137
           file_system->options_mgr()->Dump().c_str());
152
153
137
  file_system->CreateStatistics();
154
137
  file_system->SetupSqlite();
155
137
  if (!file_system->DetermineNfsMode())
156
    return file_system.Release();
157
137
  if (!file_system->SetupWorkspace())
158
6
    return file_system.Release();
159
160
  // Redirect SQlite temp directory to workspace (global variable)
161
131
  unsigned length_tempdir = file_system->workspace_.length() + 1;
162
131
  sqlite3_temp_directory = static_cast<char *>(sqlite3_malloc(length_tempdir));
163
  snprintf(sqlite3_temp_directory,
164
           length_tempdir,
165
           "%s",
166
131
           file_system->workspace_.c_str());
167
168
131
  if (!file_system->TriageCacheMgr())
169
24
    return file_system.Release();
170
107
  file_system->SetupUuid();
171
107
  if (!file_system->SetupNfsMaps())
172
    return file_system.Release();
173
  bool retval = sqlite::RegisterVfsRdOnly(
174
    file_system->cache_mgr_,
175
    file_system->statistics_,
176
107
    sqlite::kVfsOptDefault);
177
107
  assert(retval);
178
107
  file_system->has_custom_sqlitevfs_ = true;
179
180
107
  ClientCtx::GetInstance();
181
182
107
  file_system->boot_status_ = loader::kFailOk;
183
107
  return file_system.Release();
184
}
185
186
187
137
void FileSystem::CreateStatistics() {
188
137
  statistics_ = new perf::Statistics();
189
190
  // Register the ShortString's static counters
191
137
  statistics_->Register("pathstring.n_instances", "Number of instances");
192
137
  statistics_->Register("pathstring.n_overflows", "Number of overflows");
193
137
  statistics_->Register("namestring.n_instances", "Number of instances");
194
137
  statistics_->Register("namestring.n_overflows", "Number of overflows");
195
137
  statistics_->Register("linkstring.n_instances", "Number of instances");
196
137
  statistics_->Register("linkstring.n_overflows", "Number of overflows");
197
198
  // Callback counters
199
  n_fs_open_ = statistics_->Register("cvmfs.n_fs_open",
200
137
                                     "Overall number of file open operations");
201
  n_fs_dir_open_ = statistics_->Register("cvmfs.n_fs_dir_open",
202
137
                   "Overall number of directory open operations");
203
  n_fs_lookup_ = statistics_->Register("cvmfs.n_fs_lookup",
204
137
                                       "Number of lookups");
205
  n_fs_lookup_negative_ = statistics_->Register("cvmfs.n_fs_lookup_negative",
206
137
                                                "Number of negative lookups");
207
137
  n_fs_stat_ = statistics_->Register("cvmfs.n_fs_stat", "Number of stats");
208
137
  n_fs_read_ = statistics_->Register("cvmfs.n_fs_read", "Number of files read");
209
  n_fs_readlink_ = statistics_->Register("cvmfs.n_fs_readlink",
210
137
                                         "Number of links read");
211
  n_fs_forget_ = statistics_->Register("cvmfs.n_fs_forget",
212
137
                                       "Number of inode forgets");
213
  n_io_error_ = statistics_->Register("cvmfs.n_io_error",
214
137
                                      "Number of I/O errors");
215
  no_open_files_ = statistics_->Register("cvmfs.no_open_files",
216
137
                                         "Number of currently opened files");
217
  no_open_dirs_ = statistics_->Register("cvmfs.no_open_dirs",
218
137
                  "Number of currently opened directories");
219
137
}
220
221
222
/**
223
 * Figure out mode of operation and cache directory.  Checking options for
224
 * sanity is in a separate method.
225
 */
226
116
FileSystem::PosixCacheSettings FileSystem::DeterminePosixCacheSettings(
227
  const string &instance
228
) {
229
116
  string optarg;
230
116
  PosixCacheSettings settings;
231
232




116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_SHARED", instance),
233
                             &optarg)
234
      && options_mgr_->IsOn(optarg))
235
  {
236
8
    settings.is_shared = true;
237
  }
238




116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_SERVER_MODE", instance),
239
                             &optarg)
240
      && options_mgr_->IsOn(optarg))
241
  {
242
    settings.avoid_rename = true;
243
  }
244
245
116
  if (type_ == kFsFuse)
246
89
    settings.quota_limit = kDefaultQuotaLimit;
247
116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_QUOTA_LIMIT", instance),
248
                             &optarg))
249
  {
250
38
    settings.quota_limit = String2Int64(optarg) * 1024 * 1024;
251
  }
252
116
  if (settings.quota_limit > 0)
253
60
    settings.is_managed = true;
254
255
116
  settings.cache_path = kDefaultCacheBase;
256
116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_BASE", instance),
257
                             &optarg))
258
  {
259
92
    settings.cache_path = MakeCanonicalPath(optarg);
260
92
    settings.cache_base_defined = true;
261
  }
262
116
  if (settings.is_shared) {
263
8
    settings.cache_path += "/shared";
264
  } else {
265
108
    settings.cache_path += "/" + name_;
266
  }
267
268
  // CheckCacheMode makes sure that CVMFS_CACHE_DIR and CVMFS_CACHE_BASE are
269
  // not set at the same time.
270
116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_DIR", instance),
271
                             &optarg))
272
  {
273
24
    settings.cache_dir_defined = true;
274
24
    settings.cache_path = optarg;
275
  }
276
116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_ALIEN", instance),
277
                             &optarg))
278
  {
279
22
    settings.is_alien = true;
280
22
    settings.cache_path = optarg;
281
  }
282
  // We already changed the cwd to the workspace
283
  // Which is only done if using FUSE
284

116
  if ((type_ == kFsFuse) && (settings.cache_path == workspace_fullpath_)) {
285
65
    settings.cache_path = ".";
286
  }
287
288
  // The cache workspace usually is the cache directory, unless explicitly
289
  // set otherwise
290
116
  settings.workspace = settings.cache_path;
291






116
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_WORKSPACE", instance),
292
                             &optarg) ||
293
      options_mgr_->GetValue("CVMFS_WORKSPACE", &optarg))
294
  {
295
    // Used for the shared quota manager
296
14
    settings.workspace = optarg;
297
  }
298
299
  return settings;
300
}
301
302
303
137
bool FileSystem::DetermineNfsMode() {
304
137
  string optarg;
305
306



137
  if (options_mgr_->GetValue("CVMFS_NFS_SOURCE", &optarg) &&
307
      options_mgr_->IsOn(optarg))
308
  {
309
12
    nfs_mode_ |= kNfsMaps;
310
12
    if (options_mgr_->GetValue("CVMFS_NFS_SHARED", &optarg)) {
311
9
      nfs_mode_ |= kNfsMapsHa;
312
9
      nfs_maps_dir_ = optarg;
313
    }
314
  }
315
316

137
  if ((type_ == kFsLibrary) && (nfs_mode_ != kNfsNone)) {
317
    boot_error_ = "Failure: libcvmfs does not support NFS export.";
318
    boot_status_ = loader::kFailOptions;
319
    return false;
320
  }
321
137
  return true;
322
}
323
324
325
137
FileSystem::FileSystem(const FileSystem::FileSystemInfo &fs_info)
326
  : name_(fs_info.name)
327
  , exe_path_(fs_info.exe_path)
328
  , type_(fs_info.type)
329
  , options_mgr_(fs_info.options_mgr)
330
  , wait_workspace_(fs_info.wait_workspace)
331
  , foreground_(fs_info.foreground)
332
  , n_fs_open_(NULL)
333
  , n_fs_dir_open_(NULL)
334
  , n_fs_lookup_(NULL)
335
  , n_fs_lookup_negative_(NULL)
336
  , n_fs_stat_(NULL)
337
  , n_fs_read_(NULL)
338
  , n_fs_readlink_(NULL)
339
  , n_fs_forget_(NULL)
340
  , n_io_error_(NULL)
341
  , no_open_files_(NULL)
342
  , no_open_dirs_(NULL)
343
  , statistics_(NULL)
344
  , fd_workspace_lock_(-1)
345
  , found_previous_crash_(false)
346
  , nfs_mode_(kNfsNone)
347
  , cache_mgr_(NULL)
348
  , uuid_cache_(NULL)
349
  , nfs_maps_(NULL)
350
137
  , has_custom_sqlitevfs_(false)
351
{
352
137
  assert(!g_alive);
353
137
  g_alive = true;
354
137
  g_uid = geteuid();
355
137
  g_gid = getegid();
356
357
137
  string optarg;
358






137
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_SERVER_MODE",
359
                                         kDefaultCacheMgrInstance),
360
                             &optarg)
361
      && options_mgr_->IsOn(optarg))
362
  {
363
    g_raw_symlinks = true;
364
  }
365
}
366
367
368
134
FileSystem::~FileSystem() {
369
134
  ClientCtx::CleanupInstance();
370
371
134
  if (has_custom_sqlitevfs_)
372
104
    sqlite::UnregisterVfsRdOnly();
373
374
134
  delete uuid_cache_;
375
134
  delete nfs_maps_;
376
134
  delete cache_mgr_;
377
378
134
  if (sqlite3_temp_directory) {
379
128
    sqlite3_free(sqlite3_temp_directory);
380
128
    sqlite3_temp_directory = NULL;
381
  }
382
383
134
  if (!path_crash_guard_.empty())
384
128
    unlink(path_crash_guard_.c_str());
385
134
  if (!path_workspace_lock_.empty())
386
130
    unlink(path_workspace_lock_.c_str());
387
134
  if (fd_workspace_lock_ >= 0)
388
128
    UnlockFile(fd_workspace_lock_);
389
390
134
  sqlite3_shutdown();
391
134
  SqliteMemoryManager::CleanupInstance();
392
393
134
  delete statistics_;
394
395
134
  SetLogSyslogPrefix("");
396
134
  SetLogMicroSyslog("");
397
134
  SetLogDebugFile("");
398
134
  google::protobuf::ShutdownProtobufLibrary();
399
134
  g_alive = false;
400
134
}
401
402
403
133
bool FileSystem::LockWorkspace() {
404
133
  path_workspace_lock_ = workspace_ + "/lock." + name_;
405
133
  fd_workspace_lock_ = TryLockFile(path_workspace_lock_);
406
133
  if (fd_workspace_lock_ >= 0)
407
131
    return true;
408
409
2
  if (fd_workspace_lock_ == -1) {
410
    boot_error_ = "could not acquire workspace lock (" +
411
                 StringifyInt(errno) + ")";
412
    boot_status_ = loader::kFailCacheDir;
413
    return false;
414
  }
415
416
2
  assert(fd_workspace_lock_ == -2);
417
418
2
  if (!wait_workspace_) {
419
2
    boot_status_ = loader::kFailLockWorkspace;
420
2
    return false;
421
  }
422
423
  fd_workspace_lock_ = LockFile(path_workspace_lock_);
424
  if (fd_workspace_lock_ < 0) {
425
    boot_error_ = "could not acquire workspace lock (" +
426
                   StringifyInt(errno) + ")";
427
    boot_status_ = loader::kFailCacheDir;
428
    return false;
429
  }
430
  return true;
431
}
432
433
434
136
void FileSystem::LogSqliteError(
435
  void *user_data __attribute__((unused)),
436
  int sqlite_extended_error,
437
  const char *message)
438
{
439
136
  int log_dest = kLogDebug;
440
136
  int sqlite_error = sqlite_extended_error & 0xFF;
441
136
  switch (sqlite_error) {
442
    case SQLITE_INTERNAL:
443
    case SQLITE_PERM:
444
    case SQLITE_NOMEM:
445
    case SQLITE_IOERR:
446
    case SQLITE_CORRUPT:
447
    case SQLITE_FULL:
448
    case SQLITE_CANTOPEN:
449
    case SQLITE_MISUSE:
450
    case SQLITE_FORMAT:
451
    case SQLITE_NOTADB:
452
6
      log_dest |= kLogSyslogErr;
453
      break;
454
    case SQLITE_WARNING:
455
    case SQLITE_NOTICE:
456
    default:
457
      break;
458
  }
459
  LogCvmfs(kLogCvmfs, log_dest, "SQlite3: %s (%d)",
460
136
           message, sqlite_extended_error);
461
136
}
462
463
464
/**
465
 * Creates the cache parameter for a specific instance of the cache.  Injects
466
 * the instance name such that CVMFS_CACHE_FOO_BAR becomes
467
 * CVMFS_CACHE_<INSTANCE>_FOO_BAR
468
 */
469
1173
string FileSystem::MkCacheParm(
470
  const string &generic_parameter,
471
  const string &instance)
472
{
473
1173
  assert(HasPrefix(generic_parameter, "CVMFS_CACHE_", false));
474
475
1173
  if (instance == kDefaultCacheMgrInstance) {
476
    // Compatibility parameter names
477

853
    if ((generic_parameter == "CVMFS_CACHE_SHARED") &&
478
        !options_mgr_->IsDefined(generic_parameter))
479
    {
480
102
      return "CVMFS_SHARED_CACHE";
481
    }
482

751
    if ((generic_parameter == "CVMFS_CACHE_ALIEN") &&
483
        !options_mgr_->IsDefined(generic_parameter))
484
    {
485
102
      return "CVMFS_ALIEN_CACHE";
486
    }
487

649
    if ((generic_parameter == "CVMFS_CACHE_SERVER_MODE") &&
488
        !options_mgr_->IsDefined(generic_parameter))
489
    {
490
239
      return "CVMFS_SERVER_CACHE_MODE";
491
    }
492

410
    if ((generic_parameter == "CVMFS_CACHE_QUOTA_LIMIT") &&
493
        !options_mgr_->IsDefined(generic_parameter))
494
    {
495
102
      return "CVMFS_QUOTA_LIMIT";
496
    }
497
308
    return generic_parameter;
498
  }
499
500
320
  return "CVMFS_CACHE_" + instance + "_" + generic_parameter.substr(12);
501
}
502
503
504
void FileSystem::ResetErrorCounters() {
505
  n_io_error_->Set(0);
506
}
507
508
509
/**
510
 * Can be recursive for the tiered cache manager.
511
 */
512
179
CacheManager *FileSystem::SetupCacheMgr(const string &instance) {
513
179
  if (constructed_instances_.find(instance) != constructed_instances_.end()) {
514
2
    boot_error_ = "circular cache definition: " + instance;
515
2
    boot_status_ = loader::kFailCacheDir;
516
2
    return NULL;
517
  }
518
177
  constructed_instances_.insert(instance);
519
520
  LogCvmfs(kLogCvmfs, kLogDebug, "setting up cache manager instance %s",
521
177
           instance.c_str());
522
177
  string instance_type;
523
177
  if (instance == kDefaultCacheMgrInstance) {
524
102
    instance_type = "posix";
525
  } else {
526
    options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_TYPE", instance),
527
75
                           &instance_type);
528
  }
529
177
  if (instance_type == "posix") {
530
116
    return SetupPosixCacheMgr(instance);
531
61
  } else if (instance_type == "ram") {
532
31
    return SetupRamCacheMgr(instance);
533
30
  } else if (instance_type == "tiered") {
534
28
    return SetupTieredCacheMgr(instance);
535
2
  } else if (instance_type == "external") {
536
    return SetupExternalCacheMgr(instance);
537
  } else {
538
    boot_error_ = "invalid cache manager type for '" + instance +  "':" +
539
2
      instance_type;
540
2
    boot_status_ = loader::kFailCacheDir;
541
2
    return NULL;
542
  }
543
}
544
545
546
CacheManager *FileSystem::SetupExternalCacheMgr(const string &instance) {
547
  string optarg;
548
  unsigned nfiles = kDefaultNfiles;
549
  if (options_mgr_->GetValue("CVMFS_NFILES", &optarg))
550
    nfiles = String2Uint64(optarg);
551
  vector<string> cmd_line;
552
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_CMDLINE", instance),
553
      &optarg))
554
  {
555
    cmd_line = SplitString(optarg, ',');
556
  }
557
558
  if (!options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_LOCATOR", instance),
559
      &optarg))
560
  {
561
    boot_error_ = MkCacheParm("CVMFS_CACHE_LOCATOR", instance) + " missing";
562
    boot_status_ = loader::kFailCacheDir;
563
    return NULL;
564
  }
565
566
  UniquePtr<ExternalCacheManager::PluginHandle> plugin_handle(
567
    ExternalCacheManager::CreatePlugin(optarg, cmd_line));
568
  if (!plugin_handle->IsValid()) {
569
    boot_error_ = plugin_handle->error_msg();
570
    boot_status_ = loader::kFailCacheDir;
571
    return NULL;
572
  }
573
  ExternalCacheManager *cache_mgr = ExternalCacheManager::Create(
574
    plugin_handle->fd_connection(), nfiles, name_ + ":" + instance);
575
  if (cache_mgr == NULL) {
576
    boot_error_ = "failed to create external cache manager for " + instance;
577
    boot_status_ = loader::kFailCacheDir;
578
    return NULL;
579
  }
580
  cache_mgr->AcquireQuotaManager(ExternalQuotaManager::Create(cache_mgr));
581
  return cache_mgr;
582
}
583
584
585
116
CacheManager *FileSystem::SetupPosixCacheMgr(const string &instance) {
586
116
  PosixCacheSettings settings = DeterminePosixCacheSettings(instance);
587
116
  if (!CheckPosixCacheSettings(settings))
588
9
    return NULL;
589
590
  UniquePtr<PosixCacheManager> cache_mgr(PosixCacheManager::Create(
591
    settings.cache_path,
592
    settings.is_alien,
593
    settings.avoid_rename ? PosixCacheManager::kRenameLink
594
107
                          : PosixCacheManager::kRenameNormal));
595
107
  if (!cache_mgr.IsValid()) {
596
    boot_error_ = "Failed to setup posix cache '" + instance + "' in " +
597
                  settings.cache_path + ": " + strerror(errno);
598
    boot_status_ = loader::kFailCacheDir;
599
    return NULL;
600
  }
601
602
  // Sentinel file for future use
603
  // Might be a read-only cache
604
107
  const bool ignore_failure = settings.is_alien;
605
107
  CreateFile(settings.cache_path + "/.cvmfscache", 0600, ignore_failure);
606
607
107
  if (settings.is_managed) {
608
57
    if (!SetupPosixQuotaMgr(settings, cache_mgr))
609
2
      return NULL;
610
  }
611
105
  return cache_mgr.Release();
612
}
613
614
615
31
CacheManager *FileSystem::SetupRamCacheMgr(const string &instance) {
616
31
  string optarg;
617
31
  unsigned nfiles = kDefaultNfiles;
618
31
  if (options_mgr_->GetValue("CVMFS_NFILES", &optarg)) {
619
    nfiles = String2Uint64(optarg);
620
  }
621
  uint64_t sz_cache_bytes;
622
31
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_SIZE", instance),
623
                             &optarg))
624
  {
625
    if (HasSuffix(optarg, "%", false)) {
626
      sz_cache_bytes = platform_memsize() * String2Uint64(optarg)/100;
627
    } else {
628
      sz_cache_bytes = String2Uint64(optarg) * 1024 * 1024;
629
    }
630
  } else {
631
31
    sz_cache_bytes = platform_memsize() >> 5;  // ~3%
632
  }
633
31
  MemoryKvStore::MemoryAllocator alloc = MemoryKvStore::kMallocHeap;
634
31
  if (options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_MALLOC", instance),
635
                             &optarg))
636
  {
637
6
    if (optarg == "libc") {
638
3
      alloc = MemoryKvStore::kMallocLibc;
639
3
    } else if (optarg == "heap") {
640
      alloc = MemoryKvStore::kMallocHeap;
641
    } else {
642
      boot_error_ = "Failure: unknown malloc " +
643
3
                    MkCacheParm("CVMFS_CACHE_MALLOC", instance) + "=" + optarg;
644
3
      boot_status_ = loader::kFailOptions;
645
3
      return NULL;
646
    }
647
  }
648
  sz_cache_bytes = RoundUp8(std::max(static_cast<uint64_t>(200 * 1024 * 1024),
649
28
                                     sz_cache_bytes));
650
  RamCacheManager *cache_mgr = new RamCacheManager(
651
        sz_cache_bytes,
652
        nfiles,
653
        alloc,
654
28
        perf::StatisticsTemplate("cache." + instance, statistics_));
655
28
  if (cache_mgr == NULL) {
656
    boot_error_ = "failed to create ram cache manager for " + instance;
657
    boot_status_ = loader::kFailCacheDir;
658
    return NULL;
659
  }
660
28
  cache_mgr->AcquireQuotaManager(new NoopQuotaManager());
661
28
  return cache_mgr;
662
}
663
664
665
28
CacheManager *FileSystem::SetupTieredCacheMgr(const string &instance) {
666
28
  string optarg;
667
28
  if (!options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_UPPER", instance),
668
                              &optarg))
669
  {
670
2
    boot_error_ = MkCacheParm("CVMFS_CACHE_UPPER", instance) + " missing";
671
2
    boot_status_ = loader::kFailOptions;
672
2
    return NULL;
673
  }
674
26
  UniquePtr<CacheManager> upper(SetupCacheMgr(optarg));
675
26
  if (!upper.IsValid())
676
    return NULL;
677
678
26
  if (!options_mgr_->GetValue(MkCacheParm("CVMFS_CACHE_LOWER", instance),
679
                              &optarg))
680
  {
681
2
    boot_error_ = MkCacheParm("CVMFS_CACHE_LOWER", instance) + " missing";
682
2
    boot_status_ = loader::kFailOptions;
683
2
    return NULL;
684
  }
685
24
  UniquePtr<CacheManager> lower(SetupCacheMgr(optarg));
686
24
  if (!lower.IsValid())
687
2
    return NULL;
688
689
  CacheManager *tiered =
690
22
    TieredCacheManager::Create(upper.Release(), lower.Release());
691
22
  if (tiered == NULL) {
692
    boot_error_ = "Failed to setup tiered cache manager " + instance;
693
    boot_status_ = loader::kFailCacheDir;
694
    return NULL;
695
  }
696




22
  if (options_mgr_->GetValue(
697
        MkCacheParm("CVMFS_CACHE_LOWER_READONLY", instance), &optarg) &&
698
      options_mgr_->IsOn(optarg))
699
  {
700
    static_cast<TieredCacheManager*>(tiered)->SetLowerReadOnly();
701
  }
702
22
  return tiered;
703
}
704
705
706
131
bool FileSystem::SetupCrashGuard() {
707
131
  path_crash_guard_ = workspace_ + "/running." + name_;
708
  platform_stat64 info;
709
131
  int retval = platform_stat(path_crash_guard_.c_str(), &info);
710
131
  if (retval == 0) {
711
2
    found_previous_crash_ = true;
712
    LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogWarn,
713
2
             "looks like cvmfs has been crashed previously");
714
  }
715
131
  retval = open(path_crash_guard_.c_str(), O_RDONLY | O_CREAT, 0600);
716
131
  if (retval < 0) {
717
    boot_error_ = "could not open running sentinel (" +
718
                  StringifyInt(errno) + ")";
719
    boot_status_ = loader::kFailCacheDir;
720
    return false;
721
  }
722
131
  close(retval);
723
131
  return true;
724
}
725
726
727
131
bool FileSystem::SetupCwd() {
728
131
  if (type_ == kFsFuse) {
729
    // Try to jump to workspace / cache directory.  This tests, if it is
730
    // accessible and it brings speed later on.
731
104
    int retval = chdir(workspace_.c_str());
732
104
    if (retval != 0) {
733
      boot_error_ = "workspace " + workspace_ + " is unavailable";
734
      boot_status_ = loader::kFailCacheDir;
735
      return false;
736
    }
737
104
    workspace_ = ".";
738
104
    return true;
739
  }
740
741
  // Note: as of version 2.4 support for CVMFS_CWD_CACHE is dropped due to
742
  // disproportionate large complexity to configure correctly.  This affects
743
  // only libcvmfs, mostly the legacy part.
744
  // string optarg;
745
  // if (options_mgr_->GetValue("CVMFS_CWD_CACHE", &optarg) &&
746
  //    options_mgr_->IsOn(optarg))
747
  // {
748
  //  ...
749
  // }
750
27
  return true;
751
}
752
753
754
137
void FileSystem::SetupLogging() {
755
137
  string optarg;
756
137
  if (options_mgr_->GetValue("CVMFS_SYSLOG_LEVEL", &optarg))
757
12
    SetLogSyslogLevel(String2Uint64(optarg));
758
137
  if (options_mgr_->GetValue("CVMFS_SYSLOG_FACILITY", &optarg))
759
    SetLogSyslogFacility(String2Int64(optarg));
760
137
  if (options_mgr_->GetValue("CVMFS_USYSLOG", &optarg))
761
    SetLogMicroSyslog(optarg);
762
137
  if (options_mgr_->GetValue("CVMFS_DEBUGLOG", &optarg))
763
    SetLogDebugFile(optarg);
764
137
  if (options_mgr_->GetValue("CVMFS_SYSLOG_PREFIX", &optarg)) {
765
4
    SetLogSyslogPrefix(optarg);
766
  } else {
767
133
    SetLogSyslogPrefix(name_);
768
  }
769
137
}
770
771
772
107
bool FileSystem::SetupNfsMaps() {
773
#ifdef CVMFS_NFS_SUPPORT
774
  if (!IsHaNfsSource())
775
    nfs_maps_dir_ = workspace_;
776
777
  string no_nfs_sentinel;
778
  if (cache_mgr_->id() == kPosixCacheManager) {
779
    PosixCacheManager *posix_cache_mgr =
780
        reinterpret_cast<PosixCacheManager *>(cache_mgr_);
781
    no_nfs_sentinel = posix_cache_mgr->cache_path() + "/no_nfs_maps." + name_;
782
    if (!IsNfsSource()) {
783
      // Might be a read-only cache
784
      const bool ignore_failure = posix_cache_mgr->alien_cache();
785
      CreateFile(no_nfs_sentinel, 0600, ignore_failure);
786
      return true;
787
    }
788
  } else {
789
    if (IsNfsSource()) {
790
      boot_error_ = "NFS source only works with POSIX cache manager.";
791
      boot_status_ = loader::kFailNfsMaps;
792
      return false;
793
    }
794
    return true;
795
  }
796
797
  assert(cache_mgr_->id() == kPosixCacheManager);
798
  assert(IsNfsSource());
799
  if (!no_nfs_sentinel.empty() && FileExists(no_nfs_sentinel)) {
800
    boot_error_ = "Cache was used without NFS maps before. "
801
                  "It has to be wiped out.";
802
    boot_status_ = loader::kFailNfsMaps;
803
    return false;
804
  }
805
806
  // nfs maps need to be protected by workspace lock
807
  PosixCacheManager *posix_cache_mgr =
808
        reinterpret_cast<PosixCacheManager *>(cache_mgr_);
809
  if (posix_cache_mgr->cache_path() != workspace_) {
810
    boot_error_ = "Cache directory and workspace must be identical for "
811
                  "NFS export";
812
    boot_status_ = loader::kFailNfsMaps;
813
    return false;
814
  }
815
816
  string inode_cache_dir = nfs_maps_dir_ + "/nfs_maps." + name_;
817
  if (!MkdirDeep(inode_cache_dir, 0700)) {
818
    boot_error_ = "Failed to initialize NFS maps";
819
    boot_status_ = loader::kFailNfsMaps;
820
    return false;
821
  }
822
823
  // TODO(jblomer): make this a manager class
824
  if (IsHaNfsSource()) {
825
    nfs_maps_ = NfsMapsSqlite::Create(
826
      inode_cache_dir,
827
      catalog::ClientCatalogManager::kInodeOffset + 1,
828
      found_previous_crash_,
829
      statistics_);
830
  } else {
831
    nfs_maps_ = NfsMapsLeveldb::Create(
832
      inode_cache_dir,
833
      catalog::ClientCatalogManager::kInodeOffset + 1,
834
      found_previous_crash_,
835
      statistics_);
836
  }
837
838
  if (nfs_maps_ == NULL) {
839
    boot_error_ = "Failed to initialize NFS maps";
840
    boot_status_ = loader::kFailNfsMaps;
841
    return false;
842
  }
843
844
  string optarg;
845
  if (options_mgr_->GetValue("CVMFS_NFS_INTERLEAVED_INODES", &optarg)) {
846
    vector<string> tokens = SplitString(optarg, '%');
847
    if (tokens.size() != 2) {
848
      boot_error_ =
849
        "invalid format for CVMFS_NFS_INTERLEAVED_INODES: " + optarg;
850
      boot_status_ = loader::kFailNfsMaps;
851
      return false;
852
    }
853
    nfs_maps_->SetInodeResidue(String2Uint64(tokens[1]),
854
                               String2Uint64(tokens[0]));
855
  }
856
857
  return true;
858
859
#else
860
107
  return true;
861
#endif
862
}
863
864
865
57
bool FileSystem::SetupPosixQuotaMgr(
866
  const FileSystem::PosixCacheSettings &settings,
867
  CacheManager *cache_mgr
868
) {
869
57
  assert(settings.quota_limit >= 0);
870
57
  int64_t quota_threshold = settings.quota_limit / 2;
871
57
  string cache_workspace = settings.cache_path;
872
57
  if (settings.cache_path != settings.workspace) {
873
    LogCvmfs(kLogQuota, kLogDebug | kLogSyslog,
874
             "using workspace %s to protect cache database in %s",
875
             settings.workspace.c_str(), settings.cache_path.c_str());
876
    cache_workspace += ":" + settings.workspace;
877
  }
878
  PosixQuotaManager *quota_mgr;
879
880
57
  if (settings.is_shared) {
881
    quota_mgr = PosixQuotaManager::CreateShared(
882
                  exe_path_,
883
                  cache_workspace,
884
                  settings.quota_limit,
885
                  quota_threshold,
886
2
                  foreground_);
887
2
    if (quota_mgr == NULL) {
888
2
      boot_error_ = "Failed to initialize shared lru cache";
889
2
      boot_status_ = loader::kFailQuota;
890
2
      return false;
891
    }
892
  } else {
893
    quota_mgr = PosixQuotaManager::Create(
894
                  cache_workspace,
895
                  settings.quota_limit,
896
                  quota_threshold,
897
55
                  found_previous_crash_);
898
55
    if (quota_mgr == NULL) {
899
      boot_error_ = "Failed to initialize lru cache";
900
      boot_status_ = loader::kFailQuota;
901
      return false;
902
    }
903
  }
904
905
55
  if (quota_mgr->GetSize() > quota_mgr->GetCapacity()) {
906
    LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog,
907
             "cache is already beyond quota size "
908
             "(size: %" PRId64 ", capacity: %" PRId64 "), cleaning up",
909
             quota_mgr->GetSize(), quota_mgr->GetCapacity());
910
    if (!quota_mgr->Cleanup(quota_threshold)) {
911
      delete quota_mgr;
912
      boot_error_ = "Failed to clean up cache";
913
      boot_status_ = loader::kFailQuota;
914
      return false;
915
    }
916
  }
917
918
55
  int retval = cache_mgr->AcquireQuotaManager(quota_mgr);
919
55
  assert(retval);
920
  LogCvmfs(kLogCvmfs, kLogDebug,
921
           "CernVM-FS: quota initialized, current size %luMB",
922
55
           quota_mgr->GetSize() / (1024 * 1024));
923
55
  return true;
924
}
925
926
927
137
void FileSystem::SetupSqlite() {
928
  // Make sure SQlite starts clean after initialization
929
137
  sqlite3_shutdown();
930
931
  int retval;
932
137
  retval = sqlite3_config(SQLITE_CONFIG_LOG, FileSystem::LogSqliteError, NULL);
933
137
  assert(retval == SQLITE_OK);
934
137
  retval = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
935
137
  assert(retval == SQLITE_OK);
936
137
  SqliteMemoryManager::GetInstance()->AssignGlobalArenas();
937
938
  // Disable SQlite3 file locking
939
137
  retval = sqlite3_vfs_register(sqlite3_vfs_find("unix-none"), 1);
940
137
  assert(retval == SQLITE_OK);
941
137
}
942
943
944
137
bool FileSystem::SetupWorkspace() {
945
137
  string optarg;
946
  // This is very similar to "determine cache dir".  It's for backward
947
  // compatibility with classic cache configuration where there was no
948
  // distinction between workspace and cache.
949
  // Complicated cache configurations should explicitly set CVMFS_WORKSPACE.
950
137
  workspace_ = kDefaultCacheBase;
951
137
  if (options_mgr_->GetValue("CVMFS_CACHE_BASE", &optarg))
952
112
    workspace_ = MakeCanonicalPath(optarg);
953



137
  if (options_mgr_->GetValue("CVMFS_SHARED_CACHE", &optarg) &&
954
      options_mgr_->IsOn(optarg))
955
  {
956
8
    workspace_ += "/shared";
957
  } else {
958
129
    workspace_ += "/" + name_;
959
  }
960
137
  if (options_mgr_->GetValue("CVMFS_CACHE_DIR", &optarg)) {
961
28
    if (options_mgr_->IsDefined("CVMFS_CACHE_BASE")) {
962
      boot_error_ =
963
3
        "'CVMFS_CACHE_BASE' and 'CVMFS_CACHE_DIR' are mutually exclusive";
964
3
      boot_status_ = loader::kFailOptions;
965
3
      return false;
966
    }
967
25
    workspace_ = optarg;
968
  }
969
134
  if (options_mgr_->GetValue("CVMFS_WORKSPACE", &optarg))
970
8
    workspace_ = optarg;
971
134
  workspace_fullpath_ = workspace_;
972
973
  // If workspace and alien cache are the same directory, we need to open
974
  // permission now to 0770 to avoid a race when fixing it later
975
134
  const int mode = 0770;
976
134
  if (!MkdirDeep(workspace_, mode, false)) {
977
1
    boot_error_ = "cannot create workspace directory " + workspace_;
978
1
    boot_status_ = loader::kFailCacheDir;
979
1
    return false;
980
  }
981
982
133
  if (!LockWorkspace())
983
2
    return false;
984
131
  if (!SetupCwd())
985
    return false;
986
131
  if (!SetupCrashGuard())
987
    return false;
988
989
131
  return true;
990
}
991
992
993
107
void FileSystem::SetupUuid() {
994
107
  uuid_cache_ = cvmfs::Uuid::Create(workspace_ + "/uuid");
995
107
  if (uuid_cache_ == NULL) {
996
    LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogWarn,
997
             "failed to load/store %s/uuid", workspace_.c_str());
998
    uuid_cache_ = cvmfs::Uuid::Create("");
999
    assert(uuid_cache_ != NULL);
1000
  }
1001
107
}
1002
1003
1004
/**
1005
 * Required by CernVM: the fuse module needs to free r/w file descriptor to the
1006
 * cache in order to properly unravel the file system stack on shutdown.
1007
 */
1008
void FileSystem::TearDown2ReadOnly() {
1009
  if ((cache_mgr_ != NULL) && (cache_mgr_->id() == kPosixCacheManager)) {
1010
    PosixCacheManager *posix_cache_mgr =
1011
      reinterpret_cast<PosixCacheManager *>(cache_mgr_);
1012
    posix_cache_mgr->TearDown2ReadOnly();
1013
  }
1014
1015
  unlink(path_crash_guard_.c_str());
1016
  LogCvmfs(kLogCache, kLogSyslog, "switch to read-only cache mode");
1017
  SetLogMicroSyslog("");
1018
}
1019
1020
1021
131
bool FileSystem::TriageCacheMgr() {
1022
131
  cache_mgr_instance_ = kDefaultCacheMgrInstance;
1023
131
  string instance;
1024



131
  if (options_mgr_->GetValue("CVMFS_CACHE_PRIMARY", &instance) &&
1025
      !instance.empty())
1026
  {
1027
31
    if (!CheckInstanceName(instance))
1028
2
      return false;
1029
29
    cache_mgr_instance_ = instance;
1030
  }
1031
1032
129
  cache_mgr_ = SetupCacheMgr(cache_mgr_instance_);
1033
129
  return cache_mgr_ != NULL;
1034
}
1035
1036
1037
//------------------------------------------------------------------------------
1038
1039
1040
const char *MountPoint::kDefaultAuthzSearchPath = "/usr/libexec/cvmfs/authz";
1041
const char *MountPoint::kDefaultBlacklist = "/etc/cvmfs/blacklist";
1042
1043
59
bool MountPoint::CheckBlacklists() {
1044
59
  blacklist_paths_.clear();
1045
59
  string blacklist;
1046
59
  if (!options_mgr_->GetValue("CVMFS_BLACKLIST", &blacklist))
1047
53
    blacklist = kDefaultBlacklist;
1048
59
  blacklist_paths_.push_back(blacklist);
1049
1050
59
  bool append = false;
1051
59
  if (FileExists(blacklist)) {
1052
3
    if (!signature_mgr_->LoadBlacklist(blacklist, append)) {
1053
      boot_error_ = "failed to load blacklist " + blacklist;
1054
      boot_status_ = loader::kFailSignature;
1055
      return false;
1056
    }
1057
3
    append = true;
1058
  }
1059
1060
59
  string config_repository_path;
1061
59
  if (options_mgr_->HasConfigRepository(fqrn_, &config_repository_path)) {
1062
9
    blacklist = config_repository_path + "blacklist";
1063
9
    blacklist_paths_.push_back(blacklist);
1064
9
    if (FileExists(blacklist)) {
1065
6
      if (!signature_mgr_->LoadBlacklist(blacklist, append)) {
1066
        boot_error_ = "failed to load blacklist from config repository";
1067
        boot_status_ = loader::kFailSignature;
1068
        return false;
1069
      }
1070
    }
1071
  }
1072
1073
59
  return true;
1074
}
1075
1076
1077
/**
1078
 * Like CheckBlacklists but supposed to be used after bootstrap, possibly in
1079
 * multi-threaded context.
1080
 */
1081
6
bool MountPoint::ReloadBlacklists() {
1082
6
  bool result = true;
1083
6
  bool append = false;
1084

6
  for (unsigned i = 0; i < blacklist_paths_.size(); ++i) {
1085
9
    string blacklist = blacklist_paths_[i];
1086
9
    if (FileExists(blacklist)) {
1087
      bool retval = signature_mgr_->LoadBlacklist(blacklist, append);
1088
      // TODO(jblomer): this can leave us with a half-loaded blacklist
1089
      if (!retval)
1090
        return false;
1091
      append = true;
1092
    }
1093
  }
1094
6
  return result;
1095
}
1096
1097
1098
/**
1099
 * The option_mgr parameter can be NULL, in which case the global option manager
1100
 * from the file system is used.
1101
 */
1102
61
MountPoint *MountPoint::Create(
1103
  const string &fqrn,
1104
  FileSystem *file_system,
1105
  OptionsManager *options_mgr)
1106
{
1107
61
  if (options_mgr == NULL)
1108
53
    options_mgr = file_system->options_mgr();
1109
  UniquePtr<MountPoint> mountpoint(new MountPoint(
1110
61
    fqrn, file_system, options_mgr));
1111
1112
  // At this point, we have a repository name, the type (fuse or library) and
1113
  // an options manager (which can be the same than the FileSystem's one).
1114
1115
61
  mountpoint->CreateStatistics();
1116
61
  mountpoint->CreateAuthz();
1117
61
  mountpoint->backoff_throttle_ = new BackoffThrottle();
1118
1119

61
  if (!mountpoint->CreateSignatureManager() || !mountpoint->CheckBlacklists())
1120
2
    return mountpoint.Release();
1121
59
  if (!mountpoint->CreateDownloadManagers())
1122
2
    return mountpoint.Release();
1123
57
  if (!mountpoint->CreateResolvConfWatcher()) {
1124
    return mountpoint.Release();
1125
  }
1126
57
  mountpoint->CreateFetchers();
1127
57
  if (!mountpoint->CreateCatalogManager())
1128
20
    return mountpoint.Release();
1129
37
  if (!mountpoint->CreateTracer())
1130
    return mountpoint.Release();
1131
1132
37
  mountpoint->ReEvaluateAuthz();
1133
37
  mountpoint->CreateTables();
1134
37
  mountpoint->SetupBehavior();
1135
1136
37
  mountpoint->boot_status_ = loader::kFailOk;
1137
37
  return mountpoint.Release();
1138
}
1139
1140
1141
61
void MountPoint::CreateAuthz() {
1142
61
  string optarg;
1143
61
  string authz_helper;
1144
61
  if (options_mgr_->GetValue("CVMFS_AUTHZ_HELPER", &optarg))
1145
    authz_helper = optarg;
1146
61
  string authz_search_path(kDefaultAuthzSearchPath);
1147
61
  if (options_mgr_->GetValue("CVMFS_AUTHZ_SEARCH_PATH", &optarg))
1148
    authz_search_path = optarg;
1149
1150
  authz_fetcher_ = new AuthzExternalFetcher(
1151
    fqrn_,
1152
    authz_helper,
1153
    authz_search_path,
1154
61
    options_mgr_);
1155
61
  assert(authz_fetcher_ != NULL);
1156
1157
  authz_session_mgr_ = AuthzSessionManager::Create(
1158
    authz_fetcher_,
1159
61
    statistics_);
1160
61
  assert(authz_session_mgr_ != NULL);
1161
1162
61
  authz_attachment_ = new AuthzAttachment(authz_session_mgr_);
1163
61
  assert(authz_attachment_ != NULL);
1164
61
}
1165
1166
1167
57
bool MountPoint::CreateCatalogManager() {
1168
57
  string optarg;
1169
1170
57
  catalog_mgr_ = new catalog::ClientCatalogManager(this);
1171
1172
57
  SetupInodeAnnotation();
1173
57
  if (!SetupOwnerMaps())
1174
2
    return false;
1175
55
  shash::Any root_hash;
1176
55
  if (!DetermineRootHash(&root_hash))
1177
4
    return false;
1178
1179
  bool retval;
1180
51
  if (root_hash.IsNull()) {
1181
24
    retval = catalog_mgr_->Init();
1182
  } else {
1183
27
    fixed_catalog_ = true;
1184
    bool alt_root_path =
1185
      options_mgr_->GetValue("CVMFS_ALT_ROOT_PATH", &optarg) &&
1186



27
      options_mgr_->IsOn(optarg);
1187
27
    retval = catalog_mgr_->InitFixed(root_hash, alt_root_path);
1188
  }
1189
51
  if (!retval) {
1190
11
    boot_error_ = "Failed to initialize root file catalog";
1191
11
    boot_status_ = loader::kFailCatalog;
1192
11
    return false;
1193
  }
1194
1195
40
  if (catalog_mgr_->IsRevisionBlacklisted()) {
1196
3
    boot_error_ = "repository revision blacklisted";
1197
3
    boot_status_ = loader::kFailRevisionBlacklisted;
1198
3
    return false;
1199
  }
1200
1201



37
  if (options_mgr_->GetValue("CVMFS_AUTO_UPDATE", &optarg) &&
1202
      !options_mgr_->IsOn(optarg))
1203
  {
1204
    fixed_catalog_ = true;
1205
  }
1206
1207
37
  if (options_mgr_->GetValue("CVMFS_CATALOG_WATERMARK", &optarg)) {
1208
    catalog_mgr_->SetCatalogWatermark(String2Uint64(optarg));
1209
  }
1210
1211
37
  if (catalog_mgr_->volatile_flag()) {
1212
    LogCvmfs(kLogCvmfs, kLogDebug, "content of repository flagged as VOLATILE");
1213
  }
1214
1215
37
  return true;
1216
}
1217
1218
1219
59
bool MountPoint::CreateDownloadManagers() {
1220
59
  string optarg;
1221
59
  download_mgr_ = new download::DownloadManager();
1222
59
  const bool use_system_proxy = false;
1223
  download_mgr_->Init(kDefaultNumConnections, use_system_proxy,
1224
59
                      perf::StatisticsTemplate("download", statistics_));
1225
59
  download_mgr_->SetCredentialsAttachment(authz_attachment_);
1226
1227
59
  if (options_mgr_->GetValue("CVMFS_SERVER_URL", &optarg)) {
1228
59
    download_mgr_->SetHostChain(optarg);
1229
  }
1230
1231
59
  SetupDnsTuning(download_mgr_);
1232
59
  SetupHttpTuning();
1233
1234
59
  string forced_proxy_template;
1235
59
  if (options_mgr_->GetValue("CVMFS_PROXY_TEMPLATE", &optarg))
1236
    forced_proxy_template = optarg;
1237
  download_mgr_->SetProxyTemplates(file_system_->uuid_cache()->uuid(),
1238
59
                                   forced_proxy_template);
1239
1240
59
  string proxies;
1241
59
  if (options_mgr_->GetValue("CVMFS_HTTP_PROXY", &optarg))
1242
57
    proxies = optarg;
1243
  proxies = download::ResolveProxyDescription(
1244
    proxies,
1245
    file_system_->workspace() + "/proxies" + GetUniqFileSuffix(),
1246
59
    download_mgr_);
1247
59
  if (proxies == "") {
1248
2
    boot_error_ = "failed to discover HTTP proxy servers";
1249
2
    boot_status_ = loader::kFailWpad;
1250
2
    return false;
1251
  }
1252
57
  string fallback_proxies;
1253
57
  if (options_mgr_->GetValue("CVMFS_FALLBACK_PROXY", &optarg))
1254
    fallback_proxies = optarg;
1255
  download_mgr_->SetProxyChain(proxies, fallback_proxies,
1256
57
                               download::DownloadManager::kSetProxyBoth);
1257
1258
  bool do_geosort = options_mgr_->GetValue("CVMFS_USE_GEOAPI", &optarg) &&
1259



57
                    options_mgr_->IsOn(optarg);
1260
57
  if (do_geosort) {
1261
    download_mgr_->ProbeGeo();
1262
  }
1263
57
  if (options_mgr_->GetValue("CVMFS_MAX_SERVERS", &optarg)) {
1264
12
    unsigned max_servers = String2Uint64(optarg);
1265
12
    std::vector<std::string> host_chain;
1266
12
    download_mgr_->GetHostInfo(&host_chain, NULL, NULL);
1267

12
    if (max_servers > 0 && max_servers < host_chain.size()) {
1268
3
      host_chain.resize(max_servers);
1269
3
      download_mgr_->SetHostChain(host_chain);
1270
    }
1271
  }
1272
57
  return SetupExternalDownloadMgr(do_geosort);
1273
}
1274
1275
57
bool MountPoint::CreateResolvConfWatcher() {
1276
57
  std::string roaming_value;
1277
57
  options_mgr_->GetValue("CVMFS_DNS_ROAMING", &roaming_value);
1278



57
  if (options_mgr_->IsDefined("CVMFS_DNS_ROAMING") &&
1279
      options_mgr_->IsOn(roaming_value)) {
1280
    LogCvmfs(kLogCvmfs, kLogDebug,
1281
             "DNS roaming is enabled for this repository.");
1282
    // Create a file watcher to update the DNS settings of the download
1283
    // managers when there are changes to /etc/resolv.conf
1284
    resolv_conf_watcher_ = platform_file_watcher();
1285
1286
    if (resolv_conf_watcher_) {
1287
      ResolvConfEventHandler *handler =
1288
          new ResolvConfEventHandler(download_mgr_, external_download_mgr_);
1289
      resolv_conf_watcher_->RegisterHandler("/etc/resolv.conf", handler);
1290
    }
1291
  } else {
1292
    LogCvmfs(kLogCvmfs, kLogDebug,
1293
57
             "DNS roaming is disabled for this repository.");
1294
  }
1295
57
  return true;
1296
}
1297
1298
57
void MountPoint::CreateFetchers() {
1299
  fetcher_ = new cvmfs::Fetcher(
1300
    file_system_->cache_mgr(),
1301
    download_mgr_,
1302
    backoff_throttle_,
1303
57
    perf::StatisticsTemplate("fetch", statistics_));
1304
1305
57
  const bool is_external_data = true;
1306
  external_fetcher_ = new cvmfs::Fetcher(
1307
    file_system_->cache_mgr(),
1308
    external_download_mgr_,
1309
    backoff_throttle_,
1310
    perf::StatisticsTemplate("fetch-external", statistics_),
1311
57
    is_external_data);
1312
57
}
1313
1314
1315
61
bool MountPoint::CreateSignatureManager() {
1316
61
  string optarg;
1317
61
  signature_mgr_ = new signature::SignatureManager();
1318
61
  signature_mgr_->Init();
1319
1320
61
  string public_keys;
1321
61
  if (options_mgr_->GetValue("CVMFS_PUBLIC_KEY", &optarg)) {
1322
58
    public_keys = optarg;
1323
3
  } else if (options_mgr_->GetValue("CVMFS_KEYS_DIR", &optarg)) {
1324
    // Collect .pub files from CVMFS_KEYS_DIR
1325
    public_keys = JoinStrings(FindFilesBySuffix(optarg, ".pub"), ":");
1326
  } else {
1327
    public_keys =
1328
3
      JoinStrings(FindFilesBySuffix("/etc/cvmfs/keys", ".pub"), ":");
1329
  }
1330
1331
61
  if (!signature_mgr_->LoadPublicRsaKeys(public_keys)) {
1332
2
    boot_error_ = "failed to load public key(s)";
1333
2
    boot_status_ = loader::kFailSignature;
1334
2
    return false;
1335
  }
1336
  LogCvmfs(kLogCvmfs, kLogDebug, "CernVM-FS: using public key(s) %s",
1337
59
           public_keys.c_str());
1338
1339
59
  if (options_mgr_->GetValue("CVMFS_TRUSTED_CERTS", &optarg)) {
1340
    if (!signature_mgr_->LoadTrustedCaCrl(optarg)) {
1341
      boot_error_ = "failed to load trusted certificates";
1342
      boot_status_ = loader::kFailSignature;
1343
      return false;
1344
    }
1345
  }
1346
1347
59
  return true;
1348
}
1349
1350
1351
61
void MountPoint::CreateStatistics() {
1352
61
  statistics_ = file_system_->statistics()->Fork();
1353
61
  if (file_system_->type() != FileSystem::kFsFuse)
1354
8
    return;
1355
1356
  // TODO(jblomer): this should be registered by the tracker
1357
  statistics_->Register("inode_tracker.n_insert",
1358
53
                        "overall number of accessed inodes");
1359
  statistics_->Register("inode_tracker.n_remove",
1360
53
                        "overall number of evicted inodes");
1361
  statistics_->Register("inode_tracker.no_reference",
1362
53
                        "currently active inodes");
1363
  statistics_->Register("inode_tracker.n_hit_inode",
1364
53
                        "overall number of inode lookups");
1365
  statistics_->Register("inode_tracker.n_hit_path",
1366
53
                        "overall number of successful path lookups");
1367
  statistics_->Register("inode_tracker.n_miss_path",
1368
53
                        "overall number of unsuccessful path lookups");
1369
}
1370
1371
1372
37
void MountPoint::CreateTables() {
1373
37
  if (file_system_->type() != FileSystem::kFsFuse) {
1374
    // Libcvmfs simplified tables
1375
5
    md5path_cache_ = new lru::Md5PathCache(kLibPathCacheSize, statistics_);
1376
5
    simple_chunk_tables_ = new SimpleChunkTables();
1377
5
    return;
1378
  }
1379
1380
32
  chunk_tables_ = new ChunkTables();
1381
1382
32
  string optarg;
1383
32
  uint64_t mem_cache_size = kDefaultMemcacheSize;
1384
32
  if (options_mgr_->GetValue("CVMFS_MEMCACHE_SIZE", &optarg))
1385
    mem_cache_size = String2Uint64(optarg) * 1024 * 1024;
1386
1387
  const double memcache_unit_size =
1388
    (static_cast<double>(kInodeCacheFactor) * lru::Md5PathCache::GetEntrySize())
1389
32
    + lru::InodeCache::GetEntrySize() + lru::PathCache::GetEntrySize();
1390
  const unsigned memcache_num_units =
1391
32
    mem_cache_size / static_cast<unsigned>(memcache_unit_size);
1392
  // Number of cache entries must be a multiple of 64
1393
32
  const unsigned mask_64 = ~((1 << 6) - 1);
1394
32
  inode_cache_ = new lru::InodeCache(memcache_num_units & mask_64, statistics_);
1395
32
  path_cache_ = new lru::PathCache(memcache_num_units & mask_64, statistics_);
1396
  md5path_cache_ = new lru::Md5PathCache((memcache_num_units * 7) & mask_64,
1397
32
                                         statistics_);
1398
1399
32
  inode_tracker_ = new glue::InodeTracker();
1400
}
1401
1402
/**
1403
 * Will create a tracer for the current mount point
1404
 * Tracefile path, Trace buffer size and trace buffer flush threshold
1405
 * can be configured by the options: CVMFS_TRACEFILE,
1406
 * CVMFS_TRACEBUFFER, CVMFS_TRACEBUFFER_THRESHOLD(respectively)
1407
 * VMFS_TRACEBUFFER and CVMFS_TRACEBUFFER_THRESHOLD will silently fallback
1408
 * to default values if configuration values don't exist or are invalid
1409
 */
1410
37
bool MountPoint::CreateTracer() {
1411
37
  string optarg;
1412
37
  tracer_ = new Tracer();
1413
37
  if (options_mgr_->GetValue("CVMFS_TRACEFILE", &optarg)) {
1414
    if (file_system_->type() != FileSystem::kFsFuse) {
1415
      boot_error_ = "tracer is only supported in the fuse module";
1416
      boot_status_ = loader::kFailOptions;
1417
      return false;
1418
    }
1419
    string tracebuffer_file = optarg;
1420
    uint64_t tracebuffer_size = kTracerBufferSize;
1421
    uint64_t tracebuffer_threshold = kTracerFlushThreshold;
1422
1423
    if (options_mgr_->GetValue("CVMFS_TRACEBUFFER", &optarg)) {
1424
      tracebuffer_size = String2Uint64(optarg);
1425
    }
1426
    if (options_mgr_->GetValue("CVMFS_TRACEBUFFER_THRESHOLD",
1427
      &optarg)) {
1428
      tracebuffer_threshold = String2Uint64(optarg);
1429
    }
1430
    assert(tracebuffer_size <= INT_MAX
1431
      && tracebuffer_threshold <= INT_MAX);
1432
    LogCvmfs(kLogCvmfs, kLogDebug,
1433
      "Initialising tracer with buffer size %" PRIu64 " and threshold %" PRIu64,
1434
      tracebuffer_size, tracebuffer_threshold);
1435
    tracer_->Activate(tracebuffer_size, tracebuffer_threshold,
1436
      tracebuffer_file);
1437
  }
1438
37
  return true;
1439
}
1440
1441
1442
55
bool MountPoint::DetermineRootHash(shash::Any *root_hash) {
1443
55
  string optarg;
1444
55
  if (options_mgr_->GetValue("CVMFS_ROOT_HASH", &optarg)) {
1445
23
    *root_hash = MkFromHexPtr(shash::HexPtr(optarg), shash::kSuffixCatalog);
1446
23
    return true;
1447
  }
1448
1449





32
  if (!options_mgr_->IsDefined("CVMFS_REPOSITORY_TAG") &&
1450
      !options_mgr_->IsDefined("CVMFS_REPOSITORY_DATE"))
1451
  {
1452
24
    root_hash->SetNull();
1453
24
    return true;
1454
  }
1455
1456
8
  string history_path;
1457
8
  if (!FetchHistory(&history_path))
1458
    return false;
1459
8
  UnlinkGuard history_file(history_path);
1460
  UniquePtr<history::History> tag_db(
1461
8
    history::SqliteHistory::Open(history_path));
1462
8
  if (!tag_db) {
1463
    LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog,
1464
             "failed to open history database (%s)", history_path.c_str());
1465
    boot_error_ = "failed to open history database";
1466
    boot_status_ = loader::kFailHistory;
1467
    return false;
1468
  }
1469
1470
8
  history::History::Tag tag;
1471
  bool retval;
1472
8
  if (!options_mgr_->GetValue("CVMFS_REPOSITORY_TAG", &repository_tag_)) {
1473
4
    string repository_date;
1474
    // options_mgr_->IsDefined("CVMFS_REPOSITORY_DATE") must be true
1475
4
    options_mgr_->GetValue("CVMFS_REPOSITORY_DATE", &repository_date);
1476
4
    time_t repository_utctime = IsoTimestamp2UtcTime(repository_date);
1477
4
    if (repository_utctime == 0) {
1478
      boot_error_ = "invalid timestamp in CVMFS_REPOSITORY_DATE: " +
1479
                    repository_date + ". Use YYYY-MM-DDTHH:MM:SSZ";
1480
      boot_status_ = loader::kFailHistory;
1481
      return false;
1482
    }
1483
4
    retval = tag_db->GetByDate(repository_utctime, &tag);
1484
4
    if (!retval) {
1485
      boot_error_ = "no repository state as early as utc timestamp " +
1486
2
                     StringifyTime(repository_utctime, true);
1487
2
      boot_status_ = loader::kFailHistory;
1488
2
      return false;
1489
    }
1490
    LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslog,
1491
             "time stamp %s UTC resolved to tag '%s'",
1492
             StringifyTime(repository_utctime, true).c_str(),
1493
2
             tag.name.c_str());
1494
2
    repository_tag_ = tag.name;
1495
  } else {
1496
4
    retval = tag_db->GetByName(repository_tag_, &tag);
1497
4
    if (!retval) {
1498
2
      boot_error_ = "no such tag: " + repository_tag_;
1499
2
      boot_status_ = loader::kFailHistory;
1500
2
      return false;
1501
    }
1502
  }
1503
4
  LogCvmfs(kLogCvmfs, kLogDebug, "mounting tag %s", tag.name.c_str());
1504
1505
4
  *root_hash = tag.root_hash;
1506
4
  return true;
1507
}
1508
1509
1510
8
bool MountPoint::FetchHistory(std::string *history_path) {
1511
  manifest::Failures retval_mf;
1512
8
  manifest::ManifestEnsemble ensemble;
1513
  retval_mf = manifest::Fetch("", fqrn_, 0, NULL, signature_mgr_, download_mgr_,
1514
8
                              &ensemble);
1515
8
  if (retval_mf != manifest::kFailOk) {
1516
    boot_error_ = "Failed to fetch manifest";
1517
    boot_status_ = loader::kFailHistory;
1518
    return false;
1519
  }
1520
8
  shash::Any history_hash = ensemble.manifest->history();
1521
8
  if (history_hash.IsNull()) {
1522
    boot_error_ = "No history";
1523
    boot_status_ = loader::kFailHistory;
1524
    return false;
1525
  }
1526
1527
  int fd = fetcher_->Fetch(
1528
    history_hash,
1529
    CacheManager::kSizeUnknown,
1530
    "tag database for " + fqrn_,
1531
    zlib::kZlibDefault,
1532
8
    CacheManager::kTypeRegular);
1533
8
  if (fd < 0) {
1534
    boot_error_ = "failed to download history: " + StringifyInt(-fd);
1535
    boot_status_ = loader::kFailHistory;
1536
    return false;
1537
  }
1538
  // We have the custom sqlite vfs driver installed
1539
8
  *history_path = "@" + StringifyInt(fd);
1540
8
  return true;
1541
}
1542
1543
1544
unsigned MountPoint::GetEffectiveTtlSec() {
1545
  unsigned max_ttl;
1546
  {
1547
    MutexLockGuard lock_guard(lock_max_ttl_);
1548
    max_ttl = max_ttl_sec_;
1549
  }
1550
  const unsigned catalog_ttl_sec = catalog_mgr_->GetTTL();
1551
1552
  return max_ttl ? std::min(max_ttl, catalog_ttl_sec) : catalog_ttl_sec;
1553
}
1554
1555
1556
unsigned MountPoint::GetMaxTtlMn() {
1557
  MutexLockGuard lock_guard(lock_max_ttl_);
1558
  return max_ttl_sec_ / 60;
1559
}
1560
1561
1562
/**
1563
 * Files in the workspace from different file systems / mountpoints need to
1564
 * have different names.  Used, for example, for caching proxy settings.
1565
 */
1566
59
string MountPoint::GetUniqFileSuffix() {
1567
59
  return "." + file_system_->name() + "-" + fqrn_;
1568
}
1569
1570
1571
61
MountPoint::MountPoint(
1572
  const string &fqrn,
1573
  FileSystem *file_system,
1574
  OptionsManager *options_mgr)
1575
  : fqrn_(fqrn)
1576
  , uuid_(cvmfs::Uuid::Create(""))
1577
  , file_system_(file_system)
1578
  , options_mgr_(options_mgr)
1579
  , statistics_(NULL)
1580
  , authz_fetcher_(NULL)
1581
  , authz_session_mgr_(NULL)
1582
  , authz_attachment_(NULL)
1583
  , backoff_throttle_(NULL)
1584
  , signature_mgr_(NULL)
1585
  , download_mgr_(NULL)
1586
  , external_download_mgr_(NULL)
1587
  , fetcher_(NULL)
1588
  , external_fetcher_(NULL)
1589
  , inode_annotation_(NULL)
1590
  , catalog_mgr_(NULL)
1591
  , chunk_tables_(NULL)
1592
  , simple_chunk_tables_(NULL)
1593
  , inode_cache_(NULL)
1594
  , path_cache_(NULL)
1595
  , md5path_cache_(NULL)
1596
  , tracer_(NULL)
1597
  , inode_tracker_(NULL)
1598
  , resolv_conf_watcher_(NULL)
1599
  , max_ttl_sec_(kDefaultMaxTtlSec)
1600
  , kcache_timeout_sec_(static_cast<double>(kDefaultKCacheTtlSec))
1601
  , fixed_catalog_(false)
1602
  , hide_magic_xattrs_(false)
1603
61
  , has_membership_req_(false)
1604
{
1605
61
  int retval = pthread_mutex_init(&lock_max_ttl_, NULL);
1606
61
  assert(retval == 0);
1607
}
1608
1609
1610
61
MountPoint::~MountPoint() {
1611
61
  pthread_mutex_destroy(&lock_max_ttl_);
1612
1613
61
  delete inode_tracker_;
1614
61
  delete tracer_;
1615
61
  delete md5path_cache_;
1616
61
  delete path_cache_;
1617
61
  delete inode_cache_;
1618
61
  delete simple_chunk_tables_;
1619
61
  delete chunk_tables_;
1620
1621
61
  delete catalog_mgr_;
1622
61
  delete inode_annotation_;
1623
61
  delete external_fetcher_;
1624
61
  delete fetcher_;
1625
61
  if (external_download_mgr_ != NULL) {
1626
57
    external_download_mgr_->Fini();
1627
57
    delete external_download_mgr_;
1628
  }
1629
61
  if (download_mgr_ != NULL) {
1630
59
    download_mgr_->Fini();
1631
59
    delete download_mgr_;
1632
  }
1633
61
  if (signature_mgr_ != NULL) {
1634
61
    signature_mgr_->Fini();
1635
61
    delete signature_mgr_;
1636
  }
1637
1638
61
  if (resolv_conf_watcher_ != NULL) {
1639
    resolv_conf_watcher_->Stop();
1640
    delete resolv_conf_watcher_;
1641
  }
1642
1643
61
  delete backoff_throttle_;
1644
61
  delete authz_attachment_;
1645
61
  delete authz_session_mgr_;
1646
61
  delete authz_fetcher_;
1647
61
  delete statistics_;
1648
61
  delete uuid_;
1649
}
1650
1651
1652
37
void MountPoint::ReEvaluateAuthz() {
1653
37
  string old_membership_req = membership_req_;
1654
37
  has_membership_req_ = catalog_mgr_->GetVOMSAuthz(&membership_req_);
1655
37
  if (old_membership_req != membership_req_) {
1656
    authz_session_mgr_->ClearSessionCache();
1657
    authz_attachment_->set_membership(membership_req_);
1658
  }
1659
37
}
1660
1661
1662
void MountPoint::SetMaxTtlMn(unsigned value_minutes) {
1663
  MutexLockGuard lock_guard(lock_max_ttl_);
1664
  max_ttl_sec_ = value_minutes * 60;
1665
}
1666
1667
1668
37
void MountPoint::SetupBehavior() {
1669
37
  string optarg;
1670
1671
37
  if (options_mgr_->GetValue("CVMFS_MAX_TTL", &optarg))
1672
    SetMaxTtlMn(String2Uint64(optarg));
1673
1674
37
  if (options_mgr_->GetValue("CVMFS_KCACHE_TIMEOUT", &optarg)) {
1675
    // Can be negative and should then be interpreted as 0.0
1676
    kcache_timeout_sec_ =
1677
      std::max(0.0, static_cast<double>(String2Int64(optarg)));
1678
  }
1679
  LogCvmfs(kLogCvmfs, kLogDebug, "kernel caches expire after %d seconds",
1680
37
           static_cast<int>(kcache_timeout_sec_));
1681
1682



37
  if (options_mgr_->GetValue("CVMFS_HIDE_MAGIC_XATTRS", &optarg)
1683
      && options_mgr_->IsOn(optarg))
1684
  {
1685
    hide_magic_xattrs_ = true;
1686
  }
1687
37
}
1688
1689
1690
/**
1691
 * Called twice once for the regular download manager and once for the external
1692
 * download manager.
1693
 */
1694
59
void MountPoint::SetupDnsTuning(download::DownloadManager *manager) {
1695
59
  string optarg;
1696
59
  unsigned dns_timeout_ms = download::DownloadManager::kDnsDefaultTimeoutMs;
1697
59
  unsigned dns_retries = download::DownloadManager::kDnsDefaultRetries;
1698
59
  if (options_mgr_->GetValue("CVMFS_DNS_TIMEOUT", &optarg))
1699
    dns_timeout_ms = String2Uint64(optarg) * 1000;
1700
59
  if (options_mgr_->GetValue("CVMFS_DNS_RETRIES", &optarg))
1701
    dns_retries = String2Uint64(optarg);
1702
59
  manager->SetDnsParameters(dns_retries, dns_timeout_ms);
1703
1704
  // Rest has to be after SetDnsParameters because SetDnsParameters might
1705
  // construct a new resolver object
1706
1707
59
  unsigned dns_min_ttl = dns::Resolver::kDefaultMinTtl;
1708
59
  unsigned dns_max_ttl = dns::Resolver::kDefaultMaxTtl;
1709
59
  if (options_mgr_->GetValue("CVMFS_DNS_MIN_TTL", &optarg))
1710
    dns_min_ttl = String2Uint64(optarg);
1711
59
  if (options_mgr_->GetValue("CVMFS_DNS_MAX_TTL", &optarg))
1712
    dns_max_ttl = String2Uint64(optarg);
1713
59
  manager->SetDnsTtlLimits(dns_min_ttl, dns_max_ttl);
1714
1715
59
  if (options_mgr_->GetValue("CVMFS_DNS_SERVER", &optarg)) {
1716
    download_mgr_->SetDnsServer(optarg);
1717
  }
1718
1719
59
  if (options_mgr_->GetValue("CVMFS_IPFAMILY_PREFER", &optarg)) {
1720
    switch (String2Int64(optarg)) {
1721
      case 4:
1722
        manager->SetIpPreference(dns::kIpPreferV4);
1723
        break;
1724
      case 6:
1725
        manager->SetIpPreference(dns::kIpPreferV6);
1726
        break;
1727
    }
1728
  }
1729
59
  if (options_mgr_->GetValue("CVMFS_MAX_IPADDR_PER_PROXY", &optarg))
1730
    manager->SetMaxIpaddrPerProxy(String2Uint64(optarg));
1731
59
}
1732
1733
1734
57
bool MountPoint::SetupExternalDownloadMgr(bool dogeosort) {
1735
57
  string optarg;
1736
  external_download_mgr_ =
1737
    download_mgr_->Clone(perf::StatisticsTemplate("download-external",
1738
57
      statistics_));
1739
1740
  unsigned timeout;
1741
  unsigned timeout_direct;
1742
57
  download_mgr_->GetTimeout(&timeout, &timeout_direct);
1743
57
  if (options_mgr_->GetValue("CVMFS_EXTERNAL_TIMEOUT", &optarg)) {
1744
    timeout = String2Uint64(optarg);
1745
  }
1746
57
  if (options_mgr_->GetValue("CVMFS_EXTERNAL_TIMEOUT_DIRECT", &optarg)) {
1747
    timeout_direct = String2Uint64(optarg);
1748
  }
1749
57
  external_download_mgr_->SetTimeout(timeout, timeout_direct);
1750
1751
57
  if (options_mgr_->GetValue("CVMFS_EXTERNAL_URL", &optarg)) {
1752
6
    external_download_mgr_->SetHostChain(optarg);
1753
6
    if (dogeosort) {
1754
      std::vector<std::string> host_chain;
1755
      external_download_mgr_->GetHostInfo(&host_chain, NULL, NULL);
1756
      download_mgr_->GeoSortServers(&host_chain);
1757
      external_download_mgr_->SetHostChain(host_chain);
1758
    }
1759
  } else {
1760
51
    external_download_mgr_->SetHostChain("");
1761
  }
1762
1763
57
  if (options_mgr_->GetValue("CVMFS_EXTERNAL_MAX_SERVERS", &optarg)) {
1764
9
    unsigned max_servers = String2Uint64(optarg);
1765
9
    std::vector<std::string> host_chain;
1766
9
    external_download_mgr_->GetHostInfo(&host_chain, NULL, NULL);
1767

9
    if (max_servers > 0 && max_servers < host_chain.size()) {
1768
3
      host_chain.resize(max_servers);
1769
3
      external_download_mgr_->SetHostChain(host_chain);
1770
    }
1771
  }
1772
1773
57
  string proxies = "DIRECT";
1774
57
  if (options_mgr_->GetValue("CVMFS_EXTERNAL_HTTP_PROXY", &optarg)) {
1775
    proxies = download::ResolveProxyDescription(
1776
      optarg,
1777
      file_system_->workspace() + "/proxies-external" + GetUniqFileSuffix(),
1778
      external_download_mgr_);
1779
    if (proxies == "") {
1780
      boot_error_ = "failed to discover external HTTP proxy servers";
1781
      boot_status_ = loader::kFailWpad;
1782
      return false;
1783
    }
1784
  }
1785
57
  string fallback_proxies;
1786
57
  if (options_mgr_->GetValue("CVMFS_EXTERNAL_FALLBACK_PROXY", &optarg))
1787
    fallback_proxies = optarg;
1788
  external_download_mgr_->SetProxyChain(
1789
57
    proxies, fallback_proxies, download::DownloadManager::kSetProxyBoth);
1790
1791
57
  return true;
1792
}
1793
1794
1795
59
void MountPoint::SetupHttpTuning() {
1796
59
  string optarg;
1797
1798
  // TODO(jblomer): avoid double default settings
1799
1800
59
  unsigned timeout = kDefaultTimeoutSec;
1801
59
  unsigned timeout_direct = kDefaultTimeoutSec;
1802
59
  if (options_mgr_->GetValue("CVMFS_TIMEOUT", &optarg))
1803
    timeout = String2Uint64(optarg);
1804
59
  if (options_mgr_->GetValue("CVMFS_TIMEOUT_DIRECT", &optarg))
1805
    timeout_direct = String2Uint64(optarg);
1806
59
  download_mgr_->SetTimeout(timeout, timeout_direct);
1807
1808
59
  unsigned max_retries = kDefaultRetries;
1809
59
  unsigned backoff_init = kDefaultBackoffInitMs;
1810
59
  unsigned backoff_max = kDefaultBackoffMaxMs;
1811
59
  if (options_mgr_->GetValue("CVMFS_MAX_RETRIES", &optarg))
1812
54
    max_retries = String2Uint64(optarg);
1813
59
  if (options_mgr_->GetValue("CVMFS_BACKOFF_INIT", &optarg))
1814
    backoff_init = String2Uint64(optarg) * 1000;
1815
59
  if (options_mgr_->GetValue("CVMFS_BACKOFF_MAX", &optarg))
1816
    backoff_max = String2Uint64(optarg) * 1000;
1817
59
  download_mgr_->SetRetryParameters(max_retries, backoff_init, backoff_max);
1818
1819
59
  if (options_mgr_->GetValue("CVMFS_LOW_SPEED_LIMIT", &optarg))
1820
    download_mgr_->SetLowSpeedLimit(String2Uint64(optarg));
1821
59
  if (options_mgr_->GetValue("CVMFS_PROXY_RESET_AFTER", &optarg))
1822
    download_mgr_->SetProxyGroupResetDelay(String2Uint64(optarg));
1823
59
  if (options_mgr_->GetValue("CVMFS_HOST_RESET_AFTER", &optarg))
1824
    download_mgr_->SetHostResetDelay(String2Uint64(optarg));
1825
1826



59
  if (options_mgr_->GetValue("CVMFS_FOLLOW_REDIRECTS", &optarg) &&
1827
      options_mgr_->IsOn(optarg))
1828
  {
1829
    download_mgr_->EnableRedirects();
1830
  }
1831



59
  if (options_mgr_->GetValue("CVMFS_SEND_INFO_HEADER", &optarg) &&
1832
      options_mgr_->IsOn(optarg))
1833
  {
1834
    download_mgr_->EnableInfoHeader();
1835
  }
1836
59
}
1837
1838
1839
57
void MountPoint::SetupInodeAnnotation() {
1840
57
  string optarg;
1841
1842
57
  inode_annotation_ = new catalog::InodeGenerationAnnotation();
1843
57
  if (options_mgr_->GetValue("CVMFS_INITIAL_GENERATION", &optarg)) {
1844
    inode_annotation_->IncGeneration(String2Uint64(optarg));
1845
  }
1846
1847

57
  if ((file_system_->type() == FileSystem::kFsFuse) &&
1848
      !file_system_->IsNfsSource())
1849
  {
1850
49
    catalog_mgr_->SetInodeAnnotation(inode_annotation_);
1851
  }
1852
57
}
1853
1854
1855
57
bool MountPoint::SetupOwnerMaps() {
1856
57
  string optarg;
1857
57
  catalog::OwnerMap uid_map;
1858
57
  catalog::OwnerMap gid_map;
1859
1860
57
  if (options_mgr_->GetValue("CVMFS_UID_MAP", &optarg)) {
1861
2
    if (!uid_map.Read(optarg)) {
1862
2
      boot_error_ = "failed to parse uid map " + optarg;
1863
2
      boot_status_ = loader::kFailOptions;
1864
2
      return false;
1865
    }
1866
  }
1867
55
  if (options_mgr_->GetValue("CVMFS_GID_MAP", &optarg)) {
1868
    if (!gid_map.Read(optarg)) {
1869
      boot_error_ = "failed to parse gid map " + optarg;
1870
      boot_status_ = loader::kFailOptions;
1871
      return false;
1872
    }
1873
  }
1874
55
  catalog_mgr_->SetOwnerMaps(uid_map, gid_map);
1875
1876
  // TODO(jblomer): make local to catalog manager
1877



55
  if (options_mgr_->GetValue("CVMFS_CLAIM_OWNERSHIP", &optarg) &&
1878
      options_mgr_->IsOn(optarg))
1879
  {
1880
    g_claim_ownership = true;
1881
  }
1882
1883
55
  return true;
1884

45
}