]>
git.proxmox.com Git - ceph.git/blob - ceph/src/tools/cephfs/Dumper.cc
73054c335ff4520f5d72d93748709334829b1c01
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) 2010 Greg Farnum <gregf@hq.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.
15 #ifndef _BACKWARD_BACKWARD_WARNING_H
16 #define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_*
19 #include "include/compat.h"
20 #include "include/fs_types.h"
21 #include "common/entity_name.h"
22 #include "common/errno.h"
23 #include "common/safe_io.h"
24 #include "mds/mdstypes.h"
25 #include "mds/LogEvent.h"
26 #include "mds/JournalPointer.h"
27 #include "osdc/Journaler.h"
31 #define dout_context g_ceph_context
32 #define dout_subsys ceph_subsys_mds
34 #define HEADER_LEN 4096
36 int Dumper::init(mds_role_t role_
)
40 int r
= MDSUtility::init();
45 auto fs
= fsmap
->get_filesystem(role
.fscid
);
46 assert(fs
!= nullptr);
48 JournalPointer
jp(role
.rank
, fs
->mds_map
.get_metadata_pool());
49 int jp_load_result
= jp
.load(objecter
);
50 if (jp_load_result
!= 0) {
51 std::cerr
<< "Error loading journal: " << cpp_strerror(jp_load_result
) << std::endl
;
52 return jp_load_result
;
60 int Dumper::recover_journal(Journaler
*journaler
)
64 journaler
->recover(&cond
);
66 int const r
= cond
.wait();
69 derr
<< "error on recovery: " << cpp_strerror(r
) << dendl
;
72 dout(10) << "completed journal recovery" << dendl
;
78 int Dumper::dump(const char *dump_file
)
82 auto fs
= fsmap
->get_filesystem(role
.fscid
);
83 assert(fs
!= nullptr);
85 Journaler
journaler("dumper", ino
, fs
->mds_map
.get_metadata_pool(),
86 CEPH_FS_ONDISK_MAGIC
, objecter
, 0, 0,
88 r
= recover_journal(&journaler
);
92 uint64_t start
= journaler
.get_read_pos();
93 uint64_t end
= journaler
.get_write_pos();
94 uint64_t len
= end
-start
;
96 Filer
filer(objecter
, &finisher
);
98 cout
<< "journal is " << start
<< "~" << len
<< std::endl
;
100 int fd
= ::open(dump_file
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
102 // include an informative header
103 char buf
[HEADER_LEN
];
104 memset(buf
, 0, sizeof(buf
));
105 snprintf(buf
, HEADER_LEN
, "Ceph mds%d journal dump\n start offset %llu (0x%llx)\n length %llu (0x%llx)\n write_pos %llu (0x%llx)\n format %llu\n trimmed_pos %llu (0x%llx)\n%c",
107 (unsigned long long)start
, (unsigned long long)start
,
108 (unsigned long long)len
, (unsigned long long)len
,
109 (unsigned long long)journaler
.last_committed
.write_pos
, (unsigned long long)journaler
.last_committed
.write_pos
,
110 (unsigned long long)journaler
.last_committed
.stream_format
,
111 (unsigned long long)journaler
.last_committed
.trimmed_pos
, (unsigned long long)journaler
.last_committed
.trimmed_pos
,
113 r
= safe_write(fd
, buf
, sizeof(buf
));
115 derr
<< "Error " << r
<< " (" << cpp_strerror(r
) << ") writing journal file header" << dendl
;
121 off64_t seeked
= ::lseek64(fd
, start
, SEEK_SET
);
122 if (seeked
== (off64_t
)-1) {
124 derr
<< "Error " << r
<< " (" << cpp_strerror(r
) << ") seeking to 0x" << std::hex
<< start
<< std::dec
<< dendl
;
130 // Read and write 32MB chunks. Slower than it could be because we're not
131 // streaming, but that's okay because this is just a debug/disaster tool.
132 const uint32_t chunk_size
= 32 * 1024 * 1024;
134 for (uint64_t pos
= start
; pos
< start
+ len
; pos
+= chunk_size
) {
136 dout(10) << "Reading at pos=0x" << std::hex
<< pos
<< std::dec
<< dendl
;
138 const uint32_t read_size
= MIN(chunk_size
, end
- pos
);
142 filer
.read(ino
, &journaler
.get_layout(), CEPH_NOSNAP
,
143 pos
, read_size
, &bl
, 0, &cond
);
147 derr
<< "Error " << r
<< " (" << cpp_strerror(r
) << ") reading "
148 "journal at offset 0x" << std::hex
<< pos
<< std::dec
<< dendl
;
152 dout(10) << "Got 0x" << std::hex
<< bl
.length() << std::dec
153 << " bytes" << dendl
;
157 derr
<< "Error " << r
<< " (" << cpp_strerror(r
) << ") writing journal file" << dendl
;
166 derr
<< "Error " << r
<< " (" << cpp_strerror(r
) << ") closing journal file" << dendl
;
170 cout
<< "wrote " << len
<< " bytes at offset " << start
<< " to " << dump_file
<< "\n"
171 << "NOTE: this is a _sparse_ file; you can\n"
172 << "\t$ tar cSzf " << dump_file
<< ".tgz " << dump_file
<< "\n"
173 << " to efficiently compress it while preserving sparseness." << std::endl
;
177 derr
<< "unable to open " << dump_file
<< ": " << cpp_strerror(err
) << dendl
;
182 int Dumper::undump(const char *dump_file
)
184 cout
<< "undump " << dump_file
<< std::endl
;
186 auto fs
= fsmap
->get_filesystem(role
.fscid
);
187 assert(fs
!= nullptr);
190 int fd
= ::open(dump_file
, O_RDONLY
);
193 derr
<< "couldn't open " << dump_file
<< ": " << cpp_strerror(r
) << dendl
;
197 // Ceph mds0 journal dump
198 // start offset 232401996 (0xdda2c4c)
199 // length 1097504 (0x10bf20)
201 char buf
[HEADER_LEN
];
202 r
= safe_read(fd
, buf
, sizeof(buf
));
204 VOID_TEMP_FAILURE_RETRY(::close(fd
));
208 long long unsigned start
, len
, write_pos
, format
, trimmed_pos
;
209 sscanf(strstr(buf
, "start offset"), "start offset %llu", &start
);
210 sscanf(strstr(buf
, "length"), "length %llu", &len
);
211 sscanf(strstr(buf
, "write_pos"), "write_pos %llu", &write_pos
);
212 sscanf(strstr(buf
, "format"), "format %llu", &format
);
213 if (strstr(buf
, "trimmed_pos")) {
214 sscanf(strstr(buf
, "trimmed_pos"), "trimmed_pos %llu", &trimmed_pos
);
216 // Old format dump, any untrimmed objects before expire_pos will
217 // be discarded as trash.
218 trimmed_pos
= start
- (start
% file_layout_t::get_default().object_size
);
221 if (trimmed_pos
> start
) {
222 derr
<< std::hex
<< "Invalid header (trimmed 0x" << trimmed_pos
223 << " > expire 0x" << start
<< std::dec
<< dendl
;
228 if (start
> write_pos
) {
229 derr
<< std::hex
<< "Invalid header (expire 0x" << start
230 << " > write 0x" << write_pos
<< std::dec
<< dendl
;
235 cout
<< "start " << start
<<
237 " write_pos " << write_pos
<<
238 " format " << format
<<
239 " trimmed_pos " << trimmed_pos
<< std::endl
;
242 h
.trimmed_pos
= trimmed_pos
;
243 h
.expire_pos
= start
;
244 h
.write_pos
= write_pos
;
245 h
.stream_format
= format
;
246 h
.magic
= CEPH_FS_ONDISK_MAGIC
;
248 h
.layout
= file_layout_t::get_default();
249 h
.layout
.pool_id
= fs
->mds_map
.get_metadata_pool();
254 object_t oid
= file_object_t(ino
, 0);
255 object_locator_t
oloc(fs
->mds_map
.get_metadata_pool());
258 cout
<< "writing header " << oid
<< std::endl
;
259 C_SaferCond header_cond
;
261 objecter
->write_full(oid
, oloc
, snapc
, hbl
,
262 ceph::real_clock::now(), 0,
266 r
= header_cond
.wait();
268 derr
<< "Failed to write header: " << cpp_strerror(r
) << dendl
;
273 Filer
filer(objecter
, &finisher
);
275 /* Erase any objects at the end of the region to which we shall write
276 * the new log data. This is to avoid leaving trailing junk after
277 * the newly written data. Any junk more than one object ahead
278 * will be taken care of during normal operation by Journaler's
279 * prezeroing behaviour */
281 uint32_t const object_size
= h
.layout
.object_size
;
282 assert(object_size
> 0);
283 uint64_t const last_obj
= h
.write_pos
/ object_size
;
284 uint64_t const purge_count
= 2;
285 C_SaferCond purge_cond
;
286 cout
<< "Purging " << purge_count
<< " objects from " << last_obj
<< std::endl
;
288 filer
.purge_range(ino
, &h
.layout
, snapc
, last_obj
, purge_count
,
289 ceph::real_clock::now(), 0, &purge_cond
);
294 // Stream from `fd` to `filer`
295 uint64_t pos
= start
;
300 lseek64(fd
, pos
, SEEK_SET
);
301 uint64_t l
= MIN(left
, 1024*1024);
305 cout
<< " writing " << pos
<< "~" << l
<< std::endl
;
306 C_SaferCond write_cond
;
308 filer
.write(ino
, &h
.layout
, snapc
, pos
, l
, j
,
309 ceph::real_clock::now(), 0, &write_cond
);
312 r
= write_cond
.wait();
314 derr
<< "Failed to write header: " << cpp_strerror(r
) << dendl
;
324 VOID_TEMP_FAILURE_RETRY(::close(fd
));
325 cout
<< "done." << std::endl
;