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
50 ceph::async::io_context_pool icp
;
52 static void fuse_usage()
54 const char* argv
[] = {
58 struct fuse_args args
= FUSE_ARGS_INIT(2, (char**)argv
);
59 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
60 struct fuse_cmdline_opts opts
= {};
61 if (fuse_parse_cmdline(&args
, &opts
) != -1) {
63 cout
<< "usage: " << argv
[0] << " [options] <mountpoint>\n\n";
64 cout
<< "FUSE options:\n";
71 if (fuse_parse_cmdline(&args
, nullptr, nullptr, nullptr) == -1) {
73 derr
<< "fuse_parse_cmdline failed." << dendl
;
75 ceph_assert(args
.allocated
);
76 fuse_opt_free_args(&args
);
82 "usage: ceph-fuse [-n client.username] [-m mon-ip-addr:mon-port] <mount point> [OPTIONS]\n"
83 " --client_mountpoint/-r <sub_directory>\n"
84 " use sub_directory as the mounted root, rather than the full Ceph tree.\n"
87 generic_client_usage();
90 int main(int argc
, const char **argv
, const char *envp
[]) {
92 //cerr << "ceph-fuse starting " << myrank << "/" << world << std::endl;
93 std::vector
<const char*> args
;
94 argv_to_vec(argc
, argv
, args
);
96 cerr
<< argv
[0] << ": -h or --help for usage" << std::endl
;
99 if (ceph_argparse_need_usage(args
)) {
104 std::map
<std::string
,std::string
> defaults
= {
106 { "chdir", "/" } // FUSE will chdir("/"); be ready.
109 auto cct
= global_init(&defaults
, args
, CEPH_ENTITY_TYPE_CLIENT
,
110 CODE_ENVIRONMENT_DAEMON
,
111 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS
);
113 for (auto i
= args
.begin(); i
!= args
.end();) {
114 if (ceph_argparse_double_dash(args
, i
)) {
116 } else if (ceph_argparse_flag(args
, i
, "--localize-reads", (char*)nullptr)) {
117 cerr
<< "setting CEPH_OSD_FLAG_LOCALIZE_READS" << std::endl
;
118 filer_flags
|= CEPH_OSD_FLAG_LOCALIZE_READS
;
119 } else if (ceph_argparse_flag(args
, i
, "-V", (char*)nullptr)) {
120 const char* tmpargv
[] = {
125 struct fuse_args fargs
= FUSE_ARGS_INIT(2, (char**)tmpargv
);
126 #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
127 struct fuse_cmdline_opts opts
= {};
128 if (fuse_parse_cmdline(&fargs
, &opts
) == -1) {
130 if (fuse_parse_cmdline(&fargs
, nullptr, nullptr, nullptr) == -1) {
132 derr
<< "fuse_parse_cmdline failed." << dendl
;
134 ceph_assert(fargs
.allocated
);
135 fuse_opt_free_args(&fargs
);
143 const char **newargv
;
145 vec_to_argv(argv
[0], args
, &newargc
, &newargv
);
147 // check for 32-bit arch
150 cerr
<< "WARNING: Ceph inode numbers are 64 bits wide, and FUSE on 32-bit kernels does" << std::endl
;
151 cerr
<< " not cope well with that situation. Expect to crash shortly." << std::endl
;
156 auto daemonize
= g_conf().get_val
<bool>("daemonize");
158 global_init_prefork(g_ceph_context
);
161 r
= forker
.prefork(err
);
162 if (r
< 0 || forker
.is_parent()) {
163 // Start log if current process is about to exit. Otherwise, we hit an assert
164 // in the Ceph context destructor.
165 g_ceph_context
->_log
->start();
168 cerr
<< "ceph-fuse " << err
<< std::endl
;
171 if (forker
.is_parent()) {
172 r
= forker
.parent_wait(err
);
174 cerr
<< "ceph-fuse " << err
<< std::endl
;
178 global_init_postfork_start(cct
.get());
182 common_init_finish(g_ceph_context
);
184 init_async_signal_handler();
185 register_async_signal_handler(SIGHUP
, sighup_handler
);
187 //cout << "child, mounting" << std::endl;
188 class RemountTest
: public Thread
{
192 RemountTest() : cfuse(nullptr), client(nullptr) {}
193 void init(CephFuse
*cf
, Client
*cl
) {
197 ~RemountTest() override
{}
198 void *entry() override
{
199 #if defined(__linux__)
200 int ver
= get_linux_version();
201 ceph_assert(ver
!= 0);
202 bool client_try_dentry_invalidate
= g_conf().get_val
<bool>(
203 "client_try_dentry_invalidate");
204 bool can_invalidate_dentries
=
205 client_try_dentry_invalidate
&& ver
< KERNEL_VERSION(3, 18, 0);
206 int tr
= client
->test_dentry_handling(can_invalidate_dentries
);
207 bool client_die_on_failed_dentry_invalidate
= g_conf().get_val
<bool>(
208 "client_die_on_failed_dentry_invalidate");
209 if (tr
!= 0 && client_die_on_failed_dentry_invalidate
) {
210 cerr
<< "ceph-fuse[" << getpid()
211 << "]: fuse failed dentry invalidate/remount test with error "
212 << cpp_strerror(tr
) << ", stopping" << std::endl
;
215 string mountpoint
= cfuse
->get_mount_point();
216 snprintf(buf
, sizeof(buf
), "fusermount -u -z %s", mountpoint
.c_str());
217 int umount_r
= system(buf
);
219 if (umount_r
!= -1) {
220 if (WIFEXITED(umount_r
)) {
221 umount_r
= WEXITSTATUS(umount_r
);
222 cerr
<< "got error " << umount_r
223 << " when unmounting Ceph on failed remount test!" << std::endl
;
225 cerr
<< "attempt to umount on failed remount test failed (on a signal?)" << std::endl
;
228 cerr
<< "system() invocation failed during remount test" << std::endl
;
232 return reinterpret_cast<void*>(tr
);
234 return reinterpret_cast<void*>(0);
241 Messenger
*messenger
= nullptr;
242 StandaloneClient
*client
;
246 void *tester_rp
= nullptr;
248 icp
.start(cct
->_conf
.get_val
<std::uint64_t>("client_asio_thread_count"));
249 MonClient
*mc
= new MonClient(g_ceph_context
, icp
);
250 int r
= mc
->build_initial_monmap();
252 cerr
<< "failed to generate initial mon list" << std::endl
;
256 goto out_mc_start_failed
;
259 messenger
= Messenger::create_client_messenger(g_ceph_context
, "client");
260 messenger
->set_default_policy(Messenger::Policy::lossy_client(0));
261 messenger
->set_policy(entity_name_t::TYPE_MDS
,
262 Messenger::Policy::lossless_client(0));
264 client
= new StandaloneClient(messenger
, mc
, icp
);
266 client
->set_filer_flags(filer_flags
);
269 cfuse
= new CephFuse(client
, forker
.get_signal_fd());
271 r
= cfuse
->init(newargc
, newargv
);
273 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to initialize" << std::endl
;
274 goto out_messenger_start_failed
;
277 cerr
<< "ceph-fuse[" << getpid() << "]: starting ceph client" << std::endl
;
278 r
= messenger
->start();
280 cerr
<< "ceph-fuse[" << getpid() << "]: ceph messenger failed with " << cpp_strerror(-r
) << std::endl
;
281 goto out_messenger_start_failed
;
287 cerr
<< "ceph-fuse[" << getpid() << "]: ceph client failed with " << cpp_strerror(-r
) << std::endl
;
288 goto out_init_failed
;
291 client
->update_metadata("mount_point", cfuse
->get_mount_point());
292 perms
= client
->pick_my_perms();
295 // use my argc, argv (make sure you pass a mount point!)
296 auto client_mountpoint
= g_conf().get_val
<std::string
>(
297 "client_mountpoint");
298 auto mountpoint
= client_mountpoint
.c_str();
299 auto fuse_require_active_mds
= g_conf().get_val
<bool>(
300 "fuse_require_active_mds");
301 r
= client
->mount(mountpoint
, perms
, fuse_require_active_mds
);
303 if (r
== CEPH_FUSE_NO_MDS_UP
) {
304 cerr
<< "ceph-fuse[" << getpid() << "]: probably no MDS server is up?" << std::endl
;
306 cerr
<< "ceph-fuse[" << getpid() << "]: ceph mount failed with " << cpp_strerror(-r
) << std::endl
;
314 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to start" << std::endl
;
315 goto out_client_unmount
;
318 cerr
<< "ceph-fuse[" << getpid() << "]: starting fuse" << std::endl
;
319 tester
.init(cfuse
, client
);
320 tester
.create("tester");
322 tester
.join(&tester_rp
);
323 tester_r
= static_cast<int>(reinterpret_cast<uint64_t>(tester_rp
));
324 cerr
<< "ceph-fuse[" << getpid() << "]: fuse finished with error " << r
325 << " and tester_r " << tester_r
<<std::endl
;
334 unregister_async_signal_handler(SIGHUP
, sighup_handler
);
335 shutdown_async_signal_handler();
337 // wait for messenger to finish
338 messenger
->shutdown();
340 out_messenger_start_failed
:
351 //cout << "child done" << std::endl;
352 return forker
.signal_exit(r
);