diff options
Diffstat (limited to 'fs/afs/vnode.c')
-rw-r--r-- | fs/afs/vnode.c | 422 |
1 files changed, 394 insertions, 28 deletions
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index 160097619ec7..a1904ab8426a 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
@@ -30,7 +30,7 @@ static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent, | |||
30 | bad = dump_tree_aux(node->rb_left, node, depth + 2, '/'); | 30 | bad = dump_tree_aux(node->rb_left, node, depth + 2, '/'); |
31 | 31 | ||
32 | vnode = rb_entry(node, struct afs_vnode, cb_promise); | 32 | vnode = rb_entry(node, struct afs_vnode, cb_promise); |
33 | kdebug("%c %*.*s%c%p {%d}", | 33 | _debug("%c %*.*s%c%p {%d}", |
34 | rb_is_red(node) ? 'R' : 'B', | 34 | rb_is_red(node) ? 'R' : 'B', |
35 | depth, depth, "", lr, | 35 | depth, depth, "", lr, |
36 | vnode, vnode->cb_expires_at); | 36 | vnode, vnode->cb_expires_at); |
@@ -47,7 +47,7 @@ static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent, | |||
47 | 47 | ||
48 | static noinline void dump_tree(const char *name, struct afs_server *server) | 48 | static noinline void dump_tree(const char *name, struct afs_server *server) |
49 | { | 49 | { |
50 | kenter("%s", name); | 50 | _enter("%s", name); |
51 | if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-')) | 51 | if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-')) |
52 | BUG(); | 52 | BUG(); |
53 | } | 53 | } |
@@ -187,47 +187,61 @@ static void afs_vnode_deleted_remotely(struct afs_vnode *vnode) | |||
187 | spin_unlock(&server->cb_lock); | 187 | spin_unlock(&server->cb_lock); |
188 | } | 188 | } |
189 | 189 | ||
190 | spin_lock(&vnode->server->fs_lock); | ||
191 | rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes); | ||
192 | spin_unlock(&vnode->server->fs_lock); | ||
193 | |||
194 | vnode->server = NULL; | ||
190 | afs_put_server(server); | 195 | afs_put_server(server); |
191 | } | 196 | } |
192 | 197 | ||
193 | /* | 198 | /* |
194 | * finish off updating the recorded status of a file | 199 | * finish off updating the recorded status of a file after a successful |
200 | * operation completion | ||
195 | * - starts callback expiry timer | 201 | * - starts callback expiry timer |
196 | * - adds to server's callback list | 202 | * - adds to server's callback list |
197 | */ | 203 | */ |
198 | static void afs_vnode_finalise_status_update(struct afs_vnode *vnode, | 204 | void afs_vnode_finalise_status_update(struct afs_vnode *vnode, |
199 | struct afs_server *server, | 205 | struct afs_server *server) |
200 | int ret) | ||
201 | { | 206 | { |
202 | struct afs_server *oldserver = NULL; | 207 | struct afs_server *oldserver = NULL; |
203 | 208 | ||
204 | _enter("%p,%p,%d", vnode, server, ret); | 209 | _enter("%p,%p", vnode, server); |
210 | |||
211 | spin_lock(&vnode->lock); | ||
212 | clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | ||
213 | afs_vnode_note_promise(vnode, server); | ||
214 | vnode->update_cnt--; | ||
215 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
216 | spin_unlock(&vnode->lock); | ||
217 | |||
218 | wake_up_all(&vnode->update_waitq); | ||
219 | afs_put_server(oldserver); | ||
220 | _leave(""); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * finish off updating the recorded status of a file after an operation failed | ||
225 | */ | ||
226 | static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret) | ||
227 | { | ||
228 | _enter("%p,%d", vnode, ret); | ||
205 | 229 | ||
206 | spin_lock(&vnode->lock); | 230 | spin_lock(&vnode->lock); |
207 | 231 | ||
208 | clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); | 232 | clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); |
209 | 233 | ||
210 | switch (ret) { | 234 | if (ret == -ENOENT) { |
211 | case 0: | ||
212 | afs_vnode_note_promise(vnode, server); | ||
213 | break; | ||
214 | case -ENOENT: | ||
215 | /* the file was deleted on the server */ | 235 | /* the file was deleted on the server */ |
216 | _debug("got NOENT from server - marking file deleted"); | 236 | _debug("got NOENT from server - marking file deleted"); |
217 | afs_vnode_deleted_remotely(vnode); | 237 | afs_vnode_deleted_remotely(vnode); |
218 | break; | ||
219 | default: | ||
220 | break; | ||
221 | } | 238 | } |
222 | 239 | ||
223 | vnode->update_cnt--; | 240 | vnode->update_cnt--; |
224 | 241 | ASSERTCMP(vnode->update_cnt, >=, 0); | |
225 | spin_unlock(&vnode->lock); | 242 | spin_unlock(&vnode->lock); |
226 | 243 | ||
227 | wake_up_all(&vnode->update_waitq); | 244 | wake_up_all(&vnode->update_waitq); |
228 | |||
229 | afs_put_server(oldserver); | ||
230 | |||
231 | _leave(""); | 245 | _leave(""); |
232 | } | 246 | } |
233 | 247 | ||
@@ -275,8 +289,12 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode, | |||
275 | return 0; | 289 | return 0; |
276 | } | 290 | } |
277 | 291 | ||
292 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
293 | |||
278 | if (vnode->update_cnt > 0) { | 294 | if (vnode->update_cnt > 0) { |
279 | /* someone else started a fetch */ | 295 | /* someone else started a fetch */ |
296 | _debug("wait on fetch %d", vnode->update_cnt); | ||
297 | |||
280 | set_current_state(TASK_UNINTERRUPTIBLE); | 298 | set_current_state(TASK_UNINTERRUPTIBLE); |
281 | ASSERT(myself.func != NULL); | 299 | ASSERT(myself.func != NULL); |
282 | add_wait_queue(&vnode->update_waitq, &myself); | 300 | add_wait_queue(&vnode->update_waitq, &myself); |
@@ -325,7 +343,7 @@ get_anyway: | |||
325 | /* pick a server to query */ | 343 | /* pick a server to query */ |
326 | server = afs_volume_pick_fileserver(vnode); | 344 | server = afs_volume_pick_fileserver(vnode); |
327 | if (IS_ERR(server)) | 345 | if (IS_ERR(server)) |
328 | return PTR_ERR(server); | 346 | goto no_server; |
329 | 347 | ||
330 | _debug("USING SERVER: %p{%08x}", | 348 | _debug("USING SERVER: %p{%08x}", |
331 | server, ntohl(server->addr.s_addr)); | 349 | server, ntohl(server->addr.s_addr)); |
@@ -336,17 +354,34 @@ get_anyway: | |||
336 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | 354 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
337 | 355 | ||
338 | /* adjust the flags */ | 356 | /* adjust the flags */ |
339 | if (ret == 0 && auth_vnode) | 357 | if (ret == 0) { |
340 | afs_cache_permit(vnode, key, acl_order); | 358 | _debug("adjust"); |
341 | afs_vnode_finalise_status_update(vnode, server, ret); | 359 | if (auth_vnode) |
360 | afs_cache_permit(vnode, key, acl_order); | ||
361 | afs_vnode_finalise_status_update(vnode, server); | ||
362 | afs_put_server(server); | ||
363 | } else { | ||
364 | _debug("failed [%d]", ret); | ||
365 | afs_vnode_status_update_failed(vnode, ret); | ||
366 | } | ||
342 | 367 | ||
343 | _leave(" = %d", ret); | 368 | ASSERTCMP(vnode->update_cnt, >=, 0); |
369 | |||
370 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
344 | return ret; | 371 | return ret; |
372 | |||
373 | no_server: | ||
374 | spin_lock(&vnode->lock); | ||
375 | vnode->update_cnt--; | ||
376 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
377 | spin_unlock(&vnode->lock); | ||
378 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
379 | return PTR_ERR(server); | ||
345 | } | 380 | } |
346 | 381 | ||
347 | /* | 382 | /* |
348 | * fetch file data from the volume | 383 | * fetch file data from the volume |
349 | * - TODO implement caching and server failover | 384 | * - TODO implement caching |
350 | */ | 385 | */ |
351 | int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, | 386 | int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, |
352 | off_t offset, size_t length, struct page *page) | 387 | off_t offset, size_t length, struct page *page) |
@@ -372,18 +407,349 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, | |||
372 | /* pick a server to query */ | 407 | /* pick a server to query */ |
373 | server = afs_volume_pick_fileserver(vnode); | 408 | server = afs_volume_pick_fileserver(vnode); |
374 | if (IS_ERR(server)) | 409 | if (IS_ERR(server)) |
375 | return PTR_ERR(server); | 410 | goto no_server; |
376 | 411 | ||
377 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | 412 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); |
378 | 413 | ||
379 | ret = afs_fs_fetch_data(server, key, vnode, offset, length, | 414 | ret = afs_fs_fetch_data(server, key, vnode, offset, length, |
380 | page, NULL, &afs_sync_call); | 415 | page, &afs_sync_call); |
381 | 416 | ||
382 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | 417 | } while (!afs_volume_release_fileserver(vnode, server, ret)); |
383 | 418 | ||
384 | /* adjust the flags */ | 419 | /* adjust the flags */ |
385 | afs_vnode_finalise_status_update(vnode, server, ret); | 420 | if (ret == 0) { |
421 | afs_vnode_finalise_status_update(vnode, server); | ||
422 | afs_put_server(server); | ||
423 | } else { | ||
424 | afs_vnode_status_update_failed(vnode, ret); | ||
425 | } | ||
386 | 426 | ||
387 | _leave(" = %d", ret); | 427 | _leave(" = %d", ret); |
388 | return ret; | 428 | return ret; |
429 | |||
430 | no_server: | ||
431 | spin_lock(&vnode->lock); | ||
432 | vnode->update_cnt--; | ||
433 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
434 | spin_unlock(&vnode->lock); | ||
435 | return PTR_ERR(server); | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | * make a file or a directory | ||
440 | */ | ||
441 | int afs_vnode_create(struct afs_vnode *vnode, struct key *key, | ||
442 | const char *name, umode_t mode, struct afs_fid *newfid, | ||
443 | struct afs_file_status *newstatus, | ||
444 | struct afs_callback *newcb, struct afs_server **_server) | ||
445 | { | ||
446 | struct afs_server *server; | ||
447 | int ret; | ||
448 | |||
449 | _enter("%s{%u,%u,%u},%x,%s,,", | ||
450 | vnode->volume->vlocation->vldb.name, | ||
451 | vnode->fid.vid, | ||
452 | vnode->fid.vnode, | ||
453 | vnode->fid.unique, | ||
454 | key_serial(key), | ||
455 | name); | ||
456 | |||
457 | /* this op will fetch the status on the directory we're creating in */ | ||
458 | spin_lock(&vnode->lock); | ||
459 | vnode->update_cnt++; | ||
460 | spin_unlock(&vnode->lock); | ||
461 | |||
462 | do { | ||
463 | /* pick a server to query */ | ||
464 | server = afs_volume_pick_fileserver(vnode); | ||
465 | if (IS_ERR(server)) | ||
466 | goto no_server; | ||
467 | |||
468 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
469 | |||
470 | ret = afs_fs_create(server, key, vnode, name, mode, newfid, | ||
471 | newstatus, newcb, &afs_sync_call); | ||
472 | |||
473 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
474 | |||
475 | /* adjust the flags */ | ||
476 | if (ret == 0) { | ||
477 | afs_vnode_finalise_status_update(vnode, server); | ||
478 | *_server = server; | ||
479 | } else { | ||
480 | afs_vnode_status_update_failed(vnode, ret); | ||
481 | *_server = NULL; | ||
482 | } | ||
483 | |||
484 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
485 | return ret; | ||
486 | |||
487 | no_server: | ||
488 | spin_lock(&vnode->lock); | ||
489 | vnode->update_cnt--; | ||
490 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
491 | spin_unlock(&vnode->lock); | ||
492 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
493 | return PTR_ERR(server); | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * remove a file or directory | ||
498 | */ | ||
499 | int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name, | ||
500 | bool isdir) | ||
501 | { | ||
502 | struct afs_server *server; | ||
503 | int ret; | ||
504 | |||
505 | _enter("%s{%u,%u,%u},%x,%s", | ||
506 | vnode->volume->vlocation->vldb.name, | ||
507 | vnode->fid.vid, | ||
508 | vnode->fid.vnode, | ||
509 | vnode->fid.unique, | ||
510 | key_serial(key), | ||
511 | name); | ||
512 | |||
513 | /* this op will fetch the status on the directory we're removing from */ | ||
514 | spin_lock(&vnode->lock); | ||
515 | vnode->update_cnt++; | ||
516 | spin_unlock(&vnode->lock); | ||
517 | |||
518 | do { | ||
519 | /* pick a server to query */ | ||
520 | server = afs_volume_pick_fileserver(vnode); | ||
521 | if (IS_ERR(server)) | ||
522 | goto no_server; | ||
523 | |||
524 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
525 | |||
526 | ret = afs_fs_remove(server, key, vnode, name, isdir, | ||
527 | &afs_sync_call); | ||
528 | |||
529 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
530 | |||
531 | /* adjust the flags */ | ||
532 | if (ret == 0) { | ||
533 | afs_vnode_finalise_status_update(vnode, server); | ||
534 | afs_put_server(server); | ||
535 | } else { | ||
536 | afs_vnode_status_update_failed(vnode, ret); | ||
537 | } | ||
538 | |||
539 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
540 | return ret; | ||
541 | |||
542 | no_server: | ||
543 | spin_lock(&vnode->lock); | ||
544 | vnode->update_cnt--; | ||
545 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
546 | spin_unlock(&vnode->lock); | ||
547 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
548 | return PTR_ERR(server); | ||
549 | } | ||
550 | |||
551 | /* | ||
552 | * create a hard link | ||
553 | */ | ||
554 | extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode, | ||
555 | struct key *key, const char *name) | ||
556 | { | ||
557 | struct afs_server *server; | ||
558 | int ret; | ||
559 | |||
560 | _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s", | ||
561 | dvnode->volume->vlocation->vldb.name, | ||
562 | dvnode->fid.vid, | ||
563 | dvnode->fid.vnode, | ||
564 | dvnode->fid.unique, | ||
565 | vnode->volume->vlocation->vldb.name, | ||
566 | vnode->fid.vid, | ||
567 | vnode->fid.vnode, | ||
568 | vnode->fid.unique, | ||
569 | key_serial(key), | ||
570 | name); | ||
571 | |||
572 | /* this op will fetch the status on the directory we're removing from */ | ||
573 | spin_lock(&vnode->lock); | ||
574 | vnode->update_cnt++; | ||
575 | spin_unlock(&vnode->lock); | ||
576 | spin_lock(&dvnode->lock); | ||
577 | dvnode->update_cnt++; | ||
578 | spin_unlock(&dvnode->lock); | ||
579 | |||
580 | do { | ||
581 | /* pick a server to query */ | ||
582 | server = afs_volume_pick_fileserver(dvnode); | ||
583 | if (IS_ERR(server)) | ||
584 | goto no_server; | ||
585 | |||
586 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
587 | |||
588 | ret = afs_fs_link(server, key, dvnode, vnode, name, | ||
589 | &afs_sync_call); | ||
590 | |||
591 | } while (!afs_volume_release_fileserver(dvnode, server, ret)); | ||
592 | |||
593 | /* adjust the flags */ | ||
594 | if (ret == 0) { | ||
595 | afs_vnode_finalise_status_update(vnode, server); | ||
596 | afs_vnode_finalise_status_update(dvnode, server); | ||
597 | afs_put_server(server); | ||
598 | } else { | ||
599 | afs_vnode_status_update_failed(vnode, ret); | ||
600 | afs_vnode_status_update_failed(dvnode, ret); | ||
601 | } | ||
602 | |||
603 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
604 | return ret; | ||
605 | |||
606 | no_server: | ||
607 | spin_lock(&vnode->lock); | ||
608 | vnode->update_cnt--; | ||
609 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
610 | spin_unlock(&vnode->lock); | ||
611 | spin_lock(&dvnode->lock); | ||
612 | dvnode->update_cnt--; | ||
613 | ASSERTCMP(dvnode->update_cnt, >=, 0); | ||
614 | spin_unlock(&dvnode->lock); | ||
615 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
616 | return PTR_ERR(server); | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * create a symbolic link | ||
621 | */ | ||
622 | int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key, | ||
623 | const char *name, const char *content, | ||
624 | struct afs_fid *newfid, | ||
625 | struct afs_file_status *newstatus, | ||
626 | struct afs_server **_server) | ||
627 | { | ||
628 | struct afs_server *server; | ||
629 | int ret; | ||
630 | |||
631 | _enter("%s{%u,%u,%u},%x,%s,%s,,,", | ||
632 | vnode->volume->vlocation->vldb.name, | ||
633 | vnode->fid.vid, | ||
634 | vnode->fid.vnode, | ||
635 | vnode->fid.unique, | ||
636 | key_serial(key), | ||
637 | name, content); | ||
638 | |||
639 | /* this op will fetch the status on the directory we're creating in */ | ||
640 | spin_lock(&vnode->lock); | ||
641 | vnode->update_cnt++; | ||
642 | spin_unlock(&vnode->lock); | ||
643 | |||
644 | do { | ||
645 | /* pick a server to query */ | ||
646 | server = afs_volume_pick_fileserver(vnode); | ||
647 | if (IS_ERR(server)) | ||
648 | goto no_server; | ||
649 | |||
650 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
651 | |||
652 | ret = afs_fs_symlink(server, key, vnode, name, content, | ||
653 | newfid, newstatus, &afs_sync_call); | ||
654 | |||
655 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
656 | |||
657 | /* adjust the flags */ | ||
658 | if (ret == 0) { | ||
659 | afs_vnode_finalise_status_update(vnode, server); | ||
660 | *_server = server; | ||
661 | } else { | ||
662 | afs_vnode_status_update_failed(vnode, ret); | ||
663 | *_server = NULL; | ||
664 | } | ||
665 | |||
666 | _leave(" = %d [cnt %d]", ret, vnode->update_cnt); | ||
667 | return ret; | ||
668 | |||
669 | no_server: | ||
670 | spin_lock(&vnode->lock); | ||
671 | vnode->update_cnt--; | ||
672 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
673 | spin_unlock(&vnode->lock); | ||
674 | _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); | ||
675 | return PTR_ERR(server); | ||
676 | } | ||
677 | |||
678 | /* | ||
679 | * rename a file | ||
680 | */ | ||
681 | int afs_vnode_rename(struct afs_vnode *orig_dvnode, | ||
682 | struct afs_vnode *new_dvnode, | ||
683 | struct key *key, | ||
684 | const char *orig_name, | ||
685 | const char *new_name) | ||
686 | { | ||
687 | struct afs_server *server; | ||
688 | int ret; | ||
689 | |||
690 | _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s", | ||
691 | orig_dvnode->volume->vlocation->vldb.name, | ||
692 | orig_dvnode->fid.vid, | ||
693 | orig_dvnode->fid.vnode, | ||
694 | orig_dvnode->fid.unique, | ||
695 | new_dvnode->volume->vlocation->vldb.name, | ||
696 | new_dvnode->fid.vid, | ||
697 | new_dvnode->fid.vnode, | ||
698 | new_dvnode->fid.unique, | ||
699 | key_serial(key), | ||
700 | orig_name, | ||
701 | new_name); | ||
702 | |||
703 | /* this op will fetch the status on both the directories we're dealing | ||
704 | * with */ | ||
705 | spin_lock(&orig_dvnode->lock); | ||
706 | orig_dvnode->update_cnt++; | ||
707 | spin_unlock(&orig_dvnode->lock); | ||
708 | if (new_dvnode != orig_dvnode) { | ||
709 | spin_lock(&new_dvnode->lock); | ||
710 | new_dvnode->update_cnt++; | ||
711 | spin_unlock(&new_dvnode->lock); | ||
712 | } | ||
713 | |||
714 | do { | ||
715 | /* pick a server to query */ | ||
716 | server = afs_volume_pick_fileserver(orig_dvnode); | ||
717 | if (IS_ERR(server)) | ||
718 | goto no_server; | ||
719 | |||
720 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
721 | |||
722 | ret = afs_fs_rename(server, key, orig_dvnode, orig_name, | ||
723 | new_dvnode, new_name, &afs_sync_call); | ||
724 | |||
725 | } while (!afs_volume_release_fileserver(orig_dvnode, server, ret)); | ||
726 | |||
727 | /* adjust the flags */ | ||
728 | if (ret == 0) { | ||
729 | afs_vnode_finalise_status_update(orig_dvnode, server); | ||
730 | if (new_dvnode != orig_dvnode) | ||
731 | afs_vnode_finalise_status_update(new_dvnode, server); | ||
732 | afs_put_server(server); | ||
733 | } else { | ||
734 | afs_vnode_status_update_failed(orig_dvnode, ret); | ||
735 | if (new_dvnode != orig_dvnode) | ||
736 | afs_vnode_status_update_failed(new_dvnode, ret); | ||
737 | } | ||
738 | |||
739 | _leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt); | ||
740 | return ret; | ||
741 | |||
742 | no_server: | ||
743 | spin_lock(&orig_dvnode->lock); | ||
744 | orig_dvnode->update_cnt--; | ||
745 | ASSERTCMP(orig_dvnode->update_cnt, >=, 0); | ||
746 | spin_unlock(&orig_dvnode->lock); | ||
747 | if (new_dvnode != orig_dvnode) { | ||
748 | spin_lock(&new_dvnode->lock); | ||
749 | new_dvnode->update_cnt--; | ||
750 | ASSERTCMP(new_dvnode->update_cnt, >=, 0); | ||
751 | spin_unlock(&new_dvnode->lock); | ||
752 | } | ||
753 | _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt); | ||
754 | return PTR_ERR(server); | ||
389 | } | 755 | } |