Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) 2002 Red Hat, Inc. All rights reserved. | |
3 | * | |
4 | * This software may be freely redistributed under the terms of the | |
5 | * GNU General Public License. | |
6 | * | |
7 | * You should have received a copy of the GNU General Public License | |
8 | * along with this program; if not, write to the Free Software | |
9 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
10 | * | |
44d1b980 | 11 | * Authors: David Woodhouse <dwmw2@infradead.org> |
1da177e4 LT |
12 | * David Howells <dhowells@redhat.com> |
13 | * | |
14 | */ | |
15 | ||
16 | #include <linux/kernel.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/init.h> | |
1da177e4 LT |
19 | #include <linux/fs.h> |
20 | #include <linux/pagemap.h> | |
e8edc6e0 | 21 | #include <linux/sched.h> |
bec5eb61 | 22 | #include <linux/mount.h> |
23 | #include <linux/namei.h> | |
a01179e6 | 24 | #include <linux/iversion.h> |
1da177e4 | 25 | #include "internal.h" |
a38a7558 | 26 | #include "afs_fs.h" |
1da177e4 | 27 | |
d3e3b7ea DH |
28 | static const struct inode_operations afs_symlink_inode_operations = { |
29 | .get_link = page_get_link, | |
30 | .listxattr = afs_listxattr, | |
31 | }; | |
32 | ||
b134d687 DH |
33 | static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *parent_vnode) |
34 | { | |
35 | static unsigned long once_only; | |
36 | ||
37 | pr_warn("kAFS: AFS vnode with undefined type %u\n", | |
38 | vnode->status.type); | |
39 | pr_warn("kAFS: A=%d m=%o s=%llx v=%llx\n", | |
40 | vnode->status.abort_code, | |
41 | vnode->status.mode, | |
42 | vnode->status.size, | |
43 | vnode->status.data_version); | |
44 | pr_warn("kAFS: vnode %llx:%llx:%x\n", | |
45 | vnode->fid.vid, | |
46 | vnode->fid.vnode, | |
47 | vnode->fid.unique); | |
48 | if (parent_vnode) | |
49 | pr_warn("kAFS: dir %llx:%llx:%x\n", | |
50 | parent_vnode->fid.vid, | |
51 | parent_vnode->fid.vnode, | |
52 | parent_vnode->fid.unique); | |
53 | ||
54 | if (!test_and_set_bit(0, &once_only)) | |
55 | dump_stack(); | |
56 | } | |
57 | ||
2cd42d19 DH |
58 | /* |
59 | * Set the file size and block count. Estimate the number of 512 bytes blocks | |
60 | * used, rounded up to nearest 1K for consistency with other AFS clients. | |
61 | */ | |
62 | static void afs_set_i_size(struct afs_vnode *vnode, u64 size) | |
63 | { | |
64 | i_size_write(&vnode->vfs_inode, size); | |
65 | vnode->vfs_inode.i_blocks = ((size + 1023) >> 10) << 1; | |
66 | } | |
67 | ||
1da177e4 | 68 | /* |
dd9fbcb8 | 69 | * Initialise an inode from the vnode status. |
1da177e4 | 70 | */ |
b134d687 | 71 | static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, |
a58823ac DH |
72 | struct afs_cb_interest *cbi, |
73 | struct afs_vnode *parent_vnode, | |
74 | struct afs_status_cb *scb) | |
1da177e4 | 75 | { |
a58823ac DH |
76 | struct afs_cb_interest *old_cbi = NULL; |
77 | struct afs_file_status *status = &scb->status; | |
1da177e4 | 78 | struct inode *inode = AFS_VNODE_TO_I(vnode); |
a58823ac | 79 | struct timespec64 t; |
1da177e4 | 80 | |
260a9803 | 81 | _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", |
a58823ac DH |
82 | status->type, |
83 | status->nlink, | |
84 | (unsigned long long) status->size, | |
85 | status->data_version, | |
86 | status->mode); | |
1da177e4 | 87 | |
a58823ac DH |
88 | write_seqlock(&vnode->cb_lock); |
89 | ||
90 | vnode->status = *status; | |
c435ee34 | 91 | |
a58823ac DH |
92 | t = status->mtime_client; |
93 | inode->i_ctime = t; | |
94 | inode->i_mtime = t; | |
95 | inode->i_atime = t; | |
96 | inode->i_uid = make_kuid(&init_user_ns, status->owner); | |
97 | inode->i_gid = make_kgid(&init_user_ns, status->group); | |
98 | set_nlink(&vnode->vfs_inode, status->nlink); | |
dd9fbcb8 | 99 | |
a58823ac | 100 | switch (status->type) { |
1da177e4 | 101 | case AFS_FTYPE_FILE: |
a58823ac | 102 | inode->i_mode = S_IFREG | status->mode; |
1da177e4 | 103 | inode->i_op = &afs_file_inode_operations; |
00d3b7a4 | 104 | inode->i_fop = &afs_file_operations; |
f3ddee8d | 105 | inode->i_mapping->a_ops = &afs_fs_aops; |
1da177e4 LT |
106 | break; |
107 | case AFS_FTYPE_DIR: | |
a58823ac | 108 | inode->i_mode = S_IFDIR | status->mode; |
1da177e4 LT |
109 | inode->i_op = &afs_dir_inode_operations; |
110 | inode->i_fop = &afs_dir_file_operations; | |
f3ddee8d | 111 | inode->i_mapping->a_ops = &afs_dir_aops; |
1da177e4 LT |
112 | break; |
113 | case AFS_FTYPE_SYMLINK: | |
944c74f4 | 114 | /* Symlinks with a mode of 0644 are actually mountpoints. */ |
a58823ac | 115 | if ((status->mode & 0777) == 0644) { |
944c74f4 DH |
116 | inode->i_flags |= S_AUTOMOUNT; |
117 | ||
944c74f4 | 118 | set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); |
944c74f4 DH |
119 | |
120 | inode->i_mode = S_IFDIR | 0555; | |
121 | inode->i_op = &afs_mntpt_inode_operations; | |
122 | inode->i_fop = &afs_mntpt_file_operations; | |
f3ddee8d | 123 | inode->i_mapping->a_ops = &afs_fs_aops; |
944c74f4 | 124 | } else { |
a58823ac | 125 | inode->i_mode = S_IFLNK | status->mode; |
d3e3b7ea | 126 | inode->i_op = &afs_symlink_inode_operations; |
f3ddee8d | 127 | inode->i_mapping->a_ops = &afs_fs_aops; |
944c74f4 | 128 | } |
21fc61c7 | 129 | inode_nohighmem(inode); |
1da177e4 LT |
130 | break; |
131 | default: | |
b134d687 | 132 | dump_vnode(vnode, parent_vnode); |
a58823ac | 133 | write_sequnlock(&vnode->cb_lock); |
160cb957 | 134 | return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type); |
1da177e4 LT |
135 | } |
136 | ||
2cd42d19 | 137 | afs_set_i_size(vnode, status->size); |
c435ee34 | 138 | |
a58823ac DH |
139 | vnode->invalid_before = status->data_version; |
140 | inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | |
141 | ||
142 | if (!scb->have_cb) { | |
143 | /* it's a symlink we just created (the fileserver | |
144 | * didn't give us a callback) */ | |
a58823ac DH |
145 | vnode->cb_expires_at = ktime_get_real_seconds(); |
146 | } else { | |
a58823ac | 147 | vnode->cb_expires_at = scb->callback.expires_at; |
f642404a DH |
148 | old_cbi = rcu_dereference_protected(vnode->cb_interest, |
149 | lockdep_is_held(&vnode->cb_lock.lock)); | |
a58823ac | 150 | if (cbi != old_cbi) |
f642404a | 151 | rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(cbi)); |
a58823ac DH |
152 | else |
153 | old_cbi = NULL; | |
154 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | |
155 | } | |
156 | ||
157 | write_sequnlock(&vnode->cb_lock); | |
158 | afs_put_cb_interest(afs_v2net(vnode), old_cbi); | |
1da177e4 | 159 | return 0; |
ec26815a | 160 | } |
1da177e4 | 161 | |
a58823ac DH |
162 | /* |
163 | * Update the core inode struct from a returned status record. | |
164 | */ | |
165 | static void afs_apply_status(struct afs_fs_cursor *fc, | |
166 | struct afs_vnode *vnode, | |
167 | struct afs_status_cb *scb, | |
168 | const afs_dataversion_t *expected_version) | |
169 | { | |
170 | struct afs_file_status *status = &scb->status; | |
171 | struct timespec64 t; | |
172 | umode_t mode; | |
173 | bool data_changed = false; | |
174 | ||
175 | BUG_ON(test_bit(AFS_VNODE_UNSET, &vnode->flags)); | |
176 | ||
177 | if (status->type != vnode->status.type) { | |
178 | pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n", | |
179 | vnode->fid.vid, | |
180 | vnode->fid.vnode, | |
181 | vnode->fid.unique, | |
182 | status->type, vnode->status.type); | |
183 | afs_protocol_error(NULL, -EBADMSG, afs_eproto_bad_status); | |
184 | return; | |
185 | } | |
186 | ||
187 | if (status->nlink != vnode->status.nlink) | |
188 | set_nlink(&vnode->vfs_inode, status->nlink); | |
189 | ||
190 | if (status->owner != vnode->status.owner) | |
191 | vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); | |
192 | ||
193 | if (status->group != vnode->status.group) | |
194 | vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); | |
195 | ||
196 | if (status->mode != vnode->status.mode) { | |
197 | mode = vnode->vfs_inode.i_mode; | |
198 | mode &= ~S_IALLUGO; | |
199 | mode |= status->mode; | |
200 | WRITE_ONCE(vnode->vfs_inode.i_mode, mode); | |
201 | } | |
202 | ||
203 | t = status->mtime_client; | |
204 | vnode->vfs_inode.i_ctime = t; | |
205 | vnode->vfs_inode.i_mtime = t; | |
206 | vnode->vfs_inode.i_atime = t; | |
207 | ||
208 | if (vnode->status.data_version != status->data_version) | |
209 | data_changed = true; | |
210 | ||
211 | vnode->status = *status; | |
212 | ||
213 | if (expected_version && | |
214 | *expected_version != status->data_version) { | |
3647e42b DH |
215 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) |
216 | pr_warn("kAFS: vnode modified {%llx:%llu} %llx->%llx %s\n", | |
217 | vnode->fid.vid, vnode->fid.vnode, | |
218 | (unsigned long long)*expected_version, | |
219 | (unsigned long long)status->data_version, | |
220 | fc->type ? fc->type->name : "???"); | |
221 | ||
a58823ac DH |
222 | vnode->invalid_before = status->data_version; |
223 | if (vnode->status.type == AFS_FTYPE_DIR) { | |
224 | if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | |
225 | afs_stat_v(vnode, n_inval); | |
226 | } else { | |
227 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | |
228 | } | |
229 | } else if (vnode->status.type == AFS_FTYPE_DIR) { | |
230 | /* Expected directory change is handled elsewhere so | |
231 | * that we can locally edit the directory and save on a | |
232 | * download. | |
233 | */ | |
234 | if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | |
235 | data_changed = false; | |
236 | } | |
237 | ||
238 | if (data_changed) { | |
239 | inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | |
2cd42d19 | 240 | afs_set_i_size(vnode, status->size); |
a58823ac DH |
241 | } |
242 | } | |
243 | ||
244 | /* | |
245 | * Apply a callback to a vnode. | |
246 | */ | |
247 | static void afs_apply_callback(struct afs_fs_cursor *fc, | |
248 | struct afs_vnode *vnode, | |
249 | struct afs_status_cb *scb, | |
250 | unsigned int cb_break) | |
251 | { | |
252 | struct afs_cb_interest *old; | |
253 | struct afs_callback *cb = &scb->callback; | |
254 | ||
255 | if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) { | |
a58823ac | 256 | vnode->cb_expires_at = cb->expires_at; |
f642404a DH |
257 | old = rcu_dereference_protected(vnode->cb_interest, |
258 | lockdep_is_held(&vnode->cb_lock.lock)); | |
a58823ac | 259 | if (old != fc->cbi) { |
f642404a | 260 | rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(fc->cbi)); |
a58823ac DH |
261 | afs_put_cb_interest(afs_v2net(vnode), old); |
262 | } | |
263 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | |
264 | } | |
265 | } | |
266 | ||
267 | /* | |
268 | * Apply the received status and callback to an inode all in the same critical | |
269 | * section to avoid races with afs_validate(). | |
270 | */ | |
271 | void afs_vnode_commit_status(struct afs_fs_cursor *fc, | |
272 | struct afs_vnode *vnode, | |
273 | unsigned int cb_break, | |
274 | const afs_dataversion_t *expected_version, | |
275 | struct afs_status_cb *scb) | |
276 | { | |
277 | if (fc->ac.error != 0) | |
278 | return; | |
279 | ||
280 | write_seqlock(&vnode->cb_lock); | |
281 | ||
a38a7558 DH |
282 | if (scb->have_error) { |
283 | if (scb->status.abort_code == VNOVNODE) { | |
284 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | |
285 | clear_nlink(&vnode->vfs_inode); | |
051d2525 | 286 | __afs_break_callback(vnode, afs_cb_break_for_deleted); |
a38a7558 DH |
287 | } |
288 | } else { | |
289 | if (scb->have_status) | |
290 | afs_apply_status(fc, vnode, scb, expected_version); | |
291 | if (scb->have_cb) | |
292 | afs_apply_callback(fc, vnode, scb, cb_break); | |
293 | } | |
a58823ac DH |
294 | |
295 | write_sequnlock(&vnode->cb_lock); | |
296 | ||
a38a7558 | 297 | if (fc->ac.error == 0 && scb->have_status) |
a58823ac DH |
298 | afs_cache_permit(vnode, fc->key, cb_break, scb); |
299 | } | |
300 | ||
d2ddc776 DH |
301 | /* |
302 | * Fetch file status from the volume. | |
303 | */ | |
a58823ac DH |
304 | int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool is_new, |
305 | afs_access_t *_caller_access) | |
d2ddc776 | 306 | { |
a58823ac | 307 | struct afs_status_cb *scb; |
d2ddc776 DH |
308 | struct afs_fs_cursor fc; |
309 | int ret; | |
310 | ||
3b6492df | 311 | _enter("%s,{%llx:%llu.%u,S=%lx}", |
d2ddc776 DH |
312 | vnode->volume->name, |
313 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, | |
314 | vnode->flags); | |
315 | ||
a58823ac DH |
316 | scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); |
317 | if (!scb) | |
318 | return -ENOMEM; | |
319 | ||
d2ddc776 | 320 | ret = -ERESTARTSYS; |
20b8391f | 321 | if (afs_begin_vnode_operation(&fc, vnode, key, true)) { |
a58823ac DH |
322 | afs_dataversion_t data_version = vnode->status.data_version; |
323 | ||
d2ddc776 | 324 | while (afs_select_fileserver(&fc)) { |
68251f0a | 325 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
a58823ac | 326 | afs_fs_fetch_file_status(&fc, scb, NULL); |
d2ddc776 DH |
327 | } |
328 | ||
a58823ac DH |
329 | if (fc.error) { |
330 | /* Do nothing. */ | |
331 | } else if (is_new) { | |
332 | ret = afs_inode_init_from_status(vnode, key, fc.cbi, | |
333 | NULL, scb); | |
334 | fc.error = ret; | |
335 | if (ret == 0) | |
336 | afs_cache_permit(vnode, key, fc.cb_break, scb); | |
337 | } else { | |
338 | afs_vnode_commit_status(&fc, vnode, fc.cb_break, | |
339 | &data_version, scb); | |
340 | } | |
341 | afs_check_for_remote_deletion(&fc, vnode); | |
d2ddc776 DH |
342 | ret = afs_end_vnode_operation(&fc); |
343 | } | |
344 | ||
a58823ac DH |
345 | if (ret == 0 && _caller_access) |
346 | *_caller_access = scb->status.caller_access; | |
347 | kfree(scb); | |
d2ddc776 DH |
348 | _leave(" = %d", ret); |
349 | return ret; | |
350 | } | |
351 | ||
1da177e4 LT |
352 | /* |
353 | * iget5() comparator | |
354 | */ | |
c435ee34 | 355 | int afs_iget5_test(struct inode *inode, void *opaque) |
1da177e4 | 356 | { |
b8359153 | 357 | struct afs_iget_data *iget_data = opaque; |
3b6492df | 358 | struct afs_vnode *vnode = AFS_FS_I(inode); |
1da177e4 | 359 | |
b8359153 | 360 | return memcmp(&vnode->fid, &iget_data->fid, sizeof(iget_data->fid)) == 0; |
ec26815a | 361 | } |
1da177e4 | 362 | |
bec5eb61 | 363 | /* |
364 | * iget5() comparator for inode created by autocell operations | |
365 | * | |
366 | * These pseudo inodes don't match anything. | |
367 | */ | |
4d673da1 | 368 | static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque) |
bec5eb61 | 369 | { |
370 | return 0; | |
371 | } | |
372 | ||
1da177e4 LT |
373 | /* |
374 | * iget5() inode initialiser | |
375 | */ | |
376 | static int afs_iget5_set(struct inode *inode, void *opaque) | |
377 | { | |
b8359153 | 378 | struct afs_iget_data *iget_data = opaque; |
1da177e4 LT |
379 | struct afs_vnode *vnode = AFS_FS_I(inode); |
380 | ||
b8359153 DH |
381 | vnode->fid = iget_data->fid; |
382 | vnode->volume = iget_data->volume; | |
383 | vnode->cb_v_break = iget_data->cb_v_break; | |
384 | vnode->cb_s_break = iget_data->cb_s_break; | |
1da177e4 | 385 | |
3b6492df DH |
386 | /* YFS supports 96-bit vnode IDs, but Linux only supports |
387 | * 64-bit inode numbers. | |
388 | */ | |
b8359153 DH |
389 | inode->i_ino = iget_data->fid.vnode; |
390 | inode->i_generation = iget_data->fid.unique; | |
1da177e4 | 391 | return 0; |
ec26815a | 392 | } |
1da177e4 | 393 | |
bec5eb61 | 394 | /* |
4d673da1 DH |
395 | * Create an inode for a dynamic root directory or an autocell dynamic |
396 | * automount dir. | |
bec5eb61 | 397 | */ |
4d673da1 | 398 | struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) |
bec5eb61 | 399 | { |
bec5eb61 | 400 | struct afs_super_info *as; |
401 | struct afs_vnode *vnode; | |
bec5eb61 | 402 | struct inode *inode; |
403 | static atomic_t afs_autocell_ino; | |
404 | ||
b8359153 DH |
405 | struct afs_iget_data iget_data = { |
406 | .cb_v_break = 0, | |
407 | .cb_s_break = 0, | |
408 | }; | |
409 | ||
4d673da1 | 410 | _enter(""); |
bec5eb61 | 411 | |
bec5eb61 | 412 | as = sb->s_fs_info; |
4d673da1 | 413 | if (as->volume) { |
b8359153 DH |
414 | iget_data.volume = as->volume; |
415 | iget_data.fid.vid = as->volume->vid; | |
4d673da1 DH |
416 | } |
417 | if (root) { | |
b8359153 DH |
418 | iget_data.fid.vnode = 1; |
419 | iget_data.fid.unique = 1; | |
4d673da1 | 420 | } else { |
b8359153 DH |
421 | iget_data.fid.vnode = atomic_inc_return(&afs_autocell_ino); |
422 | iget_data.fid.unique = 0; | |
4d673da1 | 423 | } |
bec5eb61 | 424 | |
b8359153 | 425 | inode = iget5_locked(sb, iget_data.fid.vnode, |
4d673da1 | 426 | afs_iget5_pseudo_dir_test, afs_iget5_set, |
b8359153 | 427 | &iget_data); |
bec5eb61 | 428 | if (!inode) { |
429 | _leave(" = -ENOMEM"); | |
430 | return ERR_PTR(-ENOMEM); | |
431 | } | |
432 | ||
3b6492df | 433 | _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", |
b8359153 DH |
434 | inode, inode->i_ino, iget_data.fid.vid, iget_data.fid.vnode, |
435 | iget_data.fid.unique); | |
bec5eb61 | 436 | |
437 | vnode = AFS_FS_I(inode); | |
438 | ||
439 | /* there shouldn't be an existing inode */ | |
440 | BUG_ON(!(inode->i_state & I_NEW)); | |
441 | ||
442 | inode->i_size = 0; | |
443 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | |
4d673da1 DH |
444 | if (root) { |
445 | inode->i_op = &afs_dynroot_inode_operations; | |
446 | inode->i_fop = &afs_dynroot_file_operations; | |
447 | } else { | |
448 | inode->i_op = &afs_autocell_inode_operations; | |
449 | } | |
bfe86848 | 450 | set_nlink(inode, 2); |
a0a5386a EB |
451 | inode->i_uid = GLOBAL_ROOT_UID; |
452 | inode->i_gid = GLOBAL_ROOT_GID; | |
ba25b81e | 453 | inode->i_ctime = inode->i_atime = inode->i_mtime = current_time(inode); |
bec5eb61 | 454 | inode->i_blocks = 0; |
a01179e6 | 455 | inode_set_iversion_raw(inode, 0); |
bec5eb61 | 456 | inode->i_generation = 0; |
457 | ||
458 | set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); | |
4d673da1 DH |
459 | if (!root) { |
460 | set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); | |
461 | inode->i_flags |= S_AUTOMOUNT; | |
462 | } | |
463 | ||
464 | inode->i_flags |= S_NOATIME; | |
bec5eb61 | 465 | unlock_new_inode(inode); |
466 | _leave(" = %p", inode); | |
467 | return inode; | |
468 | } | |
469 | ||
402cb8dd DH |
470 | /* |
471 | * Get a cache cookie for an inode. | |
472 | */ | |
473 | static void afs_get_inode_cache(struct afs_vnode *vnode) | |
474 | { | |
475 | #ifdef CONFIG_AFS_FSCACHE | |
476 | struct { | |
477 | u32 vnode_id; | |
478 | u32 unique; | |
479 | u32 vnode_id_ext[2]; /* Allow for a 96-bit key */ | |
480 | } __packed key; | |
481 | struct afs_vnode_cache_aux aux; | |
482 | ||
f3ddee8d DH |
483 | if (vnode->status.type == AFS_FTYPE_DIR) { |
484 | vnode->cache = NULL; | |
485 | return; | |
486 | } | |
487 | ||
402cb8dd DH |
488 | key.vnode_id = vnode->fid.vnode; |
489 | key.unique = vnode->fid.unique; | |
3b6492df DH |
490 | key.vnode_id_ext[0] = vnode->fid.vnode >> 32; |
491 | key.vnode_id_ext[1] = vnode->fid.vnode_hi; | |
402cb8dd DH |
492 | aux.data_version = vnode->status.data_version; |
493 | ||
494 | vnode->cache = fscache_acquire_cookie(vnode->volume->cache, | |
495 | &afs_vnode_cache_index_def, | |
496 | &key, sizeof(key), | |
497 | &aux, sizeof(aux), | |
ee1235a9 | 498 | vnode, vnode->status.size, true); |
402cb8dd DH |
499 | #endif |
500 | } | |
501 | ||
1da177e4 LT |
502 | /* |
503 | * inode retrieval | |
504 | */ | |
260a9803 | 505 | struct inode *afs_iget(struct super_block *sb, struct key *key, |
b8359153 DH |
506 | struct afs_iget_data *iget_data, |
507 | struct afs_status_cb *scb, | |
a58823ac | 508 | struct afs_cb_interest *cbi, |
b134d687 | 509 | struct afs_vnode *parent_vnode) |
1da177e4 | 510 | { |
1da177e4 LT |
511 | struct afs_super_info *as; |
512 | struct afs_vnode *vnode; | |
b8359153 | 513 | struct afs_fid *fid = &iget_data->fid; |
1da177e4 LT |
514 | struct inode *inode; |
515 | int ret; | |
516 | ||
3b6492df | 517 | _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique); |
1da177e4 LT |
518 | |
519 | as = sb->s_fs_info; | |
b8359153 | 520 | iget_data->volume = as->volume; |
1da177e4 LT |
521 | |
522 | inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, | |
b8359153 | 523 | iget_data); |
1da177e4 LT |
524 | if (!inode) { |
525 | _leave(" = -ENOMEM"); | |
08e0e7c8 | 526 | return ERR_PTR(-ENOMEM); |
1da177e4 LT |
527 | } |
528 | ||
3b6492df | 529 | _debug("GOT INODE %p { vl=%llx vn=%llx, u=%x }", |
08e0e7c8 DH |
530 | inode, fid->vid, fid->vnode, fid->unique); |
531 | ||
1da177e4 LT |
532 | vnode = AFS_FS_I(inode); |
533 | ||
534 | /* deal with an existing inode */ | |
535 | if (!(inode->i_state & I_NEW)) { | |
08e0e7c8 DH |
536 | _leave(" = %p", inode); |
537 | return inode; | |
1da177e4 LT |
538 | } |
539 | ||
a58823ac | 540 | if (!scb) { |
260a9803 | 541 | /* it's a remotely extant inode */ |
a58823ac | 542 | ret = afs_fetch_status(vnode, key, true, NULL); |
260a9803 DH |
543 | if (ret < 0) |
544 | goto bad_inode; | |
545 | } else { | |
a58823ac DH |
546 | ret = afs_inode_init_from_status(vnode, key, cbi, parent_vnode, |
547 | scb); | |
548 | if (ret < 0) | |
549 | goto bad_inode; | |
260a9803 DH |
550 | } |
551 | ||
5800db81 DH |
552 | afs_get_inode_cache(vnode); |
553 | ||
1da177e4 | 554 | /* success */ |
260a9803 | 555 | clear_bit(AFS_VNODE_UNSET, &vnode->flags); |
08e0e7c8 | 556 | inode->i_flags |= S_NOATIME; |
1da177e4 | 557 | unlock_new_inode(inode); |
7c712458 | 558 | _leave(" = %p", inode); |
08e0e7c8 | 559 | return inode; |
1da177e4 LT |
560 | |
561 | /* failure */ | |
ec26815a | 562 | bad_inode: |
aa7fa240 | 563 | iget_failed(inode); |
1da177e4 | 564 | _leave(" = %d [bad]", ret); |
08e0e7c8 | 565 | return ERR_PTR(ret); |
ec26815a | 566 | } |
1da177e4 | 567 | |
416351f2 DH |
568 | /* |
569 | * mark the data attached to an inode as obsolete due to a write on the server | |
570 | * - might also want to ditch all the outstanding writes and dirty pages | |
571 | */ | |
572 | void afs_zap_data(struct afs_vnode *vnode) | |
573 | { | |
3b6492df | 574 | _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); |
416351f2 | 575 | |
c1515999 DH |
576 | #ifdef CONFIG_AFS_FSCACHE |
577 | fscache_invalidate(vnode->cache); | |
578 | #endif | |
579 | ||
416351f2 | 580 | /* nuke all the non-dirty pages that aren't locked, mapped or being |
0f300ca9 DH |
581 | * written back in a regular file and completely discard the pages in a |
582 | * directory or symlink */ | |
583 | if (S_ISREG(vnode->vfs_inode.i_mode)) | |
584 | invalidate_remote_inode(&vnode->vfs_inode); | |
585 | else | |
586 | invalidate_inode_pages2(vnode->vfs_inode.i_mapping); | |
416351f2 DH |
587 | } |
588 | ||
260a9803 | 589 | /* |
c925bd0a | 590 | * Check the validity of a vnode/inode. |
260a9803 | 591 | */ |
c925bd0a | 592 | bool afs_check_validity(struct afs_vnode *vnode) |
260a9803 | 593 | { |
f642404a DH |
594 | struct afs_cb_interest *cbi; |
595 | struct afs_server *server; | |
596 | struct afs_volume *volume = vnode->volume; | |
051d2525 | 597 | enum afs_cb_break_reason need_clear = afs_cb_break_no_break; |
c435ee34 | 598 | time64_t now = ktime_get_real_seconds(); |
051d2525 | 599 | bool valid; |
f642404a DH |
600 | unsigned int cb_break, cb_s_break, cb_v_break; |
601 | int seq = 0; | |
260a9803 | 602 | |
f642404a DH |
603 | do { |
604 | read_seqbegin_or_lock(&vnode->cb_lock, &seq); | |
605 | cb_v_break = READ_ONCE(volume->cb_v_break); | |
606 | cb_break = vnode->cb_break; | |
607 | ||
608 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | |
609 | cbi = rcu_dereference(vnode->cb_interest); | |
610 | server = rcu_dereference(cbi->server); | |
611 | cb_s_break = READ_ONCE(server->cb_s_break); | |
612 | ||
613 | if (vnode->cb_s_break != cb_s_break || | |
614 | vnode->cb_v_break != cb_v_break) { | |
615 | vnode->cb_s_break = cb_s_break; | |
616 | vnode->cb_v_break = cb_v_break; | |
051d2525 | 617 | need_clear = afs_cb_break_for_vsbreak; |
f642404a DH |
618 | valid = false; |
619 | } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | |
051d2525 | 620 | need_clear = afs_cb_break_for_zap; |
f642404a DH |
621 | valid = false; |
622 | } else if (vnode->cb_expires_at - 10 <= now) { | |
051d2525 | 623 | need_clear = afs_cb_break_for_lapsed; |
f642404a DH |
624 | valid = false; |
625 | } else { | |
626 | valid = true; | |
627 | } | |
628 | } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | |
68251f0a | 629 | valid = true; |
f642404a DH |
630 | } else { |
631 | vnode->cb_v_break = cb_v_break; | |
632 | valid = false; | |
260a9803 | 633 | } |
260a9803 | 634 | |
f642404a DH |
635 | } while (need_seqretry(&vnode->cb_lock, seq)); |
636 | ||
637 | done_seqretry(&vnode->cb_lock, seq); | |
61c347ba | 638 | |
051d2525 | 639 | if (need_clear != afs_cb_break_no_break) { |
61c347ba DH |
640 | write_seqlock(&vnode->cb_lock); |
641 | if (cb_break == vnode->cb_break) | |
051d2525 DH |
642 | __afs_break_callback(vnode, need_clear); |
643 | else | |
644 | trace_afs_cb_miss(&vnode->fid, need_clear); | |
61c347ba DH |
645 | write_sequnlock(&vnode->cb_lock); |
646 | valid = false; | |
647 | } | |
648 | ||
c925bd0a DH |
649 | return valid; |
650 | } | |
651 | ||
652 | /* | |
653 | * validate a vnode/inode | |
654 | * - there are several things we need to check | |
655 | * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, | |
656 | * symlink) | |
657 | * - parent dir metadata changed (security changes) | |
658 | * - dentry data changed (write, truncate) | |
659 | * - dentry metadata changed (security changes) | |
660 | */ | |
661 | int afs_validate(struct afs_vnode *vnode, struct key *key) | |
662 | { | |
663 | bool valid; | |
664 | int ret; | |
665 | ||
666 | _enter("{v={%llx:%llu} fl=%lx},%x", | |
667 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, | |
668 | key_serial(key)); | |
669 | ||
f642404a | 670 | rcu_read_lock(); |
c925bd0a | 671 | valid = afs_check_validity(vnode); |
f642404a | 672 | rcu_read_unlock(); |
440fbc3a DH |
673 | |
674 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | |
675 | clear_nlink(&vnode->vfs_inode); | |
676 | ||
c435ee34 | 677 | if (valid) |
260a9803 DH |
678 | goto valid; |
679 | ||
b61f7dcf | 680 | down_write(&vnode->validate_lock); |
260a9803 DH |
681 | |
682 | /* if the promise has expired, we need to check the server again to get | |
683 | * a new promise - note that if the (parent) directory's metadata was | |
684 | * changed then the security may be different and we may no longer have | |
685 | * access */ | |
c435ee34 | 686 | if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { |
260a9803 | 687 | _debug("not promised"); |
a58823ac | 688 | ret = afs_fetch_status(vnode, key, false, NULL); |
c435ee34 DH |
689 | if (ret < 0) { |
690 | if (ret == -ENOENT) { | |
691 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | |
692 | ret = -ESTALE; | |
693 | } | |
260a9803 | 694 | goto error_unlock; |
c435ee34 | 695 | } |
260a9803 DH |
696 | _debug("new promise [fl=%lx]", vnode->flags); |
697 | } | |
698 | ||
699 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | |
700 | _debug("file already deleted"); | |
701 | ret = -ESTALE; | |
702 | goto error_unlock; | |
703 | } | |
704 | ||
705 | /* if the vnode's data version number changed then its contents are | |
706 | * different */ | |
416351f2 DH |
707 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) |
708 | afs_zap_data(vnode); | |
b61f7dcf | 709 | up_write(&vnode->validate_lock); |
260a9803 DH |
710 | valid: |
711 | _leave(" = 0"); | |
712 | return 0; | |
713 | ||
714 | error_unlock: | |
b61f7dcf | 715 | up_write(&vnode->validate_lock); |
260a9803 DH |
716 | _leave(" = %d", ret); |
717 | return ret; | |
718 | } | |
719 | ||
1da177e4 LT |
720 | /* |
721 | * read the attributes of an inode | |
722 | */ | |
a528d35e DH |
723 | int afs_getattr(const struct path *path, struct kstat *stat, |
724 | u32 request_mask, unsigned int query_flags) | |
1da177e4 | 725 | { |
a528d35e | 726 | struct inode *inode = d_inode(path->dentry); |
c435ee34 DH |
727 | struct afs_vnode *vnode = AFS_FS_I(inode); |
728 | int seq = 0; | |
1da177e4 | 729 | |
d6e43f75 | 730 | _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); |
1da177e4 | 731 | |
c435ee34 DH |
732 | do { |
733 | read_seqbegin_or_lock(&vnode->cb_lock, &seq); | |
734 | generic_fillattr(inode, stat); | |
735 | } while (need_seqretry(&vnode->cb_lock, seq)); | |
736 | ||
737 | done_seqretry(&vnode->cb_lock, seq); | |
1da177e4 | 738 | return 0; |
ec26815a | 739 | } |
1da177e4 | 740 | |
bec5eb61 | 741 | /* |
742 | * discard an AFS inode | |
743 | */ | |
744 | int afs_drop_inode(struct inode *inode) | |
745 | { | |
746 | _enter(""); | |
747 | ||
748 | if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) | |
749 | return generic_delete_inode(inode); | |
750 | else | |
751 | return generic_drop_inode(inode); | |
752 | } | |
753 | ||
1da177e4 LT |
754 | /* |
755 | * clear an AFS inode | |
756 | */ | |
b57922d9 | 757 | void afs_evict_inode(struct inode *inode) |
1da177e4 | 758 | { |
f642404a | 759 | struct afs_cb_interest *cbi; |
1da177e4 LT |
760 | struct afs_vnode *vnode; |
761 | ||
762 | vnode = AFS_FS_I(inode); | |
763 | ||
3b6492df | 764 | _enter("{%llx:%llu.%d}", |
260a9803 | 765 | vnode->fid.vid, |
1da177e4 | 766 | vnode->fid.vnode, |
c435ee34 | 767 | vnode->fid.unique); |
1da177e4 | 768 | |
08e0e7c8 DH |
769 | _debug("CLEAR INODE %p", inode); |
770 | ||
771 | ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); | |
772 | ||
91b0abe3 | 773 | truncate_inode_pages_final(&inode->i_data); |
dbd5768f | 774 | clear_inode(inode); |
b57922d9 | 775 | |
f642404a DH |
776 | write_seqlock(&vnode->cb_lock); |
777 | cbi = rcu_dereference_protected(vnode->cb_interest, | |
778 | lockdep_is_held(&vnode->cb_lock.lock)); | |
779 | if (cbi) { | |
780 | afs_put_cb_interest(afs_i2net(inode), cbi); | |
781 | rcu_assign_pointer(vnode->cb_interest, NULL); | |
08e0e7c8 | 782 | } |
f642404a | 783 | write_sequnlock(&vnode->cb_lock); |
1da177e4 | 784 | |
4343d008 DH |
785 | while (!list_empty(&vnode->wb_keys)) { |
786 | struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next, | |
787 | struct afs_wb_key, vnode_link); | |
788 | list_del(&wbk->vnode_link); | |
789 | afs_put_wb_key(wbk); | |
790 | } | |
1da177e4 | 791 | |
9b3f26c9 | 792 | #ifdef CONFIG_AFS_FSCACHE |
402cb8dd DH |
793 | { |
794 | struct afs_vnode_cache_aux aux; | |
795 | ||
796 | aux.data_version = vnode->status.data_version; | |
797 | fscache_relinquish_cookie(vnode->cache, &aux, | |
798 | test_bit(AFS_VNODE_DELETED, &vnode->flags)); | |
799 | vnode->cache = NULL; | |
800 | } | |
1da177e4 LT |
801 | #endif |
802 | ||
a1b879ee | 803 | afs_prune_wb_keys(vnode); |
fe342cf7 | 804 | afs_put_permits(rcu_access_pointer(vnode->permit_cache)); |
79ddbfa5 DH |
805 | key_put(vnode->silly_key); |
806 | vnode->silly_key = NULL; | |
59d49076 DH |
807 | key_put(vnode->lock_key); |
808 | vnode->lock_key = NULL; | |
1da177e4 | 809 | _leave(""); |
ec26815a | 810 | } |
31143d5d DH |
811 | |
812 | /* | |
813 | * set the attributes of an inode | |
814 | */ | |
815 | int afs_setattr(struct dentry *dentry, struct iattr *attr) | |
816 | { | |
d2ddc776 | 817 | struct afs_fs_cursor fc; |
a58823ac | 818 | struct afs_status_cb *scb; |
2b0143b5 | 819 | struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); |
31143d5d | 820 | struct key *key; |
a58823ac | 821 | int ret = -ENOMEM; |
31143d5d | 822 | |
3b6492df | 823 | _enter("{%llx:%llu},{n=%pd},%x", |
a455589f | 824 | vnode->fid.vid, vnode->fid.vnode, dentry, |
31143d5d DH |
825 | attr->ia_valid); |
826 | ||
827 | if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | | |
828 | ATTR_MTIME))) { | |
829 | _leave(" = 0 [unsupported]"); | |
830 | return 0; | |
831 | } | |
832 | ||
a58823ac DH |
833 | scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); |
834 | if (!scb) | |
835 | goto error; | |
836 | ||
31143d5d | 837 | /* flush any dirty data outstanding on a regular file */ |
4343d008 | 838 | if (S_ISREG(vnode->vfs_inode.i_mode)) |
31143d5d | 839 | filemap_write_and_wait(vnode->vfs_inode.i_mapping); |
31143d5d DH |
840 | |
841 | if (attr->ia_valid & ATTR_FILE) { | |
215804a9 | 842 | key = afs_file_key(attr->ia_file); |
31143d5d DH |
843 | } else { |
844 | key = afs_request_key(vnode->volume->cell); | |
845 | if (IS_ERR(key)) { | |
846 | ret = PTR_ERR(key); | |
a58823ac | 847 | goto error_scb; |
31143d5d DH |
848 | } |
849 | } | |
850 | ||
d2ddc776 | 851 | ret = -ERESTARTSYS; |
20b8391f | 852 | if (afs_begin_vnode_operation(&fc, vnode, key, false)) { |
a58823ac DH |
853 | afs_dataversion_t data_version = vnode->status.data_version; |
854 | ||
855 | if (attr->ia_valid & ATTR_SIZE) | |
856 | data_version++; | |
857 | ||
d2ddc776 | 858 | while (afs_select_fileserver(&fc)) { |
68251f0a | 859 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
a58823ac | 860 | afs_fs_setattr(&fc, attr, scb); |
d2ddc776 DH |
861 | } |
862 | ||
a58823ac DH |
863 | afs_check_for_remote_deletion(&fc, vnode); |
864 | afs_vnode_commit_status(&fc, vnode, fc.cb_break, | |
865 | &data_version, scb); | |
d2ddc776 DH |
866 | ret = afs_end_vnode_operation(&fc); |
867 | } | |
868 | ||
31143d5d DH |
869 | if (!(attr->ia_valid & ATTR_FILE)) |
870 | key_put(key); | |
871 | ||
a58823ac DH |
872 | error_scb: |
873 | kfree(scb); | |
31143d5d DH |
874 | error: |
875 | _leave(" = %d", ret); | |
876 | return ret; | |
877 | } |