]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> | |
7 | * | |
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. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <sys/stat.h> | |
16 | #include <sys/utsname.h> | |
17 | #include <iostream> | |
18 | #include <string> | |
19 | using namespace std; | |
20 | ||
21 | #include "common/config.h" | |
22 | #include "common/errno.h" | |
23 | ||
24 | #include "client/Client.h" | |
25 | #include "client/fuse_ll.h" | |
26 | ||
27 | #include "msg/Messenger.h" | |
28 | ||
29 | #include "mon/MonClient.h" | |
30 | ||
31 | #include "common/Timer.h" | |
32 | #include "common/ceph_argparse.h" | |
33 | #if defined(__linux__) | |
34 | #include "common/linux_version.h" | |
35 | #endif | |
36 | #include "global/global_init.h" | |
37 | #include "global/signal_handler.h" | |
38 | #include "common/Preforker.h" | |
39 | #include "common/safe_io.h" | |
40 | ||
41 | #include <sys/types.h> | |
42 | #include <fcntl.h> | |
43 | ||
44 | #include <fuse.h> | |
45 | ||
46 | #define dout_context g_ceph_context | |
47 | ||
48 | static void fuse_usage() | |
49 | { | |
50 | const char* argv[] = { | |
51 | "ceph-fuse", | |
52 | "-h", | |
53 | }; | |
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; | |
57 | } | |
58 | assert(args.allocated); | |
59 | fuse_opt_free_args(&args); | |
60 | } | |
61 | ||
62 | void usage() | |
63 | { | |
64 | cout << | |
c07f9fc5 FG |
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" | |
7c673cae FG |
68 | "\n"; |
69 | fuse_usage(); | |
70 | generic_client_usage(); | |
71 | } | |
72 | ||
73 | int main(int argc, const char **argv, const char *envp[]) { | |
74 | int filer_flags = 0; | |
75 | //cerr << "ceph-fuse starting " << myrank << "/" << world << std::endl; | |
76 | std::vector<const char*> args; | |
77 | argv_to_vec(argc, argv, args); | |
78 | if (args.empty()) { | |
79 | usage(); | |
80 | } | |
81 | env_to_vec(args); | |
82 | ||
83 | std::vector<const char*> def_args{"--pid-file="}; | |
84 | ||
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)) { | |
90 | break; | |
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)) { | |
95 | usage(); | |
96 | } else { | |
97 | ++i; | |
98 | } | |
99 | } | |
100 | ||
101 | // args for fuse | |
102 | const char **newargv; | |
103 | int newargc; | |
104 | vec_to_argv(argv[0], args, &newargc, &newargv); | |
105 | ||
106 | // FUSE will chdir("/"); be ready. | |
107 | g_ceph_context->_conf->set_val("chdir", "/"); | |
108 | g_ceph_context->_conf->apply_changes(NULL); | |
109 | ||
110 | // check for 32-bit arch | |
111 | #ifndef __LP64__ | |
112 | cerr << std::endl; | |
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; | |
115 | cerr << std::endl; | |
116 | #endif | |
117 | ||
118 | Preforker forker; | |
119 | if (g_conf->daemonize) { | |
120 | global_init_prefork(g_ceph_context); | |
121 | int r; | |
122 | string err; | |
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(); | |
128 | } | |
129 | if (r < 0) { | |
130 | cerr << "ceph-fuse " << err << std::endl; | |
131 | return r; | |
132 | } | |
133 | if (forker.is_parent()) { | |
134 | r = forker.parent_wait(err); | |
135 | if (r < 0) { | |
136 | cerr << "ceph-fuse " << err << std::endl; | |
137 | } | |
138 | return r; | |
139 | } | |
140 | global_init_postfork_start(cct.get()); | |
141 | } | |
142 | ||
143 | { | |
144 | common_init_finish(g_ceph_context); | |
145 | ||
146 | //cout << "child, mounting" << std::endl; | |
147 | class RemountTest : public Thread { | |
148 | public: | |
149 | CephFuse *cfuse; | |
150 | Client *client; | |
151 | RemountTest() : cfuse(NULL), client(NULL) {} | |
152 | void init(CephFuse *cf, Client *cl) { | |
153 | cfuse = cf; | |
154 | client = cl; | |
155 | } | |
156 | ~RemountTest() override {} | |
157 | void *entry() override { | |
158 | #if defined(__linux__) | |
159 | int ver = get_linux_version(); | |
160 | assert(ver != 0); | |
b32b8144 FG |
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); | |
7c673cae | 165 | int tr = client->test_dentry_handling(can_invalidate_dentries); |
b32b8144 FG |
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) { | |
7c673cae FG |
169 | cerr << "ceph-fuse[" << getpid() |
170 | << "]: fuse failed dentry invalidate/remount test with error " | |
171 | << cpp_strerror(tr) << ", stopping" << std::endl; | |
172 | ||
173 | char buf[5050]; | |
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); | |
177 | if (umount_r) { | |
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; | |
183 | } else { | |
184 | cerr << "attempt to umount on failed remount test failed (on a signal?)" << std::endl; | |
185 | } | |
186 | } else { | |
187 | cerr << "system() invocation failed during remount test" << std::endl; | |
188 | } | |
189 | } | |
190 | } | |
191 | return reinterpret_cast<void*>(tr); | |
192 | #else | |
193 | return reinterpret_cast<void*>(0); | |
194 | #endif | |
195 | } | |
196 | } tester; | |
197 | ||
198 | ||
199 | // get monmap | |
200 | Messenger *messenger = NULL; | |
201 | StandaloneClient *client; | |
202 | CephFuse *cfuse; | |
203 | UserPerm perms; | |
204 | int tester_r = 0; | |
205 | void *tester_rp = NULL; | |
206 | ||
207 | MonClient *mc = new MonClient(g_ceph_context); | |
208 | int r = mc->build_initial_monmap(); | |
209 | if (r == -EINVAL) | |
210 | usage(); | |
211 | if (r < 0) | |
212 | goto out_mc_start_failed; | |
213 | ||
214 | // start up network | |
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)); | |
219 | ||
220 | client = new StandaloneClient(messenger, mc); | |
221 | if (filer_flags) { | |
222 | client->set_filer_flags(filer_flags); | |
223 | } | |
224 | ||
225 | cfuse = new CephFuse(client, forker.get_signal_fd()); | |
226 | ||
227 | r = cfuse->init(newargc, newargv); | |
228 | if (r != 0) { | |
229 | cerr << "ceph-fuse[" << getpid() << "]: fuse failed to initialize" << std::endl; | |
230 | goto out_messenger_start_failed; | |
231 | } | |
232 | ||
233 | cerr << "ceph-fuse[" << getpid() << "]: starting ceph client" << std::endl; | |
234 | r = messenger->start(); | |
235 | if (r < 0) { | |
236 | cerr << "ceph-fuse[" << getpid() << "]: ceph messenger failed with " << cpp_strerror(-r) << std::endl; | |
237 | goto out_messenger_start_failed; | |
238 | } | |
239 | ||
240 | init_async_signal_handler(); | |
241 | register_async_signal_handler(SIGHUP, sighup_handler); | |
242 | ||
243 | // start client | |
244 | r = client->init(); | |
245 | if (r < 0) { | |
246 | cerr << "ceph-fuse[" << getpid() << "]: ceph client failed with " << cpp_strerror(-r) << std::endl; | |
247 | goto out_init_failed; | |
248 | } | |
249 | ||
250 | client->update_metadata("mount_point", cfuse->get_mount_point()); | |
251 | perms = client->pick_my_perms(); | |
252 | // start up fuse | |
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); | |
256 | if (r < 0) { | |
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; | |
260 | goto out_shutdown; | |
261 | } | |
262 | ||
263 | r = cfuse->start(); | |
264 | if (r != 0) { | |
265 | cerr << "ceph-fuse[" << getpid() << "]: fuse failed to start" << std::endl; | |
266 | goto out_client_unmount; | |
267 | } | |
268 | ||
269 | cerr << "ceph-fuse[" << getpid() << "]: starting fuse" << std::endl; | |
270 | tester.init(cfuse, client); | |
271 | tester.create("tester"); | |
272 | r = cfuse->loop(); | |
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; | |
277 | ||
278 | ||
279 | out_client_unmount: | |
280 | client->unmount(); | |
281 | cfuse->finalize(); | |
282 | out_shutdown: | |
283 | client->shutdown(); | |
284 | out_init_failed: | |
285 | unregister_async_signal_handler(SIGHUP, sighup_handler); | |
286 | shutdown_async_signal_handler(); | |
287 | ||
288 | // wait for messenger to finish | |
289 | messenger->shutdown(); | |
290 | messenger->wait(); | |
291 | out_messenger_start_failed: | |
292 | delete cfuse; | |
293 | delete client; | |
294 | delete messenger; | |
295 | out_mc_start_failed: | |
296 | free(newargv); | |
297 | delete mc; | |
298 | //cout << "child done" << std::endl; | |
299 | return forker.signal_exit(r); | |
300 | } | |
301 | } | |
302 |