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) 2014 Red Hat
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.
21 #include "MDSContext.h"
22 #include "ScrubHeader.h"
24 #include "include/elist.h"
31 /// A finisher needed so that we don't re-enter kick_off_scrubs
34 /// The stack of dentries we want to scrub
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
41 class C_KickOffScrubs : public MDSInternalContext {
44 C_KickOffScrubs(MDCache *mdcache, ScrubStack *s);
45 void finish(int r) override { }
46 void complete(int r) override {
47 stack->scrubs_in_progress--;
48 stack->kick_off_scrubs();
52 C_KickOffScrubs scrub_kick;
56 ScrubStack(MDCache *mdc, Finisher *finisher_) :
58 inode_stack(member_offset(CInode, item_scrub)),
59 scrubs_in_progress(0),
62 scrub_kick(mdc, this),
65 assert(inode_stack.empty());
66 assert(!scrubs_in_progress);
69 * Put a inode on the top of the scrub stack, so it is the highest priority.
70 * If there are other scrubs in progress, they will not continue scrubbing new
71 * entries until this one is completed.
72 * @param in The inodey to scrub
73 * @param header The ScrubHeader propagated from whereever this scrub
76 void enqueue_inode_top(CInode *in, const ScrubHeaderRefConst& header,
77 MDSInternalContextBase *on_finish) {
78 enqueue_inode(in, header, on_finish, true);
80 /** Like enqueue_inode_top, but we wait for all pending scrubs before
83 void enqueue_inode_bottom(CInode *in, const ScrubHeaderRefConst& header,
84 MDSInternalContextBase *on_finish) {
85 enqueue_inode(in, header, on_finish, false);
90 * Put the inode at either the top or bottom of the stack, with
91 * the given scrub params, and then try and kick off more scrubbing.
93 void enqueue_inode(CInode *in, const ScrubHeaderRefConst& header,
94 MDSInternalContextBase *on_finish, bool top);
95 void _enqueue_inode(CInode *in, CDentry *parent, const ScrubHeaderRefConst& header,
96 MDSInternalContextBase *on_finish, bool top);
98 * Kick off as many scrubs as are appropriate, based on the current
101 void kick_off_scrubs();
103 * Push a indoe on top of the stack.
105 inline void push_inode(CInode *in);
107 * Push a inode to the bottom of the stack.
109 inline void push_inode_bottom(CInode *in);
111 * Pop the given inode off the stack.
113 inline void pop_inode(CInode *in);
116 * Scrub a file inode.
117 * @param in The indoe to scrub
119 void scrub_file_inode(CInode *in);
122 * Callback from completion of CInode::validate_disk_state
123 * @param in The inode we were validating
124 * @param r The return status from validate_disk_state
125 * @param result Populated results from validate_disk_state
127 void _validate_inode_done(CInode *in, int r,
128 const CInode::validated_data &result);
129 friend class C_InodeValidated;
132 * Make progress on scrubbing a directory-representing dirfrag and
135 * 1) Select the next dirfrag which hasn't been scrubbed, and make progress
138 * 2) If not, move on to the next dirfrag and start it up, if any.
140 * 3) If waiting for results from dirfrag scrubs, do nothing.
142 * 4) If all dirfrags have been scrubbed, scrub my inode.
144 * @param in The CInode to scrub as a directory
145 * @param added_dentries set to true if we pushed some of our children
146 * onto the ScrubStack
147 * @param is_terminal set to true if there are no descendant dentries
148 * remaining to start scrubbing.
149 * @param done set to true if we and all our children have finished scrubbing
151 void scrub_dir_inode(CInode *in, bool *added_children, bool *is_terminal,
154 * Make progress on scrubbing a dirfrag. It may return after each of the
155 * following steps, but will report making progress on each one.
157 * 1) enqueues the next unscrubbed child directory dentry at the
160 * 2) Initiates a scrub on the next unscrubbed file dentry
162 * If there are scrubs currently in progress on child dentries, no more child
163 * dentries to scrub, and this function is invoked, it will report no
164 * progress. Try again later.
167 void scrub_dirfrag(CDir *dir, const ScrubHeaderRefConst& header,
168 bool *added_children, bool *is_terminal, bool *done);
170 * Scrub a directory-representing dentry.
172 * @param in The directory inode we're doing final scrub on.
174 void scrub_dir_inode_final(CInode *in);
177 * Get a CDir into memory, and return it if it's already complete.
178 * Otherwise, fetch it and kick off scrubbing when done.
180 * @param in The Inode to get the next directory from
181 * @param new_dir The CDir we're returning to you. NULL if
182 * not ready yet or there aren't any.
183 * @returns false if you have to wait, true if there's no work
184 * left to do (we returned it, or there are none left in this inode).
186 bool get_next_cdir(CInode *in, CDir **new_dir);
190 #endif /* SCRUBSTACK_H_ */