Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / cephfs / DataScan.h
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) 2015 Red Hat
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
16 #include "MDSUtility.h"
17 #include "include/rados/librados.hpp"
18
19 class InodeStore;
20
21 class RecoveryDriver {
22   protected:
23     // If true, overwrite structures that generate decoding errors.
24     bool force_corrupt;
25
26     // If true, overwrite root objects during init_roots even if they
27     // exist
28     bool force_init;
29
30   public:
31     virtual int init(
32         librados::Rados &rados,
33         std::string &metadata_pool_name,
34         const FSMap *fsmap,
35         fs_cluster_id_t fscid) = 0;
36
37     void set_force_corrupt(const bool val)
38     {
39       force_corrupt = val;
40     }
41
42     void set_force_init(const bool val)
43     {
44       force_init = val;
45     }
46
47
48     /**
49      * Inject an inode + dentry parents into the metadata pool,
50      * based on a backtrace recovered from the data pool
51      */
52     virtual int inject_with_backtrace(
53         const inode_backtrace_t &bt,
54         const InodeStore &dentry) = 0;
55
56     /**
57      * Inject an inode + dentry into the lost+found directory,
58      * when all we know about a file is its inode.
59      */
60     virtual int inject_lost_and_found(
61         inodeno_t ino,
62         const InodeStore &dentry) = 0;
63
64     /**
65      * Create any missing roots (i.e. mydir, strays, root inode)
66      */
67     virtual int init_roots(
68         int64_t data_pool_id) = 0;
69
70     /**
71      * Pre-injection check that all the roots are present in
72      * the metadata pool.  Used to avoid parallel workers interfering
73      * with one another, by cueing the user to go run 'init' on a
74      * single node before running a parallel scan.
75      *
76      * @param result: set to true if roots are present, else set to false
77      * @returns 0 on no unexpected errors, else error code.  Missing objects
78      *          are not considered an unexpected error: check *result for
79      *          this case.
80      */
81     virtual int check_roots(bool *result) = 0;
82
83     /**
84      * Helper to compose dnames for links to lost+found
85      * inodes.
86      */
87     std::string lost_found_dname(inodeno_t ino)
88     {
89       char s[20];
90       snprintf(s, sizeof(s), "%llx", (unsigned long long)ino);
91       return std::string(s);
92     }
93
94     RecoveryDriver()
95       : force_corrupt(false),
96         force_init(false)
97     {}
98
99     virtual ~RecoveryDriver() {}
100 };
101
102 class LocalFileDriver : public RecoveryDriver
103
104   protected:
105     const std::string path;
106     librados::IoCtx &data_io;
107
108   int inject_data(
109       const std::string &file_path,
110       uint64_t size,
111       uint32_t chunk_size,
112       inodeno_t ino);
113   public:
114
115     LocalFileDriver(const std::string &path_, librados::IoCtx &data_io_)
116       : RecoveryDriver(), path(path_), data_io(data_io_)
117     {}
118
119     // Implement RecoveryDriver interface
120     int init(
121         librados::Rados &rados,
122         std::string &metadata_pool_name,
123         const FSMap *fsmap,
124         fs_cluster_id_t fscid) override;
125
126     int inject_with_backtrace(
127         const inode_backtrace_t &bt,
128         const InodeStore &dentry) override;
129
130     int inject_lost_and_found(
131         inodeno_t ino,
132         const InodeStore &dentry) override;
133
134     int init_roots(int64_t data_pool_id) override;
135
136     int check_roots(bool *result) override;
137 };
138
139 /**
140  * A class that knows how to work with objects in a CephFS
141  * metadata pool.
142  */
143 class MetadataTool
144 {
145   protected:
146
147   librados::IoCtx metadata_io;
148
149   /**
150    * Construct a synthetic InodeStore for a normal file
151    */
152   void build_file_dentry(
153     inodeno_t ino, uint64_t file_size, time_t file_mtime,
154     const file_layout_t &layout,
155     InodeStore *out);
156
157   /**
158    * Construct a synthetic InodeStore for a directory
159    */
160   void build_dir_dentry(
161     inodeno_t ino,
162     const frag_info_t &fragstat,
163     const file_layout_t &layout,
164     InodeStore *out);
165
166   /**
167    * Try and read an fnode from a dirfrag
168    */
169   int read_fnode(inodeno_t ino, frag_t frag,
170                  fnode_t *fnode, uint64_t *read_version);
171
172   /**
173    * Try and read a dentry from a dirfrag
174    */
175   int read_dentry(inodeno_t parent_ino, frag_t frag,
176                   const std::string &dname, InodeStore *inode);
177 };
178
179 /**
180  * A class that knows how to manipulate CephFS metadata pools
181  */
182 class MetadataDriver : public RecoveryDriver, public MetadataTool
183 {
184   protected:
185     /**
186      * Create a .inode object, i.e. root or mydir
187      */
188     int inject_unlinked_inode(inodeno_t inono, int mode, int64_t data_pool_id);
189
190     /**
191      * Check for existence of .inode objects, before
192      * trying to go ahead and inject metadata.
193      */
194     int root_exists(inodeno_t ino, bool *result);
195     int find_or_create_dirfrag(
196         inodeno_t ino,
197         frag_t fragment,
198         bool *created);
199
200
201     /**
202      * Work out which fragment of a directory should contain a named
203      * dentry, recursing up the trace as necessary to retrieve
204      * fragtrees.
205      */
206     int get_frag_of(
207         inodeno_t dirino,
208         const std::string &dname,
209         frag_t *result_ft);
210
211   public:
212
213     // Implement RecoveryDriver interface
214     int init(
215         librados::Rados &rados,
216         std::string &metadata_pool_name,
217         const FSMap *fsmap,
218         fs_cluster_id_t fscid) override;
219
220     int inject_linkage(
221         inodeno_t dir_ino, const std::string &dname,
222         const frag_t fragment, const InodeStore &inode);
223
224     int inject_with_backtrace(
225         const inode_backtrace_t &bt,
226         const InodeStore &dentry) override;
227
228     int inject_lost_and_found(
229         inodeno_t ino,
230         const InodeStore &dentry) override;
231
232     int init_roots(int64_t data_pool_id) override;
233
234     int check_roots(bool *result) override;
235 };
236
237 class DataScan : public MDSUtility, public MetadataTool
238 {
239   protected:
240     RecoveryDriver *driver;
241     fs_cluster_id_t fscid;
242
243     // IoCtx for data pool (where we scrape file backtraces from)
244     librados::IoCtx data_io;
245     // Remember the data pool ID for use in layouts
246     int64_t data_pool_id;
247     string metadata_pool_name;
248
249     uint32_t n;
250     uint32_t m;
251
252     /**
253      * Scan data pool for backtraces, and inject inodes to metadata pool
254      */
255     int scan_inodes();
256
257     /**
258      * Scan data pool for file sizes and mtimes
259      */
260     int scan_extents();
261
262     /**
263      * Scan metadata pool for 0th dirfrags to link orphaned
264      * directory inodes.
265      */
266     int scan_frags();
267
268     /**
269      * Cleanup xattrs from data pool
270      */
271     int cleanup();
272
273     /**
274      * Check if an inode number is in the permitted ranges
275      */
276     bool valid_ino(inodeno_t ino) const;
277
278
279     int scan_links();
280
281     // Accept pools which are not in the FSMap
282     bool force_pool;
283     // Respond to decode errors by overwriting
284     bool force_corrupt;
285     // Overwrite root objects even if they exist
286     bool force_init;
287     // Only scan inodes without this scrub tag
288     string filter_tag;
289
290     /**
291      * @param r set to error on valid key with invalid value
292      * @return true if argument consumed, else false
293      */
294     bool parse_kwarg(
295         const std::vector<const char*> &args,
296         std::vector<const char *>::const_iterator &i,
297         int *r);
298
299     /**
300      * @return true if argument consumed, else false
301      */
302     bool parse_arg(
303       const std::vector<const char*> &arg,
304       std::vector<const char *>::const_iterator &i);
305
306     int probe_filter(librados::IoCtx &ioctx);
307
308     /**
309      * Apply a function to all objects in an ioctx's pool, optionally
310      * restricted to only those objects with a 00000000 offset and
311      * no tag matching DataScan::scrub_tag.
312      */
313     int forall_objects(
314         librados::IoCtx &ioctx,
315         bool untagged_only,
316         std::function<int(std::string, uint64_t, uint64_t)> handler);
317
318   public:
319     void usage();
320     int main(const std::vector<const char *> &args);
321
322     DataScan()
323       : driver(NULL), fscid(FS_CLUSTER_ID_NONE),
324         data_pool_id(-1), metadata_pool_name(""), n(0), m(1),
325         force_pool(false), force_corrupt(false),
326         force_init(false)
327     {
328     }
329
330     ~DataScan() override
331     {
332       delete driver;
333     }
334 };
335