]>
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 | #ifndef CEPH_CLIENT_INODE_H | |
5 | #define CEPH_CLIENT_INODE_H | |
6 | ||
b32b8144 FG |
7 | #include <numeric> |
8 | ||
f67539c2 | 9 | #include "include/compat.h" |
11fdf7f2 | 10 | #include "include/ceph_assert.h" |
7c673cae FG |
11 | #include "include/types.h" |
12 | #include "include/xlist.h" | |
13 | ||
11fdf7f2 | 14 | #include "mds/flock.h" |
7c673cae | 15 | #include "mds/mdstypes.h" // hrm |
1e59de90 | 16 | #include "include/cephfs/types.h" |
7c673cae FG |
17 | |
18 | #include "osdc/ObjectCacher.h" | |
7c673cae FG |
19 | |
20 | #include "InodeRef.h" | |
11fdf7f2 | 21 | #include "MetaSession.h" |
7c673cae | 22 | #include "UserPerm.h" |
b32b8144 | 23 | #include "Delegation.h" |
7c673cae FG |
24 | |
25 | class Client; | |
7c673cae FG |
26 | class Dentry; |
27 | class Dir; | |
28 | struct SnapRealm; | |
29 | struct Inode; | |
7c673cae FG |
30 | class MetaRequest; |
31 | class filepath; | |
32 | class Fh; | |
33 | ||
11fdf7f2 TL |
34 | class Cap { |
35 | public: | |
36 | Cap() = delete; | |
37 | Cap(Inode &i, MetaSession *s) : inode(i), | |
38 | session(s), | |
39 | gen(s->cap_gen), | |
40 | cap_item(this) | |
41 | { | |
42 | s->caps.push_back(&cap_item); | |
43 | } | |
44 | ~Cap() { | |
45 | cap_item.remove_myself(); | |
46 | } | |
47 | ||
48 | void touch(void) { | |
49 | // move to back of LRU | |
50 | session->caps.push_back(&cap_item); | |
51 | } | |
52 | ||
53 | void dump(Formatter *f) const; | |
54 | ||
55 | Inode &inode; | |
7c673cae | 56 | MetaSession *session; |
11fdf7f2 TL |
57 | uint64_t cap_id = 0; |
58 | unsigned issued = 0; | |
59 | unsigned implemented = 0; | |
60 | unsigned wanted = 0; // as known to mds. | |
61 | uint64_t seq = 0; | |
62 | uint64_t issue_seq = 0; | |
63 | __u32 mseq = 0; // migration seq | |
7c673cae FG |
64 | __u32 gen; |
65 | UserPerm latest_perms; | |
66 | ||
11fdf7f2 TL |
67 | private: |
68 | /* Note that this Cap will not move (see Inode::caps): | |
69 | * | |
70 | * Section 23.1.2#8 | |
71 | * The insert members shall not affect the validity of iterators and | |
72 | * references to the container, and the erase members shall invalidate only | |
73 | * iterators and references to the erased elements. | |
74 | */ | |
75 | xlist<Cap *>::item cap_item; | |
7c673cae FG |
76 | }; |
77 | ||
78 | struct CapSnap { | |
79 | //snapid_t follows; // map key | |
80 | InodeRef in; | |
81 | SnapContext context; | |
b3b6e05e | 82 | int issued = 0, dirty = 0; |
7c673cae | 83 | |
b3b6e05e | 84 | uint64_t size = 0; |
7c673cae | 85 | utime_t ctime, btime, mtime, atime; |
b3b6e05e TL |
86 | version_t time_warp_seq = 0; |
87 | uint64_t change_attr = 0; | |
88 | uint32_t mode = 0; | |
89 | uid_t uid = 0; | |
90 | gid_t gid = 0; | |
20effc67 | 91 | std::map<std::string,bufferptr> xattrs; |
b3b6e05e | 92 | version_t xattr_version = 0; |
7c673cae FG |
93 | |
94 | bufferlist inline_data; | |
b3b6e05e | 95 | version_t inline_version = 0; |
7c673cae | 96 | |
b3b6e05e TL |
97 | bool writing = false, dirty_data = false; |
98 | uint64_t flush_tid = 0; | |
7c673cae | 99 | |
b3b6e05e TL |
100 | int64_t cap_dirtier_uid = -1; |
101 | int64_t cap_dirtier_gid = -1; | |
11fdf7f2 | 102 | |
7c673cae | 103 | explicit CapSnap(Inode *i) |
b3b6e05e | 104 | : in(i) |
7c673cae FG |
105 | {} |
106 | ||
107 | void dump(Formatter *f) const; | |
108 | }; | |
109 | ||
110 | // inode flags | |
f6b5b4d7 TL |
111 | #define I_COMPLETE (1 << 0) |
112 | #define I_DIR_ORDERED (1 << 1) | |
113 | #define I_SNAPDIR_OPEN (1 << 2) | |
114 | #define I_KICK_FLUSH (1 << 3) | |
115 | #define I_CAP_DROPPED (1 << 4) | |
116 | #define I_ERROR_FILELOCK (1 << 5) | |
7c673cae | 117 | |
b3b6e05e | 118 | struct Inode : RefCountedObject { |
2a845540 | 119 | ceph::coarse_mono_time hold_caps_until; |
7c673cae FG |
120 | Client *client; |
121 | ||
122 | // -- the actual inode -- | |
123 | inodeno_t ino; // ORDER DEPENDENCY: oset | |
124 | snapid_t snapid; | |
b3b6e05e | 125 | ino_t faked_ino = 0; |
7c673cae | 126 | |
b3b6e05e | 127 | uint32_t rdev = 0; // if special file |
7c673cae FG |
128 | |
129 | // affected by any inode change... | |
130 | utime_t ctime; // inode change time | |
131 | utime_t btime; // birth time | |
132 | ||
133 | // perm (namespace permissions) | |
b3b6e05e TL |
134 | uint32_t mode = 0; |
135 | uid_t uid = 0; | |
136 | gid_t gid = 0; | |
7c673cae FG |
137 | |
138 | // nlink | |
b3b6e05e | 139 | int32_t nlink = 0; |
7c673cae FG |
140 | |
141 | // file (data access) | |
b3b6e05e | 142 | ceph_dir_layout dir_layout{}; |
7c673cae | 143 | file_layout_t layout; |
b3b6e05e TL |
144 | uint64_t size = 0; // on directory, # dentries |
145 | uint32_t truncate_seq = 1; | |
146 | uint64_t truncate_size = -1; | |
7c673cae FG |
147 | utime_t mtime; // file data modify time. |
148 | utime_t atime; // file data access time. | |
b3b6e05e TL |
149 | uint32_t time_warp_seq = 0; // count of (potential) mtime/atime timewarps (i.e., utimes()) |
150 | uint64_t change_attr = 0; | |
7c673cae | 151 | |
b3b6e05e | 152 | uint64_t max_size = 0; // max size we can write to |
7c673cae FG |
153 | |
154 | // dirfrag, recursive accountin | |
155 | frag_info_t dirstat; | |
156 | nest_info_t rstat; | |
157 | ||
158 | // special stuff | |
b3b6e05e TL |
159 | version_t version = 0; // auth only |
160 | version_t xattr_version = 0; | |
81eedcae | 161 | utime_t snap_btime; // snapshot creation (birth) time |
f67539c2 | 162 | std::map<std::string, std::string> snap_metadata; |
7c673cae FG |
163 | |
164 | // inline data | |
b3b6e05e | 165 | version_t inline_version = 0; |
7c673cae FG |
166 | bufferlist inline_data; |
167 | ||
1e59de90 TL |
168 | std::vector<uint8_t> fscrypt_auth; |
169 | std::vector<uint8_t> fscrypt_file; | |
170 | bool is_fscrypt_enabled() { | |
171 | return !!fscrypt_auth.size(); | |
172 | } | |
f67539c2 | 173 | |
b3b6e05e | 174 | bool is_root() const { return ino == CEPH_INO_ROOT; } |
7c673cae FG |
175 | bool is_symlink() const { return (mode & S_IFMT) == S_IFLNK; } |
176 | bool is_dir() const { return (mode & S_IFMT) == S_IFDIR; } | |
177 | bool is_file() const { return (mode & S_IFMT) == S_IFREG; } | |
178 | ||
179 | bool has_dir_layout() const { | |
180 | return layout != file_layout_t(); | |
181 | } | |
182 | ||
20effc67 | 183 | __u32 hash_dentry_name(const std::string &dn) { |
7c673cae FG |
184 | int which = dir_layout.dl_dir_hash; |
185 | if (!which) | |
186 | which = CEPH_STR_HASH_LINUX; | |
11fdf7f2 | 187 | ceph_assert(ceph_str_hash_valid(which)); |
7c673cae FG |
188 | return ceph_str_hash(which, dn.data(), dn.length()); |
189 | } | |
190 | ||
b3b6e05e | 191 | unsigned flags = 0; |
7c673cae FG |
192 | |
193 | quota_info_t quota; | |
194 | ||
195 | bool is_complete_and_ordered() { | |
196 | static const unsigned wants = I_COMPLETE | I_DIR_ORDERED; | |
197 | return (flags & wants) == wants; | |
198 | } | |
199 | ||
200 | // about the dir (if this is one!) | |
b3b6e05e | 201 | Dir *dir = 0; // if i'm a dir. |
7c673cae | 202 | fragtree_t dirfragtree; |
b3b6e05e TL |
203 | uint64_t dir_release_count = 1; |
204 | uint64_t dir_ordered_count = 1; | |
205 | bool dir_hashed = false; | |
206 | bool dir_replicated = false; | |
7c673cae FG |
207 | |
208 | // per-mds caps | |
11fdf7f2 | 209 | std::map<mds_rank_t, Cap> caps; // mds -> Cap |
b3b6e05e TL |
210 | Cap *auth_cap = 0; |
211 | int64_t cap_dirtier_uid = -1; | |
212 | int64_t cap_dirtier_gid = -1; | |
213 | unsigned dirty_caps = 0; | |
214 | unsigned flushing_caps = 0; | |
7c673cae | 215 | std::map<ceph_tid_t, int> flushing_cap_tids; |
b3b6e05e TL |
216 | int shared_gen = 0; |
217 | int cache_gen = 0; | |
218 | int snap_caps = 0; | |
219 | int snap_cap_refs = 0; | |
28e407b8 | 220 | xlist<Inode*>::item delay_cap_item, dirty_cap_item, flushing_cap_item; |
7c673cae | 221 | |
b3b6e05e | 222 | SnapRealm *snaprealm = 0; |
7c673cae FG |
223 | xlist<Inode*>::item snaprealm_item; |
224 | InodeRef snapdir_parent; // only if we are a snapdir inode | |
20effc67 | 225 | std::map<snapid_t,CapSnap> cap_snaps; // pending flush to mds |
7c673cae FG |
226 | |
227 | //int open_by_mode[CEPH_FILE_MODE_NUM]; | |
20effc67 TL |
228 | std::map<int,int> open_by_mode; |
229 | std::map<int,int> cap_refs; | |
7c673cae FG |
230 | |
231 | ObjectCacher::ObjectSet oset; // ORDER DEPENDENCY: ino | |
232 | ||
b3b6e05e TL |
233 | uint64_t reported_size = 0; |
234 | uint64_t wanted_max_size = 0; | |
235 | uint64_t requested_max_size = 0; | |
7c673cae | 236 | |
b3b6e05e | 237 | uint64_t ll_ref = 0; // separate ref count for ll client |
11fdf7f2 | 238 | xlist<Dentry *> dentries; // if i'm linked to a dentry. |
20effc67 TL |
239 | std::string symlink; // symlink content, if it's a symlink |
240 | std::map<std::string,bufferptr> xattrs; | |
241 | std::map<frag_t,int> fragmap; // known frag -> mds mappings | |
242 | std::map<frag_t, std::vector<mds_rank_t>> frag_repmap; // non-auth mds mappings | |
7c673cae | 243 | |
9f95a23c TL |
244 | std::list<ceph::condition_variable*> waitfor_caps; |
245 | std::list<ceph::condition_variable*> waitfor_commit; | |
246 | std::list<ceph::condition_variable*> waitfor_deleg; | |
7c673cae FG |
247 | |
248 | Dentry *get_first_parent() { | |
11fdf7f2 TL |
249 | ceph_assert(!dentries.empty()); |
250 | return *dentries.begin(); | |
7c673cae FG |
251 | } |
252 | ||
253 | void make_long_path(filepath& p); | |
f91f0fd5 | 254 | void make_short_path(filepath& p); |
7c673cae FG |
255 | void make_nosnap_relative_path(filepath& p); |
256 | ||
b3b6e05e TL |
257 | // The ref count. 1 for each dentry, fh, inode_map, |
258 | // cwd that links to me. | |
259 | void iget() { get(); } | |
260 | void iput(int n=1) { ceph_assert(n >= 0); while (n--) put(); } | |
7c673cae FG |
261 | |
262 | void ll_get() { | |
263 | ll_ref++; | |
264 | } | |
494da23a | 265 | void ll_put(uint64_t n=1) { |
11fdf7f2 | 266 | ceph_assert(ll_ref >= n); |
7c673cae FG |
267 | ll_ref -= n; |
268 | } | |
269 | ||
270 | // file locks | |
11fdf7f2 TL |
271 | std::unique_ptr<ceph_lock_state_t> fcntl_locks; |
272 | std::unique_ptr<ceph_lock_state_t> flock_locks; | |
7c673cae | 273 | |
f6b5b4d7 TL |
274 | bool has_any_filelocks() { |
275 | return | |
276 | (fcntl_locks && !fcntl_locks->empty()) || | |
277 | (flock_locks && !flock_locks->empty()); | |
278 | } | |
279 | ||
20effc67 | 280 | std::list<Delegation> delegations; |
b32b8144 | 281 | |
7c673cae FG |
282 | xlist<MetaRequest*> unsafe_ops; |
283 | ||
284 | std::set<Fh*> fhs; | |
285 | ||
b3b6e05e | 286 | mds_rank_t dir_pin = MDS_RANK_NONE; |
11fdf7f2 | 287 | |
b3b6e05e | 288 | Inode() = delete; |
7c673cae | 289 | Inode(Client *c, vinodeno_t vino, file_layout_t *newlayout) |
b3b6e05e TL |
290 | : client(c), ino(vino.ino), snapid(vino.snapid), delay_cap_item(this), |
291 | dirty_cap_item(this), flushing_cap_item(this), snaprealm_item(this), | |
292 | oset((void *)this, newlayout->pool_id, this->ino) {} | |
7c673cae FG |
293 | ~Inode(); |
294 | ||
295 | vinodeno_t vino() const { return vinodeno_t(ino, snapid); } | |
296 | ||
297 | struct Compare { | |
298 | bool operator() (Inode* const & left, Inode* const & right) { | |
299 | if (left->ino.val < right->ino.val) { | |
300 | return (left->snapid.val < right->snapid.val); | |
301 | } | |
302 | return false; | |
303 | } | |
304 | }; | |
305 | ||
306 | bool check_mode(const UserPerm& perms, unsigned want); | |
307 | ||
308 | // CAPS -------- | |
309 | void get_open_ref(int mode); | |
310 | bool put_open_ref(int mode); | |
311 | ||
312 | void get_cap_ref(int cap); | |
313 | int put_cap_ref(int cap); | |
314 | bool is_any_caps(); | |
11fdf7f2 | 315 | bool cap_is_valid(const Cap &cap) const; |
7c673cae | 316 | int caps_issued(int *implemented = 0) const; |
7c673cae | 317 | void try_touch_cap(mds_rank_t mds); |
94b18763 | 318 | bool caps_issued_mask(unsigned mask, bool allow_impl=false); |
7c673cae FG |
319 | int caps_used(); |
320 | int caps_file_wanted(); | |
321 | int caps_wanted(); | |
322 | int caps_mds_wanted(); | |
323 | int caps_dirty(); | |
324 | const UserPerm *get_best_perms(); | |
325 | ||
326 | bool have_valid_size(); | |
327 | Dir *open_dir(); | |
328 | ||
329 | void add_fh(Fh *f) {fhs.insert(f);} | |
330 | void rm_fh(Fh *f) {fhs.erase(f);} | |
331 | void set_async_err(int r); | |
332 | void dump(Formatter *f) const; | |
b32b8144 FG |
333 | |
334 | void break_all_delegs() { break_deleg(false); }; | |
335 | ||
336 | void recall_deleg(bool skip_read); | |
337 | bool has_recalled_deleg(); | |
338 | int set_deleg(Fh *fh, unsigned type, ceph_deleg_cb_t cb, void *priv); | |
339 | void unset_deleg(Fh *fh); | |
340 | ||
28e407b8 AA |
341 | void mark_caps_dirty(int caps); |
342 | void mark_caps_clean(); | |
b32b8144 FG |
343 | private: |
344 | // how many opens for write on this Inode? | |
345 | long open_count_for_write() | |
346 | { | |
347 | return (long)(open_by_mode[CEPH_FILE_MODE_RDWR] + | |
348 | open_by_mode[CEPH_FILE_MODE_WR]); | |
349 | }; | |
350 | ||
351 | // how many opens of any sort on this inode? | |
352 | long open_count() | |
353 | { | |
354 | return (long) std::accumulate(open_by_mode.begin(), open_by_mode.end(), 0, | |
355 | [] (int value, const std::map<int, int>::value_type& p) | |
356 | { return value + p.second; }); | |
357 | }; | |
358 | ||
359 | void break_deleg(bool skip_read); | |
360 | bool delegations_broken(bool skip_read); | |
361 | ||
7c673cae FG |
362 | }; |
363 | ||
20effc67 | 364 | std::ostream& operator<<(std::ostream &out, const Inode &in); |
7c673cae FG |
365 | |
366 | #endif |