fs_operation.c (5941B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* Fileserver-directed operation handling. 3 * 4 * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 */ 7 8#include <linux/kernel.h> 9#include <linux/slab.h> 10#include <linux/fs.h> 11#include "internal.h" 12 13static atomic_t afs_operation_debug_counter; 14 15/* 16 * Create an operation against a volume. 17 */ 18struct afs_operation *afs_alloc_operation(struct key *key, struct afs_volume *volume) 19{ 20 struct afs_operation *op; 21 22 _enter(""); 23 24 op = kzalloc(sizeof(*op), GFP_KERNEL); 25 if (!op) 26 return ERR_PTR(-ENOMEM); 27 28 if (!key) { 29 key = afs_request_key(volume->cell); 30 if (IS_ERR(key)) { 31 kfree(op); 32 return ERR_CAST(key); 33 } 34 } else { 35 key_get(key); 36 } 37 38 op->key = key; 39 op->volume = afs_get_volume(volume, afs_volume_trace_get_new_op); 40 op->net = volume->cell->net; 41 op->cb_v_break = volume->cb_v_break; 42 op->debug_id = atomic_inc_return(&afs_operation_debug_counter); 43 op->error = -EDESTADDRREQ; 44 op->ac.error = SHRT_MAX; 45 46 _leave(" = [op=%08x]", op->debug_id); 47 return op; 48} 49 50/* 51 * Lock the vnode(s) being operated upon. 52 */ 53static bool afs_get_io_locks(struct afs_operation *op) 54{ 55 struct afs_vnode *vnode = op->file[0].vnode; 56 struct afs_vnode *vnode2 = op->file[1].vnode; 57 58 _enter(""); 59 60 if (op->flags & AFS_OPERATION_UNINTR) { 61 mutex_lock(&vnode->io_lock); 62 op->flags |= AFS_OPERATION_LOCK_0; 63 _leave(" = t [1]"); 64 return true; 65 } 66 67 if (!vnode2 || !op->file[1].need_io_lock || vnode == vnode2) 68 vnode2 = NULL; 69 70 if (vnode2 > vnode) 71 swap(vnode, vnode2); 72 73 if (mutex_lock_interruptible(&vnode->io_lock) < 0) { 74 op->error = -ERESTARTSYS; 75 op->flags |= AFS_OPERATION_STOP; 76 _leave(" = f [I 0]"); 77 return false; 78 } 79 op->flags |= AFS_OPERATION_LOCK_0; 80 81 if (vnode2) { 82 if (mutex_lock_interruptible_nested(&vnode2->io_lock, 1) < 0) { 83 op->error = -ERESTARTSYS; 84 op->flags |= AFS_OPERATION_STOP; 85 mutex_unlock(&vnode->io_lock); 86 op->flags &= ~AFS_OPERATION_LOCK_0; 87 _leave(" = f [I 1]"); 88 return false; 89 } 90 op->flags |= AFS_OPERATION_LOCK_1; 91 } 92 93 _leave(" = t [2]"); 94 return true; 95} 96 97static void afs_drop_io_locks(struct afs_operation *op) 98{ 99 struct afs_vnode *vnode = op->file[0].vnode; 100 struct afs_vnode *vnode2 = op->file[1].vnode; 101 102 _enter(""); 103 104 if (op->flags & AFS_OPERATION_LOCK_1) 105 mutex_unlock(&vnode2->io_lock); 106 if (op->flags & AFS_OPERATION_LOCK_0) 107 mutex_unlock(&vnode->io_lock); 108} 109 110static void afs_prepare_vnode(struct afs_operation *op, struct afs_vnode_param *vp, 111 unsigned int index) 112{ 113 struct afs_vnode *vnode = vp->vnode; 114 115 if (vnode) { 116 vp->fid = vnode->fid; 117 vp->dv_before = vnode->status.data_version; 118 vp->cb_break_before = afs_calc_vnode_cb_break(vnode); 119 if (vnode->lock_state != AFS_VNODE_LOCK_NONE) 120 op->flags |= AFS_OPERATION_CUR_ONLY; 121 if (vp->modification) 122 set_bit(AFS_VNODE_MODIFYING, &vnode->flags); 123 } 124 125 if (vp->fid.vnode) 126 _debug("PREP[%u] {%llx:%llu.%u}", 127 index, vp->fid.vid, vp->fid.vnode, vp->fid.unique); 128} 129 130/* 131 * Begin an operation on the fileserver. 132 * 133 * Fileserver operations are serialised on the server by vnode, so we serialise 134 * them here also using the io_lock. 135 */ 136bool afs_begin_vnode_operation(struct afs_operation *op) 137{ 138 struct afs_vnode *vnode = op->file[0].vnode; 139 140 ASSERT(vnode); 141 142 _enter(""); 143 144 if (op->file[0].need_io_lock) 145 if (!afs_get_io_locks(op)) 146 return false; 147 148 afs_prepare_vnode(op, &op->file[0], 0); 149 afs_prepare_vnode(op, &op->file[1], 1); 150 op->cb_v_break = op->volume->cb_v_break; 151 _leave(" = true"); 152 return true; 153} 154 155/* 156 * Tidy up a filesystem cursor and unlock the vnode. 157 */ 158static void afs_end_vnode_operation(struct afs_operation *op) 159{ 160 _enter(""); 161 162 if (op->error == -EDESTADDRREQ || 163 op->error == -EADDRNOTAVAIL || 164 op->error == -ENETUNREACH || 165 op->error == -EHOSTUNREACH) 166 afs_dump_edestaddrreq(op); 167 168 afs_drop_io_locks(op); 169 170 if (op->error == -ECONNABORTED) 171 op->error = afs_abort_to_error(op->ac.abort_code); 172} 173 174/* 175 * Wait for an in-progress operation to complete. 176 */ 177void afs_wait_for_operation(struct afs_operation *op) 178{ 179 _enter(""); 180 181 while (afs_select_fileserver(op)) { 182 op->cb_s_break = op->server->cb_s_break; 183 if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) && 184 op->ops->issue_yfs_rpc) 185 op->ops->issue_yfs_rpc(op); 186 else if (op->ops->issue_afs_rpc) 187 op->ops->issue_afs_rpc(op); 188 else 189 op->ac.error = -ENOTSUPP; 190 191 if (op->call) 192 op->error = afs_wait_for_call_to_complete(op->call, &op->ac); 193 } 194 195 switch (op->error) { 196 case 0: 197 _debug("success"); 198 op->ops->success(op); 199 break; 200 case -ECONNABORTED: 201 if (op->ops->aborted) 202 op->ops->aborted(op); 203 fallthrough; 204 default: 205 if (op->ops->failed) 206 op->ops->failed(op); 207 break; 208 } 209 210 afs_end_vnode_operation(op); 211 212 if (op->error == 0 && op->ops->edit_dir) { 213 _debug("edit_dir"); 214 op->ops->edit_dir(op); 215 } 216 _leave(""); 217} 218 219/* 220 * Dispose of an operation. 221 */ 222int afs_put_operation(struct afs_operation *op) 223{ 224 int i, ret = op->error; 225 226 _enter("op=%08x,%d", op->debug_id, ret); 227 228 if (op->ops && op->ops->put) 229 op->ops->put(op); 230 if (op->file[0].modification) 231 clear_bit(AFS_VNODE_MODIFYING, &op->file[0].vnode->flags); 232 if (op->file[1].modification && op->file[1].vnode != op->file[0].vnode) 233 clear_bit(AFS_VNODE_MODIFYING, &op->file[1].vnode->flags); 234 if (op->file[0].put_vnode) 235 iput(&op->file[0].vnode->netfs.inode); 236 if (op->file[1].put_vnode) 237 iput(&op->file[1].vnode->netfs.inode); 238 239 if (op->more_files) { 240 for (i = 0; i < op->nr_files - 2; i++) 241 if (op->more_files[i].put_vnode) 242 iput(&op->more_files[i].vnode->netfs.inode); 243 kfree(op->more_files); 244 } 245 246 afs_end_cursor(&op->ac); 247 afs_put_serverlist(op->net, op->server_list); 248 afs_put_volume(op->net, op->volume, afs_volume_trace_put_put_op); 249 key_put(op->key); 250 kfree(op); 251 return ret; 252} 253 254int afs_do_sync_operation(struct afs_operation *op) 255{ 256 afs_begin_vnode_operation(op); 257 afs_wait_for_operation(op); 258 return afs_put_operation(op); 259}