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
)) {
102 const char **newargv
;
104 vec_to_argv(argv
[0], args
, &newargc
, &newargv
);
106 // FUSE will chdir("/"); be ready.
107 g_ceph_context
->_conf
->set_val("chdir", "/");
108 g_ceph_context
->_conf
->apply_changes(NULL
);
110 // check for 32-bit arch
113 cerr
<< "WARNING: Ceph inode numbers are 64 bits wide, and FUSE on 32-bit kernels does" << std::endl
;
114 cerr
<< " not cope well with that situation. Expect to crash shortly." << std::endl
;
119 if (g_conf
->daemonize
) {
120 global_init_prefork(g_ceph_context
);
123 r
= forker
.prefork(err
);
124 if (r
< 0 || forker
.is_parent()) {
125 // Start log if current process is about to exit. Otherwise, we hit an assert
126 // in the Ceph context destructor.
127 g_ceph_context
->_log
->start();
130 cerr
<< "ceph-fuse " << err
<< std::endl
;
133 if (forker
.is_parent()) {
134 r
= forker
.parent_wait(err
);
136 cerr
<< "ceph-fuse " << err
<< std::endl
;
140 global_init_postfork_start(cct
.get());
144 common_init_finish(g_ceph_context
);
146 //cout << "child, mounting" << std::endl;
147 class RemountTest
: public Thread
{
151 RemountTest() : cfuse(NULL
), client(NULL
) {}
152 void init(CephFuse
*cf
, Client
*cl
) {
156 ~RemountTest() override
{}
157 void *entry() override
{
158 #if defined(__linux__)
159 int ver
= get_linux_version();
161 bool client_try_dentry_invalidate
= g_conf
->get_val
<bool>(
162 "client_try_dentry_invalidate");
163 bool can_invalidate_dentries
=
164 client_try_dentry_invalidate
&& ver
< KERNEL_VERSION(3, 18, 0);
165 int tr
= client
->test_dentry_handling(can_invalidate_dentries
);
166 bool client_die_on_failed_dentry_invalidate
= g_conf
->get_val
<bool>(
167 "client_die_on_failed_dentry_invalidate");
168 if (tr
!= 0 && client_die_on_failed_dentry_invalidate
) {
169 cerr
<< "ceph-fuse[" << getpid()
170 << "]: fuse failed dentry invalidate/remount test with error "
171 << cpp_strerror(tr
) << ", stopping" << std::endl
;
174 string mountpoint
= cfuse
->get_mount_point();
175 snprintf(buf
, sizeof(buf
), "fusermount -u -z %s", mountpoint
.c_str());
176 int umount_r
= system(buf
);
178 if (umount_r
!= -1) {
179 if (WIFEXITED(umount_r
)) {
180 umount_r
= WEXITSTATUS(umount_r
);
181 cerr
<< "got error " << umount_r
182 << " when unmounting Ceph on failed remount test!" << std::endl
;
184 cerr
<< "attempt to umount on failed remount test failed (on a signal?)" << std::endl
;
187 cerr
<< "system() invocation failed during remount test" << std::endl
;
191 return reinterpret_cast<void*>(tr
);
193 return reinterpret_cast<void*>(0);
200 Messenger
*messenger
= NULL
;
201 StandaloneClient
*client
;
205 void *tester_rp
= NULL
;
207 MonClient
*mc
= new MonClient(g_ceph_context
);
208 int r
= mc
->build_initial_monmap();
212 goto out_mc_start_failed
;
215 messenger
= Messenger::create_client_messenger(g_ceph_context
, "client");
216 messenger
->set_default_policy(Messenger::Policy::lossy_client(0));
217 messenger
->set_policy(entity_name_t::TYPE_MDS
,
218 Messenger::Policy::lossless_client(0));
220 client
= new StandaloneClient(messenger
, mc
);
222 client
->set_filer_flags(filer_flags
);
225 cfuse
= new CephFuse(client
, forker
.get_signal_fd());
227 r
= cfuse
->init(newargc
, newargv
);
229 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to initialize" << std::endl
;
230 goto out_messenger_start_failed
;
233 cerr
<< "ceph-fuse[" << getpid() << "]: starting ceph client" << std::endl
;
234 r
= messenger
->start();
236 cerr
<< "ceph-fuse[" << getpid() << "]: ceph messenger failed with " << cpp_strerror(-r
) << std::endl
;
237 goto out_messenger_start_failed
;
240 init_async_signal_handler();
241 register_async_signal_handler(SIGHUP
, sighup_handler
);
246 cerr
<< "ceph-fuse[" << getpid() << "]: ceph client failed with " << cpp_strerror(-r
) << std::endl
;
247 goto out_init_failed
;
250 client
->update_metadata("mount_point", cfuse
->get_mount_point());
251 perms
= client
->pick_my_perms();
253 // use my argc, argv (make sure you pass a mount point!)
254 r
= client
->mount(g_conf
->client_mountpoint
.c_str(), perms
,
255 g_ceph_context
->_conf
->fuse_require_active_mds
);
257 if (r
== CEPH_FUSE_NO_MDS_UP
)
258 cerr
<< "ceph-fuse[" << getpid() << "]: probably no MDS server is up?" << std::endl
;
259 cerr
<< "ceph-fuse[" << getpid() << "]: ceph mount failed with " << cpp_strerror(-r
) << std::endl
;
265 cerr
<< "ceph-fuse[" << getpid() << "]: fuse failed to start" << std::endl
;
266 goto out_client_unmount
;
269 cerr
<< "ceph-fuse[" << getpid() << "]: starting fuse" << std::endl
;
270 tester
.init(cfuse
, client
);
271 tester
.create("tester");
273 tester
.join(&tester_rp
);
274 tester_r
= static_cast<int>(reinterpret_cast<uint64_t>(tester_rp
));
275 cerr
<< "ceph-fuse[" << getpid() << "]: fuse finished with error " << r
276 << " and tester_r " << tester_r
<<std::endl
;
285 unregister_async_signal_handler(SIGHUP
, sighup_handler
);
286 shutdown_async_signal_handler();
288 // wait for messenger to finish
289 messenger
->shutdown();
291 out_messenger_start_failed
:
298 //cout << "child done" << std::endl;
299 return forker
.signal_exit(r
);