1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
16 #include <sys/utsname.h>
21 #include "common/async/context_pool.h"
22 #include "common/config.h"
23 #include "common/errno.h"
25 #include "client/Client.h"
26 #include "client/fuse_ll.h"
28 #include "msg/Messenger.h"
30 #include "mon/MonClient.h"
32 #include "common/Timer.h"
33 #include "common/ceph_argparse.h"
34 #if defined(__linux__)
35 #include "common/linux_version.h"
37 #include "global/global_init.h"
38 #include "global/signal_handler.h"
39 #include "common/Preforker.h"
40 #include "common/safe_io.h"
42 #include <sys/types.h>
45 #include "include/ceph_fuse.h"
46 #include <fuse_lowlevel.h>
48 #define dout_context g_ceph_context
52 ceph::async::io_context_pool icp
;
54 static void fuse_usage()
56 const char* argv
[] = {
60 struct fuse_args args
= FUSE_ARGS_INIT(2, (char**)argv
);
61 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
62 struct fuse_cmdline_opts opts
= {};
63 if (fuse_parse_cmdline(&args
, &opts
) != -1) {
65 cout
<< "usage: " << argv
[0] << " [options] <mountpoint>\n\n";
66 cout
<< "FUSE options:\n";
73 if (fuse_parse_cmdline(&args
, nullptr, nullptr, nullptr) == -1) {
75 derr
<< "fuse_parse_cmdline failed." << dendl
;
77 ceph_assert(args
.allocated
);
78 fuse_opt_free_args(&args
);
84 "usage: ceph-fuse [-n client.username] [-m mon-ip-addr:mon-port] <mount point> [OPTIONS]\n"
85 " --client_mountpoint/-r <sub_directory>\n"
86 " use sub_directory as the mounted root, rather than the full Ceph tree.\n"
89 generic_client_usage();
92 int main(int argc
, const char **argv
, const char *envp
[]) {
94 //cerr << "ceph-fuse starting " << myrank << "/" << world << std::endl;
95 auto args
= argv_to_vec(argc
, argv
);
97 cerr
<< argv
[0] << ": -h or --help for usage" << std::endl
;
100 if (ceph_argparse_need_usage(args
)) {
105 std::map
<std::string
,std::string
> defaults
= {
107 { "chdir", "/" } // FUSE will chdir("/"); be ready.
110 auto cct
= global_init(&defaults
, args
, CEPH_ENTITY_TYPE_CLIENT
,
111 CODE_ENVIRONMENT_DAEMON
,
112 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS
);
114 for (auto i
= args
.begin(); i
!= args
.end();) {
115 if (ceph_argparse_double_dash(args
, i
)) {
117 } else if (ceph_argparse_flag(args
, i
, "--localize-reads", (char*)nullptr)) {
118 cerr
<< "setting CEPH_OSD_FLAG_LOCALIZE_READS" << std::endl
;
119 filer_flags
|= CEPH_OSD_FLAG_LOCALIZE_READS
;
120 } else if (ceph_argparse_flag(args
, i
, "-V", (char*)nullptr)) {
121 const char* tmpargv
[] = {
126 struct fuse_args fargs
= FUSE_ARGS_INIT(2, (char**)tmpargv
);
127 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
128 struct fuse_cmdline_opts opts
= {};
129 if (fuse_parse_cmdline(&fargs
, &opts
) == -1) {
131 if (fuse_parse_cmdline(&fargs
, nullptr, nullptr, nullptr) == -1) {
133 derr
<< "fuse_parse_cmdline failed." << dendl
;
135 ceph_assert(fargs
.allocated
);
136 fuse_opt_free_args(&fargs
);
144 const char **newargv
;
146 vec_to_argv(argv
[0], args
, &newargc
, &newargv
);
148 // check for 32-bit arch
151 cerr
<< "WARNING: Ceph inode numbers are 64 bits wide, and FUSE on 32-bit kernels does" << std::endl
;
152 cerr
<< " not cope well with that situation. Expect to crash shortly." << std::endl
;
157 auto daemonize
= g_conf().get_val
<bool>("daemonize");
159 global_init_prefork(g_ceph_context
);
162 r
= forker
.prefork(err
);
163 if (r
< 0 || forker
.is_parent()) {
164 // Start log if current process is about to exit. Otherwise, we hit an assert
165 // in the Ceph context destructor.
166 g_ceph_context
->_log
->start();
169 cerr
<< "ceph-fuse " << err
<< std::endl
;
172 if (forker
.is_parent()) {
173 r
= forker
.parent_wait(err
);
175 cerr
<< "ceph-fuse " << err
<< std::endl
;
179 global_init_postfork_start(cct
.get());
183 common_init_finish(g_ceph_context
);
185 init_async_signal_handler();
186 register_async_signal_handler(SIGHUP
, sighup_handler
);
188 //cout << "child, mounting" << std::endl;
189 class RemountTest
: public Thread
{
193 RemountTest() : cfuse(nullptr), client(nullptr) {}
194 void init(CephFuse
*cf
, Client
*cl
) {
198 ~RemountTest() override
{}
199 void *entry() override
{
200 #if defined(__linux__)
201 bool can_invalidate_dentries
= g_conf().get_val
<bool>(
202 "client_try_dentry_invalidate");
203 uint64_t max_retries
= g_conf().get_val
<uint64_t>(
204 "client_max_retries_on_remount_failure");
205 std::pair
<int, bool> test_result
;
209 test_result
= client
->test_dentry_handling(can_invalidate_dentries
);
210 tr
= test_result
.first
;
214 } while (++i
< max_retries
&& tr
);
216 bool abort_on_failure
= test_result
.second
;
217 bool client_die_on_failed_dentry_invalidate
= g_conf().get_val
<bool>(
218 "client_die_on_failed_dentry_invalidate");
219 if (tr
!= 0 && client_die_on_failed_dentry_invalidate
) {
220 cerr
<< "ceph-fuse[" << getpid()
221 << "]: fuse failed dentry invalidate/remount test with error "
222 << cpp_strerror(tr
) << ", stopping" << std::endl
;
225 string mountpoint
= cfuse
->get_mount_point();
226 snprintf(buf
, sizeof(buf
), "fusermount -u -z %s", mountpoint
.c_str());
227 int umount_r
= system(buf
);
229 if (umount_r
!= -1) {
230 if (WIFEXITED(umount_r
)) {
231 umount_r
= WEXITSTATUS(umount_r
);
232 cerr
<< "got error " << umount_r
233 << " when unmounting Ceph on failed remount test!" << std::endl
;
235 cerr
<< "attempt to umount on failed remount test failed (on a signal?)" << std::endl
;
238 cerr
<< "system() invocation failed during remount test" << std::endl
;
242 if(abort_on_failure
) {
245 return reinterpret_cast<void*>(tr
);
247 return reinterpret_cast<void*>(0);
254 Messenger
*messenger
= nullptr;
255 StandaloneClient
*client
;
259 void *tester_rp
= nullptr;
261 icp
.start(cct
->_conf
.get_val
<std::uint64_t>("client_asio_thread_count"));
262 MonClient
*mc
= new MonClient(g_ceph_context
, icp
);
263 int r
= mc
->build_initial_monmap();
265 cerr
<< "failed to generate initial mon list" << std::endl
;
269 goto out_mc_start_failed
;
272 messenger
= Messenger::create_client_messenger(g_ceph_context
, "client");
273 messenger
->set_default_policy(Messenger::Policy::lossy_client(0));
274 messenger
->set_policy(entity_name_t::TYPE_MDS
,
275 Messenger::Policy::lossless_client(0));
277 client
= new StandaloneClient(messenger
, mc
, icp
);
279 client
->set_filer_flags(filer_flags
);
282 cfuse
= new CephFuse(client
, forker
.get_signal_fd());
284 r
= cfuse
->init(newargc
, newargv
);
286 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to initialize" << std::endl
;
287 goto out_messenger_start_failed
;
290 cerr
<< "ceph-fuse[" << getpid() << "]: starting ceph client" << std::endl
;
291 r
= messenger
->start();
293 cerr
<< "ceph-fuse[" << getpid() << "]: ceph messenger failed with " << cpp_strerror(-r
) << std::endl
;
294 goto out_messenger_start_failed
;
300 cerr
<< "ceph-fuse[" << getpid() << "]: ceph client failed with " << cpp_strerror(-r
) << std::endl
;
301 goto out_init_failed
;
304 client
->update_metadata("mount_point", cfuse
->get_mount_point());
305 perms
= client
->pick_my_perms();
308 // use my argc, argv (make sure you pass a mount point!)
309 auto client_mountpoint
= g_conf().get_val
<std::string
>(
310 "client_mountpoint");
311 auto mountpoint
= client_mountpoint
.c_str();
312 auto fuse_require_active_mds
= g_conf().get_val
<bool>(
313 "fuse_require_active_mds");
314 r
= client
->mount(mountpoint
, perms
, fuse_require_active_mds
);
316 if (r
== CEPH_FUSE_NO_MDS_UP
) {
317 cerr
<< "ceph-fuse[" << getpid() << "]: probably no MDS server is up?" << std::endl
;
319 cerr
<< "ceph-fuse[" << getpid() << "]: ceph mount failed with " << cpp_strerror(-r
) << std::endl
;
327 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to start" << std::endl
;
328 goto out_client_unmount
;
331 cerr
<< "ceph-fuse[" << getpid() << "]: starting fuse" << std::endl
;
332 tester
.init(cfuse
, client
);
333 tester
.create("tester");
335 tester
.join(&tester_rp
);
336 tester_r
= static_cast<int>(reinterpret_cast<uint64_t>(tester_rp
));
337 cerr
<< "ceph-fuse[" << getpid() << "]: fuse finished with error " << r
338 << " and tester_r " << tester_r
<<std::endl
;
347 unregister_async_signal_handler(SIGHUP
, sighup_handler
);
348 shutdown_async_signal_handler();
350 // wait for messenger to finish
351 messenger
->shutdown();
353 out_messenger_start_failed
:
364 //cout << "child done" << std::endl;
365 return forker
.signal_exit(r
);