]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/ScrubStack.h
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / mds / ScrubStack.h
CommitLineData
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) 2014 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#ifndef SCRUBSTACK_H_
16#define SCRUBSTACK_H_
17
18#include "CDir.h"
19#include "CDentry.h"
20#include "CInode.h"
21#include "MDSContext.h"
22#include "ScrubHeader.h"
23
24#include "include/elist.h"
25
26class MDCache;
27class Finisher;
28
29class ScrubStack {
30protected:
31 /// A finisher needed so that we don't re-enter kick_off_scrubs
32 Finisher *finisher;
33
11fdf7f2 34 /// The stack of inodes we want to scrub
7c673cae
FG
35 elist<CInode*> inode_stack;
36 /// current number of dentries we're actually scrubbing
37 int scrubs_in_progress;
38 ScrubStack *scrubstack; // hack for dout
39 int stack_size;
40
41 class C_KickOffScrubs : public MDSInternalContext {
42 ScrubStack *stack;
43 public:
44 C_KickOffScrubs(MDCache *mdcache, ScrubStack *s);
45 void finish(int r) override { }
46 void complete(int r) override {
11fdf7f2
TL
47 if (r == -ECANCELED) {
48 return;
49 }
50
7c673cae
FG
51 stack->scrubs_in_progress--;
52 stack->kick_off_scrubs();
53 // don't delete self
54 }
55 };
56 C_KickOffScrubs scrub_kick;
57
58public:
59 MDCache *mdcache;
60 ScrubStack(MDCache *mdc, Finisher *finisher_) :
61 finisher(finisher_),
62 inode_stack(member_offset(CInode, item_scrub)),
63 scrubs_in_progress(0),
64 scrubstack(this),
65 stack_size(0),
66 scrub_kick(mdc, this),
67 mdcache(mdc) {}
68 ~ScrubStack() {
11fdf7f2
TL
69 ceph_assert(inode_stack.empty());
70 ceph_assert(!scrubs_in_progress);
7c673cae
FG
71 }
72 /**
73 * Put a inode on the top of the scrub stack, so it is the highest priority.
74 * If there are other scrubs in progress, they will not continue scrubbing new
75 * entries until this one is completed.
76 * @param in The inodey to scrub
11fdf7f2 77 * @param header The ScrubHeader propagated from wherever this scrub
7c673cae
FG
78 * was initiated
79 */
b32b8144 80 void enqueue_inode_top(CInode *in, ScrubHeaderRef& header,
11fdf7f2 81 MDSContext *on_finish) {
7c673cae 82 enqueue_inode(in, header, on_finish, true);
11fdf7f2 83 scrub_origins.emplace(in);
7c673cae
FG
84 }
85 /** Like enqueue_inode_top, but we wait for all pending scrubs before
86 * starting this one.
87 */
b32b8144 88 void enqueue_inode_bottom(CInode *in, ScrubHeaderRef& header,
11fdf7f2 89 MDSContext *on_finish) {
7c673cae 90 enqueue_inode(in, header, on_finish, false);
11fdf7f2 91 scrub_origins.emplace(in);
7c673cae
FG
92 }
93
11fdf7f2
TL
94 /**
95 * Abort an ongoing scrub operation. The abort operation could be
96 * delayed if there are in-progress scrub operations on going. The
97 * caller should provide a context which is completed after all
98 * in-progress scrub operations are completed and pending inodes
99 * are removed from the scrub stack (with the context callbacks for
100 * inodes completed with -ECANCELED).
101 * @param on_finish Context callback to invoke after abort
102 */
103 void scrub_abort(Context *on_finish);
104
105 /**
106 * Pause scrub operations. Similar to abort, pause is delayed if
107 * there are in-progress scrub operations on going. The caller
108 * should provide a context which is completed after all in-progress
109 * scrub operations are completed. Subsequent scrub operations are
110 * queued until scrub is resumed.
111 * @param on_finish Context callback to invoke after pause
112 */
113 void scrub_pause(Context *on_finish);
114
115 /**
116 * Resume a paused scrub. Unlike abort or pause, this is instantaneous.
117 * Pending pause operations are cancelled (context callbacks are
118 * invoked with -ECANCELED).
119 * @returns 0 (success) if resumed, -EINVAL if an abort is in-progress.
120 */
121 bool scrub_resume();
122
123 /**
124 * Get the current scrub status as human readable string. Some basic
125 * information is returned such as number of inodes pending abort/pause.
126 */
127 void scrub_status(Formatter *f);
128
92f5a8d4
TL
129 bool is_scrubbing() const { return !inode_stack.empty(); }
130
7c673cae 131private:
11fdf7f2
TL
132 // scrub abort is _not_ a state, rather it's an operation that's
133 // performed after in-progress scrubs are finished.
134 enum State {
135 STATE_RUNNING = 0,
136 STATE_IDLE,
137 STATE_PAUSING,
138 STATE_PAUSED,
139 };
140 friend std::ostream &operator<<(std::ostream &os, const State &state);
141
142 State state = STATE_IDLE;
143 bool clear_inode_stack = false;
144
145 // list of pending context completions for asynchronous scrub
146 // control operations.
147 std::list<Context *> control_ctxs;
148
149 // list of inodes for which scrub operations are running -- used
150 // to diplay out in `scrub status`.
151 std::set<CInode *> scrub_origins;
152
7c673cae
FG
153 /**
154 * Put the inode at either the top or bottom of the stack, with
155 * the given scrub params, and then try and kick off more scrubbing.
156 */
b32b8144 157 void enqueue_inode(CInode *in, ScrubHeaderRef& header,
11fdf7f2 158 MDSContext *on_finish, bool top);
b32b8144 159 void _enqueue_inode(CInode *in, CDentry *parent, ScrubHeaderRef& header,
11fdf7f2 160 MDSContext *on_finish, bool top);
7c673cae
FG
161 /**
162 * Kick off as many scrubs as are appropriate, based on the current
163 * state of the stack.
164 */
165 void kick_off_scrubs();
166 /**
11fdf7f2 167 * Push a inode on top of the stack.
7c673cae
FG
168 */
169 inline void push_inode(CInode *in);
170 /**
171 * Push a inode to the bottom of the stack.
172 */
173 inline void push_inode_bottom(CInode *in);
174 /**
175 * Pop the given inode off the stack.
176 */
177 inline void pop_inode(CInode *in);
178
179 /**
180 * Scrub a file inode.
11fdf7f2 181 * @param in The inode to scrub
7c673cae
FG
182 */
183 void scrub_file_inode(CInode *in);
184
185 /**
186 * Callback from completion of CInode::validate_disk_state
187 * @param in The inode we were validating
188 * @param r The return status from validate_disk_state
189 * @param result Populated results from validate_disk_state
190 */
191 void _validate_inode_done(CInode *in, int r,
192 const CInode::validated_data &result);
193 friend class C_InodeValidated;
194
195 /**
196 * Make progress on scrubbing a directory-representing dirfrag and
197 * its children..
198 *
199 * 1) Select the next dirfrag which hasn't been scrubbed, and make progress
200 * on it if possible.
201 *
202 * 2) If not, move on to the next dirfrag and start it up, if any.
203 *
204 * 3) If waiting for results from dirfrag scrubs, do nothing.
205 *
206 * 4) If all dirfrags have been scrubbed, scrub my inode.
207 *
208 * @param in The CInode to scrub as a directory
11fdf7f2 209 * @param added_children set to true if we pushed some of our children
7c673cae
FG
210 * onto the ScrubStack
211 * @param is_terminal set to true if there are no descendant dentries
212 * remaining to start scrubbing.
213 * @param done set to true if we and all our children have finished scrubbing
214 */
215 void scrub_dir_inode(CInode *in, bool *added_children, bool *is_terminal,
216 bool *done);
217 /**
218 * Make progress on scrubbing a dirfrag. It may return after each of the
219 * following steps, but will report making progress on each one.
220 *
221 * 1) enqueues the next unscrubbed child directory dentry at the
222 * top of the stack.
223 *
224 * 2) Initiates a scrub on the next unscrubbed file dentry
225 *
226 * If there are scrubs currently in progress on child dentries, no more child
227 * dentries to scrub, and this function is invoked, it will report no
228 * progress. Try again later.
229 *
230 */
b32b8144 231 void scrub_dirfrag(CDir *dir, ScrubHeaderRef& header,
7c673cae
FG
232 bool *added_children, bool *is_terminal, bool *done);
233 /**
234 * Scrub a directory-representing dentry.
235 *
236 * @param in The directory inode we're doing final scrub on.
237 */
238 void scrub_dir_inode_final(CInode *in);
239
240 /**
241 * Get a CDir into memory, and return it if it's already complete.
242 * Otherwise, fetch it and kick off scrubbing when done.
243 *
244 * @param in The Inode to get the next directory from
245 * @param new_dir The CDir we're returning to you. NULL if
246 * not ready yet or there aren't any.
247 * @returns false if you have to wait, true if there's no work
248 * left to do (we returned it, or there are none left in this inode).
249 */
250 bool get_next_cdir(CInode *in, CDir **new_dir);
251
11fdf7f2
TL
252 /**
253 * Set scrub state
254 * @param next_state State to move the scrub to.
255 */
256 void set_state(State next_state);
257
258 /**
259 * Is scrub in one of transition states (running, pausing)
260 */
261 bool scrub_in_transition_state();
262
263 /**
264 * complete queued up contexts
265 * @param r return value to complete contexts.
266 */
267 void complete_control_contexts(int r);
268
269 /**
270 * Abort pending scrubs for inodes waiting in the inode stack.
271 * Completion context is complete with -ECANCELED.
272 */
273 void abort_pending_scrubs();
7c673cae
FG
274};
275
276#endif /* SCRUBSTACK_H_ */