diff options
Diffstat (limited to 'fs/afs/inode.c')
-rw-r--r-- | fs/afs/inode.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 5c95da7d5f3d..ba35b4824408 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -139,9 +139,10 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, | |||
139 | vnode->cb_expires_at = ktime_get_real_seconds(); | 139 | vnode->cb_expires_at = ktime_get_real_seconds(); |
140 | } else { | 140 | } else { |
141 | vnode->cb_expires_at = scb->callback.expires_at; | 141 | vnode->cb_expires_at = scb->callback.expires_at; |
142 | old_cbi = vnode->cb_interest; | 142 | old_cbi = rcu_dereference_protected(vnode->cb_interest, |
143 | lockdep_is_held(&vnode->cb_lock.lock)); | ||
143 | if (cbi != old_cbi) | 144 | if (cbi != old_cbi) |
144 | vnode->cb_interest = afs_get_cb_interest(cbi); | 145 | rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(cbi)); |
145 | else | 146 | else |
146 | old_cbi = NULL; | 147 | old_cbi = NULL; |
147 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | 148 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
@@ -245,9 +246,10 @@ static void afs_apply_callback(struct afs_fs_cursor *fc, | |||
245 | 246 | ||
246 | if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) { | 247 | if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) { |
247 | vnode->cb_expires_at = cb->expires_at; | 248 | vnode->cb_expires_at = cb->expires_at; |
248 | old = vnode->cb_interest; | 249 | old = rcu_dereference_protected(vnode->cb_interest, |
250 | lockdep_is_held(&vnode->cb_lock.lock)); | ||
249 | if (old != fc->cbi) { | 251 | if (old != fc->cbi) { |
250 | vnode->cb_interest = afs_get_cb_interest(fc->cbi); | 252 | rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(fc->cbi)); |
251 | afs_put_cb_interest(afs_v2net(vnode), old); | 253 | afs_put_cb_interest(afs_v2net(vnode), old); |
252 | } | 254 | } |
253 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | 255 | set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
@@ -565,36 +567,46 @@ void afs_zap_data(struct afs_vnode *vnode) | |||
565 | */ | 567 | */ |
566 | bool afs_check_validity(struct afs_vnode *vnode) | 568 | bool afs_check_validity(struct afs_vnode *vnode) |
567 | { | 569 | { |
570 | struct afs_cb_interest *cbi; | ||
571 | struct afs_server *server; | ||
572 | struct afs_volume *volume = vnode->volume; | ||
568 | time64_t now = ktime_get_real_seconds(); | 573 | time64_t now = ktime_get_real_seconds(); |
569 | bool valid; | 574 | bool valid; |
575 | unsigned int cb_break, cb_s_break, cb_v_break; | ||
576 | int seq = 0; | ||
570 | 577 | ||
571 | /* Quickly check the callback state. Ideally, we'd use read_seqbegin | 578 | do { |
572 | * here, but we have no way to pass the net namespace to the RCU | 579 | read_seqbegin_or_lock(&vnode->cb_lock, &seq); |
573 | * cleanup for the server record. | 580 | cb_v_break = READ_ONCE(volume->cb_v_break); |
574 | */ | 581 | cb_break = vnode->cb_break; |
575 | read_seqlock_excl(&vnode->cb_lock); | 582 | |
576 | 583 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | |
577 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | 584 | cbi = rcu_dereference(vnode->cb_interest); |
578 | if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break || | 585 | server = rcu_dereference(cbi->server); |
579 | vnode->cb_v_break != vnode->volume->cb_v_break) { | 586 | cb_s_break = READ_ONCE(server->cb_s_break); |
580 | vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; | 587 | |
581 | vnode->cb_v_break = vnode->volume->cb_v_break; | 588 | if (vnode->cb_s_break != cb_s_break || |
582 | valid = false; | 589 | vnode->cb_v_break != cb_v_break) { |
583 | } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | 590 | vnode->cb_s_break = cb_s_break; |
584 | valid = false; | 591 | vnode->cb_v_break = cb_v_break; |
585 | } else if (vnode->cb_expires_at - 10 <= now) { | 592 | valid = false; |
586 | valid = false; | 593 | } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { |
587 | } else { | 594 | valid = false; |
595 | } else if (vnode->cb_expires_at - 10 <= now) { | ||
596 | valid = false; | ||
597 | } else { | ||
598 | valid = true; | ||
599 | } | ||
600 | } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | ||
588 | valid = true; | 601 | valid = true; |
602 | } else { | ||
603 | vnode->cb_v_break = cb_v_break; | ||
604 | valid = false; | ||
589 | } | 605 | } |
590 | } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | ||
591 | valid = true; | ||
592 | } else { | ||
593 | vnode->cb_v_break = vnode->volume->cb_v_break; | ||
594 | valid = false; | ||
595 | } | ||
596 | 606 | ||
597 | read_sequnlock_excl(&vnode->cb_lock); | 607 | } while (need_seqretry(&vnode->cb_lock, seq)); |
608 | |||
609 | done_seqretry(&vnode->cb_lock, seq); | ||
598 | return valid; | 610 | return valid; |
599 | } | 611 | } |
600 | 612 | ||
@@ -616,7 +628,9 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
616 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, | 628 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, |
617 | key_serial(key)); | 629 | key_serial(key)); |
618 | 630 | ||
631 | rcu_read_lock(); | ||
619 | valid = afs_check_validity(vnode); | 632 | valid = afs_check_validity(vnode); |
633 | rcu_read_unlock(); | ||
620 | 634 | ||
621 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | 635 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
622 | clear_nlink(&vnode->vfs_inode); | 636 | clear_nlink(&vnode->vfs_inode); |
@@ -703,6 +717,7 @@ int afs_drop_inode(struct inode *inode) | |||
703 | */ | 717 | */ |
704 | void afs_evict_inode(struct inode *inode) | 718 | void afs_evict_inode(struct inode *inode) |
705 | { | 719 | { |
720 | struct afs_cb_interest *cbi; | ||
706 | struct afs_vnode *vnode; | 721 | struct afs_vnode *vnode; |
707 | 722 | ||
708 | vnode = AFS_FS_I(inode); | 723 | vnode = AFS_FS_I(inode); |
@@ -719,10 +734,14 @@ void afs_evict_inode(struct inode *inode) | |||
719 | truncate_inode_pages_final(&inode->i_data); | 734 | truncate_inode_pages_final(&inode->i_data); |
720 | clear_inode(inode); | 735 | clear_inode(inode); |
721 | 736 | ||
722 | if (vnode->cb_interest) { | 737 | write_seqlock(&vnode->cb_lock); |
723 | afs_put_cb_interest(afs_i2net(inode), vnode->cb_interest); | 738 | cbi = rcu_dereference_protected(vnode->cb_interest, |
724 | vnode->cb_interest = NULL; | 739 | lockdep_is_held(&vnode->cb_lock.lock)); |
740 | if (cbi) { | ||
741 | afs_put_cb_interest(afs_i2net(inode), cbi); | ||
742 | rcu_assign_pointer(vnode->cb_interest, NULL); | ||
725 | } | 743 | } |
744 | write_sequnlock(&vnode->cb_lock); | ||
726 | 745 | ||
727 | while (!list_empty(&vnode->wb_keys)) { | 746 | while (!list_empty(&vnode->wb_keys)) { |
728 | struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next, | 747 | struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next, |