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/config.h"
22 #include "common/errno.h"
24 #include "client/Client.h"
25 #include "client/fuse_ll.h"
27 #include "msg/Messenger.h"
29 #include "mon/MonClient.h"
31 #include "common/Timer.h"
32 #include "common/ceph_argparse.h"
33 #if defined(__linux__)
34 #include "common/linux_version.h"
36 #include "global/global_init.h"
37 #include "global/signal_handler.h"
38 #include "common/Preforker.h"
39 #include "common/safe_io.h"
41 #include <sys/types.h>
46 #define dout_context g_ceph_context
48 static void fuse_usage()
50 const char* argv
[] = {
54 struct fuse_args args
= FUSE_ARGS_INIT(2, (char**)argv
);
55 if (fuse_parse_cmdline(&args
, NULL
, NULL
, NULL
) == -1) {
56 derr
<< "fuse_parse_cmdline failed." << dendl
;
58 assert(args
.allocated
);
59 fuse_opt_free_args(&args
);
65 "usage: ceph-fuse [-n client.username] [-m mon-ip-addr:mon-port] <mount point> [OPTIONS]\n"
66 " --client_mountpoint/-r <sub_directory>\n"
67 " use sub_directory as the mounted root, rather than the full Ceph tree.\n"
70 generic_client_usage();
73 int main(int argc
, const char **argv
, const char *envp
[]) {
75 //cerr << "ceph-fuse starting " << myrank << "/" << world << std::endl;
76 std::vector
<const char*> args
;
77 argv_to_vec(argc
, argv
, args
);
83 std::vector
<const char*> def_args
{"--pid-file="};
85 auto cct
= global_init(&def_args
, args
, CEPH_ENTITY_TYPE_CLIENT
,
86 CODE_ENVIRONMENT_DAEMON
,
87 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS
);
88 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
89 if (ceph_argparse_double_dash(args
, i
)) {
91 } else if (ceph_argparse_flag(args
, i
, "--localize-reads", (char*)NULL
)) {
92 cerr
<< "setting CEPH_OSD_FLAG_LOCALIZE_READS" << std::endl
;
93 filer_flags
|= CEPH_OSD_FLAG_LOCALIZE_READS
;
94 } else if (ceph_argparse_flag(args
, i
, "-h", "--help", (char*)NULL
)) {
96 } else if (ceph_argparse_flag(args
, i
, "-V", (char*)nullptr)) {
97 const char* tmpargv
[] = {
102 struct fuse_args fargs
= FUSE_ARGS_INIT(2, (char**)tmpargv
);
103 if (fuse_parse_cmdline(&fargs
, nullptr, nullptr, nullptr) == -1) {
104 derr
<< "fuse_parse_cmdline failed." << dendl
;
106 assert(fargs
.allocated
);
107 fuse_opt_free_args(&fargs
);
115 const char **newargv
;
117 vec_to_argv(argv
[0], args
, &newargc
, &newargv
);
119 // FUSE will chdir("/"); be ready.
120 g_ceph_context
->_conf
->set_val("chdir", "/");
121 g_ceph_context
->_conf
->apply_changes(NULL
);
123 // check for 32-bit arch
126 cerr
<< "WARNING: Ceph inode numbers are 64 bits wide, and FUSE on 32-bit kernels does" << std::endl
;
127 cerr
<< " not cope well with that situation. Expect to crash shortly." << std::endl
;
132 if (g_conf
->daemonize
) {
133 global_init_prefork(g_ceph_context
);
136 r
= forker
.prefork(err
);
137 if (r
< 0 || forker
.is_parent()) {
138 // Start log if current process is about to exit. Otherwise, we hit an assert
139 // in the Ceph context destructor.
140 g_ceph_context
->_log
->start();
143 cerr
<< "ceph-fuse " << err
<< std::endl
;
146 if (forker
.is_parent()) {
147 r
= forker
.parent_wait(err
);
149 cerr
<< "ceph-fuse " << err
<< std::endl
;
153 global_init_postfork_start(cct
.get());
157 common_init_finish(g_ceph_context
);
159 //cout << "child, mounting" << std::endl;
160 class RemountTest
: public Thread
{
164 RemountTest() : cfuse(NULL
), client(NULL
) {}
165 void init(CephFuse
*cf
, Client
*cl
) {
169 ~RemountTest() override
{}
170 void *entry() override
{
171 #if defined(__linux__)
172 int ver
= get_linux_version();
174 bool client_try_dentry_invalidate
= g_conf
->get_val
<bool>(
175 "client_try_dentry_invalidate");
176 bool can_invalidate_dentries
=
177 client_try_dentry_invalidate
&& ver
< KERNEL_VERSION(3, 18, 0);
178 int tr
= client
->test_dentry_handling(can_invalidate_dentries
);
179 bool client_die_on_failed_dentry_invalidate
= g_conf
->get_val
<bool>(
180 "client_die_on_failed_dentry_invalidate");
181 if (tr
!= 0 && client_die_on_failed_dentry_invalidate
) {
182 cerr
<< "ceph-fuse[" << getpid()
183 << "]: fuse failed dentry invalidate/remount test with error "
184 << cpp_strerror(tr
) << ", stopping" << std::endl
;
187 string mountpoint
= cfuse
->get_mount_point();
188 snprintf(buf
, sizeof(buf
), "fusermount -u -z %s", mountpoint
.c_str());
189 int umount_r
= system(buf
);
191 if (umount_r
!= -1) {
192 if (WIFEXITED(umount_r
)) {
193 umount_r
= WEXITSTATUS(umount_r
);
194 cerr
<< "got error " << umount_r
195 << " when unmounting Ceph on failed remount test!" << std::endl
;
197 cerr
<< "attempt to umount on failed remount test failed (on a signal?)" << std::endl
;
200 cerr
<< "system() invocation failed during remount test" << std::endl
;
204 return reinterpret_cast<void*>(tr
);
206 return reinterpret_cast<void*>(0);
213 Messenger
*messenger
= NULL
;
214 StandaloneClient
*client
;
218 void *tester_rp
= NULL
;
220 MonClient
*mc
= new MonClient(g_ceph_context
);
221 int r
= mc
->build_initial_monmap();
225 goto out_mc_start_failed
;
228 messenger
= Messenger::create_client_messenger(g_ceph_context
, "client");
229 messenger
->set_default_policy(Messenger::Policy::lossy_client(0));
230 messenger
->set_policy(entity_name_t::TYPE_MDS
,
231 Messenger::Policy::lossless_client(0));
233 client
= new StandaloneClient(messenger
, mc
);
235 client
->set_filer_flags(filer_flags
);
238 cfuse
= new CephFuse(client
, forker
.get_signal_fd());
240 r
= cfuse
->init(newargc
, newargv
);
242 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to initialize" << std::endl
;
243 goto out_messenger_start_failed
;
246 cerr
<< "ceph-fuse[" << getpid() << "]: starting ceph client" << std::endl
;
247 r
= messenger
->start();
249 cerr
<< "ceph-fuse[" << getpid() << "]: ceph messenger failed with " << cpp_strerror(-r
) << std::endl
;
250 goto out_messenger_start_failed
;
253 init_async_signal_handler();
254 register_async_signal_handler(SIGHUP
, sighup_handler
);
259 cerr
<< "ceph-fuse[" << getpid() << "]: ceph client failed with " << cpp_strerror(-r
) << std::endl
;
260 goto out_init_failed
;
263 client
->update_metadata("mount_point", cfuse
->get_mount_point());
264 perms
= client
->pick_my_perms();
266 // use my argc, argv (make sure you pass a mount point!)
267 r
= client
->mount(g_conf
->client_mountpoint
.c_str(), perms
,
268 g_ceph_context
->_conf
->fuse_require_active_mds
);
270 if (r
== CEPH_FUSE_NO_MDS_UP
) {
271 cerr
<< "ceph-fuse[" << getpid() << "]: probably no MDS server is up?" << std::endl
;
273 cerr
<< "ceph-fuse[" << getpid() << "]: ceph mount failed with " << cpp_strerror(-r
) << std::endl
;r
= EXIT_FAILURE
;
280 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to start" << std::endl
;
281 goto out_client_unmount
;
284 cerr
<< "ceph-fuse[" << getpid() << "]: starting fuse" << std::endl
;
285 tester
.init(cfuse
, client
);
286 tester
.create("tester");
288 tester
.join(&tester_rp
);
289 tester_r
= static_cast<int>(reinterpret_cast<uint64_t>(tester_rp
));
290 cerr
<< "ceph-fuse[" << getpid() << "]: fuse finished with error " << r
291 << " and tester_r " << tester_r
<<std::endl
;
300 unregister_async_signal_handler(SIGHUP
, sighup_handler
);
301 shutdown_async_signal_handler();
303 // wait for messenger to finish
304 messenger
->shutdown();
306 out_messenger_start_failed
:
313 //cout << "child done" << std::endl;
314 return forker
.signal_exit(r
);