]>
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 | ||
16 | ||
17 | #ifndef CEPH_CDENTRY_H | |
18 | #define CEPH_CDENTRY_H | |
19 | ||
20 | #include <string> | |
21 | #include <set> | |
22 | ||
23 | #include "include/counter.h" | |
24 | #include "include/types.h" | |
25 | #include "include/buffer_fwd.h" | |
26 | #include "include/lru.h" | |
27 | #include "include/elist.h" | |
28 | #include "include/filepath.h" | |
29 | ||
30 | #include "MDSCacheObject.h" | |
31 | #include "SimpleLock.h" | |
32 | #include "LocalLock.h" | |
33 | #include "ScrubHeader.h" | |
34 | ||
35 | class CInode; | |
36 | class CDir; | |
37 | class Locker; | |
38 | class Message; | |
39 | class CDentry; | |
40 | class LogSegment; | |
41 | ||
42 | class Session; | |
43 | ||
44 | ||
45 | ||
46 | // define an ordering | |
47 | bool operator<(const CDentry& l, const CDentry& r); | |
48 | ||
49 | // dentry | |
50 | class CDentry : public MDSCacheObject, public LRUObject, public Counter<CDentry> { | |
51 | public: | |
181888fb | 52 | MEMPOOL_CLASS_HELPERS(); |
7c673cae FG |
53 | friend class CDir; |
54 | ||
55 | struct linkage_t { | |
56 | CInode *inode; | |
57 | inodeno_t remote_ino; | |
58 | unsigned char remote_d_type; | |
59 | ||
60 | linkage_t() : inode(0), remote_ino(0), remote_d_type(0) {} | |
61 | ||
62 | // dentry type is primary || remote || null | |
63 | // inode ptr is required for primary, optional for remote, undefined for null | |
64 | bool is_primary() const { return remote_ino == 0 && inode != 0; } | |
65 | bool is_remote() const { return remote_ino > 0; } | |
66 | bool is_null() const { return remote_ino == 0 && inode == 0; } | |
67 | ||
68 | CInode *get_inode() { return inode; } | |
69 | const CInode *get_inode() const { return inode; } | |
70 | inodeno_t get_remote_ino() const { return remote_ino; } | |
71 | unsigned char get_remote_d_type() const { return remote_d_type; } | |
72 | std::string get_remote_d_type_string() const; | |
73 | ||
74 | void set_remote(inodeno_t ino, unsigned char d_type) { | |
75 | remote_ino = ino; | |
76 | remote_d_type = d_type; | |
77 | inode = 0; | |
78 | } | |
79 | void link_remote(CInode *in); | |
80 | }; | |
81 | ||
82 | ||
83 | // -- state -- | |
84 | static const int STATE_NEW = (1<<0); | |
85 | static const int STATE_FRAGMENTING = (1<<1); | |
86 | static const int STATE_PURGING = (1<<2); | |
87 | static const int STATE_BADREMOTEINO = (1<<3); | |
88 | static const int STATE_EVALUATINGSTRAY = (1<<4); | |
89 | static const int STATE_PURGINGPINNED = (1<<5); | |
31f18b77 | 90 | static const int STATE_BOTTOMLRU = (1<<6); |
7c673cae FG |
91 | // stray dentry needs notification of releasing reference |
92 | static const int STATE_STRAY = STATE_NOTIFYREF; | |
31f18b77 | 93 | static const int MASK_STATE_IMPORT_KEPT = STATE_BOTTOMLRU; |
7c673cae FG |
94 | |
95 | // -- pins -- | |
96 | static const int PIN_INODEPIN = 1; // linked inode is pinned | |
97 | static const int PIN_FRAGMENTING = -2; // containing dir is refragmenting | |
98 | static const int PIN_PURGING = 3; | |
99 | static const int PIN_SCRUBPARENT = 4; | |
100 | ||
101 | static const unsigned EXPORT_NONCE = 1; | |
102 | ||
103 | ||
104 | CDentry(const std::string& n, __u32 h, | |
105 | snapid_t f, snapid_t l) : | |
106 | name(n), hash(h), | |
107 | first(f), last(l), | |
108 | item_dirty(this), | |
109 | lock(this, &lock_type), | |
110 | versionlock(this, &versionlock_type), | |
111 | dir(0), | |
112 | version(0), projected_version(0) { | |
113 | } | |
114 | CDentry(const std::string& n, __u32 h, inodeno_t ino, unsigned char dt, | |
115 | snapid_t f, snapid_t l) : | |
116 | name(n), hash(h), | |
117 | first(f), last(l), | |
118 | item_dirty(this), | |
119 | lock(this, &lock_type), | |
120 | versionlock(this, &versionlock_type), | |
121 | dir(0), | |
122 | version(0), projected_version(0) { | |
123 | linkage.remote_ino = ino; | |
124 | linkage.remote_d_type = dt; | |
125 | } | |
126 | ||
127 | const char *pin_name(int p) const override { | |
128 | switch (p) { | |
129 | case PIN_INODEPIN: return "inodepin"; | |
130 | case PIN_FRAGMENTING: return "fragmenting"; | |
131 | case PIN_PURGING: return "purging"; | |
132 | case PIN_SCRUBPARENT: return "scrubparent"; | |
133 | default: return generic_pin_name(p); | |
134 | } | |
135 | } | |
136 | ||
137 | // -- wait -- | |
138 | //static const int WAIT_LOCK_OFFSET = 8; | |
139 | ||
140 | void add_waiter(uint64_t tag, MDSInternalContextBase *c) override; | |
141 | ||
142 | bool is_lt(const MDSCacheObject *r) const override { | |
143 | return *this < *static_cast<const CDentry*>(r); | |
144 | } | |
145 | ||
146 | dentry_key_t key() { | |
147 | return dentry_key_t(last, name.c_str(), hash); | |
148 | } | |
149 | ||
150 | const CDir *get_dir() const { return dir; } | |
151 | CDir *get_dir() { return dir; } | |
152 | const std::string& get_name() const { return name; } | |
153 | ||
154 | __u32 get_hash() const { return hash; } | |
155 | ||
156 | // linkage | |
157 | const linkage_t *get_linkage() const { return &linkage; } | |
158 | linkage_t *get_linkage() { return &linkage; } | |
159 | ||
160 | linkage_t *_project_linkage() { | |
161 | projected.push_back(linkage_t()); | |
162 | return &projected.back(); | |
163 | } | |
164 | void push_projected_linkage(); | |
165 | void push_projected_linkage(inodeno_t ino, char d_type) { | |
166 | linkage_t *p = _project_linkage(); | |
167 | p->remote_ino = ino; | |
168 | p->remote_d_type = d_type; | |
169 | } | |
170 | void push_projected_linkage(CInode *inode); | |
171 | linkage_t *pop_projected_linkage(); | |
172 | ||
173 | bool is_projected() const { return !projected.empty(); } | |
174 | ||
175 | linkage_t *get_projected_linkage() { | |
176 | if (!projected.empty()) | |
177 | return &projected.back(); | |
178 | return &linkage; | |
179 | } | |
180 | ||
181 | const linkage_t *get_projected_linkage() const { | |
182 | if (!projected.empty()) | |
183 | return &projected.back(); | |
184 | return &linkage; | |
185 | } | |
186 | ||
187 | CInode *get_projected_inode() { | |
188 | return get_projected_linkage()->inode; | |
189 | } | |
190 | ||
191 | bool use_projected(client_t client, const MutationRef& mut) const { | |
192 | return lock.can_read_projected(client) || | |
193 | lock.get_xlock_by() == mut; | |
194 | } | |
195 | linkage_t *get_linkage(client_t client, const MutationRef& mut) { | |
196 | return use_projected(client, mut) ? get_projected_linkage() : get_linkage(); | |
197 | } | |
198 | ||
199 | // ref counts: pin ourselves in the LRU when we're pinned. | |
200 | void first_get() override { | |
201 | lru_pin(); | |
202 | } | |
203 | void last_put() override { | |
204 | lru_unpin(); | |
205 | } | |
206 | void _put() override; | |
207 | ||
208 | // auth pins | |
209 | bool can_auth_pin() const override; | |
210 | void auth_pin(void *by) override; | |
211 | void auth_unpin(void *by) override; | |
212 | void adjust_nested_auth_pins(int adjustment, int diradj, void *by); | |
213 | bool is_frozen() const override; | |
214 | bool is_freezing() const override; | |
215 | int get_num_dir_auth_pins() const; | |
216 | ||
217 | // remote links | |
218 | void link_remote(linkage_t *dnl, CInode *in); | |
219 | void unlink_remote(linkage_t *dnl); | |
220 | ||
221 | // copy cons | |
222 | CDentry(const CDentry& m); | |
223 | const CDentry& operator= (const CDentry& right); | |
224 | ||
225 | // misc | |
226 | void make_path_string(std::string& s, bool projected=false) const; | |
227 | void make_path(filepath& fp, bool projected=false) const; | |
228 | ||
229 | // -- version -- | |
230 | version_t get_version() const { return version; } | |
231 | void set_version(version_t v) { projected_version = version = v; } | |
232 | version_t get_projected_version() const { return projected_version; } | |
233 | void set_projected_version(version_t v) { projected_version = v; } | |
234 | ||
235 | mds_authority_t authority() const override; | |
236 | ||
237 | version_t pre_dirty(version_t min=0); | |
238 | void _mark_dirty(LogSegment *ls); | |
239 | void mark_dirty(version_t projected_dirv, LogSegment *ls); | |
240 | void mark_clean(); | |
241 | ||
242 | void mark_new(); | |
243 | bool is_new() const { return state_test(STATE_NEW); } | |
244 | void clear_new() { state_clear(STATE_NEW); } | |
245 | ||
246 | // -- replication | |
b32b8144 | 247 | void encode_replica(mds_rank_t mds, bufferlist& bl, bool need_recover) { |
7c673cae FG |
248 | if (!is_replicated()) |
249 | lock.replicate_relax(); | |
250 | ||
251 | __u32 nonce = add_replica(mds); | |
252 | ::encode(nonce, bl); | |
253 | ::encode(first, bl); | |
254 | ::encode(linkage.remote_ino, bl); | |
255 | ::encode(linkage.remote_d_type, bl); | |
b32b8144 FG |
256 | lock.encode_state_for_replica(bl); |
257 | ::encode(need_recover, bl); | |
7c673cae FG |
258 | } |
259 | void decode_replica(bufferlist::iterator& p, bool is_new); | |
260 | ||
261 | // -- exporting | |
262 | // note: this assumes the dentry already exists. | |
263 | // i.e., the name is already extracted... so we just need the other state. | |
264 | void encode_export(bufferlist& bl) { | |
265 | ::encode(first, bl); | |
266 | ::encode(state, bl); | |
267 | ::encode(version, bl); | |
268 | ::encode(projected_version, bl); | |
269 | ::encode(lock, bl); | |
181888fb | 270 | ::encode(get_replicas(), bl); |
7c673cae FG |
271 | get(PIN_TEMPEXPORTING); |
272 | } | |
273 | void finish_export() { | |
274 | // twiddle | |
275 | clear_replica_map(); | |
276 | replica_nonce = EXPORT_NONCE; | |
277 | state_clear(CDentry::STATE_AUTH); | |
278 | if (is_dirty()) | |
279 | mark_clean(); | |
280 | put(PIN_TEMPEXPORTING); | |
281 | } | |
282 | void abort_export() { | |
283 | put(PIN_TEMPEXPORTING); | |
284 | } | |
285 | void decode_import(bufferlist::iterator& blp, LogSegment *ls) { | |
286 | ::decode(first, blp); | |
287 | __u32 nstate; | |
288 | ::decode(nstate, blp); | |
289 | ::decode(version, blp); | |
290 | ::decode(projected_version, blp); | |
291 | ::decode(lock, blp); | |
181888fb | 292 | ::decode(get_replicas(), blp); |
7c673cae FG |
293 | |
294 | // twiddle | |
31f18b77 | 295 | state &= MASK_STATE_IMPORT_KEPT; |
7c673cae FG |
296 | state_set(CDentry::STATE_AUTH); |
297 | if (nstate & STATE_DIRTY) | |
298 | _mark_dirty(ls); | |
181888fb | 299 | if (is_replicated()) |
7c673cae FG |
300 | get(PIN_REPLICATED); |
301 | replica_nonce = 0; | |
302 | } | |
303 | ||
304 | // -- locking -- | |
305 | SimpleLock* get_lock(int type) override { | |
306 | assert(type == CEPH_LOCK_DN); | |
307 | return &lock; | |
308 | } | |
309 | void set_object_info(MDSCacheObjectInfo &info) override; | |
310 | void encode_lock_state(int type, bufferlist& bl) override; | |
311 | void decode_lock_state(int type, bufferlist& bl) override; | |
312 | ||
313 | // --------------------------------------------- | |
314 | // replicas (on clients) | |
315 | ||
316 | bool is_any_leases() const { | |
317 | return !client_lease_map.empty(); | |
318 | } | |
319 | const ClientLease *get_client_lease(client_t c) const { | |
320 | if (client_lease_map.count(c)) | |
321 | return client_lease_map.find(c)->second; | |
322 | return 0; | |
323 | } | |
324 | ClientLease *get_client_lease(client_t c) { | |
325 | if (client_lease_map.count(c)) | |
326 | return client_lease_map.find(c)->second; | |
327 | return 0; | |
328 | } | |
329 | bool have_client_lease(client_t c) const { | |
330 | const ClientLease *l = get_client_lease(c); | |
331 | if (l) | |
332 | return true; | |
333 | else | |
334 | return false; | |
335 | } | |
336 | ||
337 | ClientLease *add_client_lease(client_t c, Session *session); | |
338 | void remove_client_lease(ClientLease *r, Locker *locker); // returns remaining mask (if any), and kicks locker eval_gathers | |
339 | void remove_client_leases(Locker *locker); | |
340 | ||
341 | ostream& print_db_line_prefix(ostream& out) override; | |
342 | void print(ostream& out) override; | |
343 | void dump(Formatter *f) const; | |
344 | ||
345 | ||
346 | std::string name; | |
347 | __u32 hash; | |
348 | snapid_t first, last; | |
349 | ||
b32b8144 | 350 | elist<CDentry*>::item item_dirty, item_dir_dirty; |
7c673cae FG |
351 | elist<CDentry*>::item item_stray; |
352 | ||
353 | // lock | |
354 | static LockType lock_type; | |
355 | static LockType versionlock_type; | |
356 | ||
357 | SimpleLock lock; | |
358 | LocalLock versionlock; | |
359 | ||
360 | map<client_t,ClientLease*> client_lease_map; | |
361 | ||
362 | ||
363 | protected: | |
364 | friend class Migrator; | |
365 | friend class Locker; | |
366 | friend class MDCache; | |
367 | friend class StrayManager; | |
368 | friend class CInode; | |
369 | friend class C_MDC_XlockRequest; | |
370 | ||
371 | CDir *dir; // containing dirfrag | |
372 | linkage_t linkage; | |
373 | list<linkage_t> projected; | |
374 | ||
375 | version_t version; // dir version when last touched. | |
376 | version_t projected_version; // what it will be when i unlock/commit. | |
377 | }; | |
378 | ||
379 | ostream& operator<<(ostream& out, const CDentry& dn); | |
380 | ||
381 | ||
382 | #endif |