summaryrefslogtreecommitdiffstats
path: root/fs/afs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/inode.c')
-rw-r--r--fs/afs/inode.c81
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 */
566bool afs_check_validity(struct afs_vnode *vnode) 568bool 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 */
704void afs_evict_inode(struct inode *inode) 718void 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,