diff options
Diffstat (limited to 'fs/afs/rotate.c')
-rw-r--r-- | fs/afs/rotate.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c index c3ae324781f8..172ba569cd60 100644 --- a/fs/afs/rotate.c +++ b/fs/afs/rotate.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Handle fileserver selection and rotation. * * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #include <linux/kernel.h> @@ -25,7 +21,7 @@ * them here also using the io_lock. */ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode, - struct key *key) + struct key *key, bool intr) { memset(fc, 0, sizeof(*fc)); fc->vnode = vnode; @@ -33,10 +29,15 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode fc->ac.error = SHRT_MAX; fc->error = -EDESTADDRREQ; - if (mutex_lock_interruptible(&vnode->io_lock) < 0) { - fc->error = -EINTR; - fc->flags |= AFS_FS_CURSOR_STOP; - return false; + if (intr) { + fc->flags |= AFS_FS_CURSOR_INTR; + if (mutex_lock_interruptible(&vnode->io_lock) < 0) { + fc->error = -EINTR; + fc->flags |= AFS_FS_CURSOR_STOP; + return false; + } + } else { + mutex_lock(&vnode->io_lock); } if (vnode->lock_state != AFS_VNODE_LOCK_NONE) @@ -61,7 +62,8 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc, fc->untried = (1UL << fc->server_list->nr_servers) - 1; fc->index = READ_ONCE(fc->server_list->preferred); - cbi = vnode->cb_interest; + cbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock)); if (cbi) { /* See if the vnode's preferred record is still available */ for (i = 0; i < fc->server_list->nr_servers; i++) { @@ -82,8 +84,8 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc, /* Note that the callback promise is effectively broken */ write_seqlock(&vnode->cb_lock); - ASSERTCMP(cbi, ==, vnode->cb_interest); - vnode->cb_interest = NULL; + ASSERTCMP(cbi, ==, rcu_access_pointer(vnode->cb_interest)); + rcu_assign_pointer(vnode->cb_interest, NULL); if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) vnode->cb_break++; write_sequnlock(&vnode->cb_lock); @@ -118,10 +120,14 @@ static void afs_busy(struct afs_volume *volume, u32 abort_code) */ static bool afs_sleep_and_retry(struct afs_fs_cursor *fc) { - msleep_interruptible(1000); - if (signal_pending(current)) { - fc->error = -ERESTARTSYS; - return false; + if (fc->flags & AFS_FS_CURSOR_INTR) { + msleep_interruptible(1000); + if (signal_pending(current)) { + fc->error = -ERESTARTSYS; + return false; + } + } else { + msleep(1000); } return true; @@ -408,7 +414,9 @@ selected_server: if (error < 0) goto failed_set_error; - fc->cbi = afs_get_cb_interest(vnode->cb_interest); + fc->cbi = afs_get_cb_interest( + rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock))); read_lock(&server->fs_lock); alist = rcu_dereference_protected(server->addresses, @@ -459,6 +467,8 @@ no_more_servers: s->probe.abort_code); } + error = e.error; + failed_set_error: fc->error = error; failed: @@ -476,12 +486,15 @@ failed: bool afs_select_current_fileserver(struct afs_fs_cursor *fc) { struct afs_vnode *vnode = fc->vnode; - struct afs_cb_interest *cbi = vnode->cb_interest; + struct afs_cb_interest *cbi; struct afs_addr_list *alist; int error = fc->ac.error; _enter(""); + cbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock)); + switch (error) { case SHRT_MAX: if (!cbi) { @@ -490,7 +503,7 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc) return false; } - fc->cbi = afs_get_cb_interest(vnode->cb_interest); + fc->cbi = afs_get_cb_interest(cbi); read_lock(&cbi->server->fs_lock); alist = rcu_dereference_protected(cbi->server->addresses, |