1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * (C) 2001 Clemson University and The University of Chicago 4 * (C) 2011 Omnibond Systems 5 * 6 * Changes by Acxiom Corporation to implement generic service_operation() 7 * function, Copyright Acxiom Corporation, 2005. 8 * 9 * See COPYING in top-level directory. 10 */ 11 12 /* 13 * In-kernel waitqueue operations. 14 */ 15 16 #include "protocol.h" 17 #include "orangefs-kernel.h" 18 #include "orangefs-bufmap.h" 19 20 static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op, 21 long timeout, 22 bool interruptible) 23 __acquires(op->lock); 24 static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op) 25 __releases(op->lock); 26 27 /* 28 * What we do in this function is to walk the list of operations that are 29 * present in the request queue and mark them as purged. 30 * NOTE: This is called from the device close after client-core has 31 * guaranteed that no new operations could appear on the list since the 32 * client-core is anyway going to exit. 33 */ 34 void purge_waiting_ops(void) 35 { 36 struct orangefs_kernel_op_s *op, *tmp; 37 38 spin_lock(&orangefs_request_list_lock); 39 list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) { 40 gossip_debug(GOSSIP_WAIT_DEBUG, 41 "pvfs2-client-core: purging op tag %llu %s\n", 42 llu(op->tag), 43 get_opname_string(op)); 44 set_op_state_purged(op); 45 gossip_debug(GOSSIP_DEV_DEBUG, 46 "%s: op:%s: op_state:%d: process:%s:\n", 47 __func__, 48 get_opname_string(op), 49 op->op_state, 50 current->comm); 51 } 52 spin_unlock(&orangefs_request_list_lock); 53 } 54 55 /* 56 * submits a ORANGEFS operation and waits for it to complete 57 * 58 * Note op->downcall.status will contain the status of the operation (in 59 * errno format), whether provided by pvfs2-client or a result of failure to 60 * service the operation. If the caller wishes to distinguish, then 61 * op->state can be checked to see if it was serviced or not. 62 * 63 * Returns contents of op->downcall.status for convenience 64 */ 65 int service_operation(struct orangefs_kernel_op_s *op, 66 const char *op_name, 67 int flags) 68 { 69 long timeout = MAX_SCHEDULE_TIMEOUT; 70 int ret = 0; 71 72 DEFINE_WAIT(wait_entry); 73 74 op->upcall.tgid = current->tgid; 75 op->upcall.pid = current->pid; 76 77 retry_servicing: 78 op->downcall.status = 0; 79 gossip_debug(GOSSIP_WAIT_DEBUG, 80 "%s: %s op:%p: process:%s: pid:%d:\n", 81 __func__, 82 op_name, 83 op, 84 current->comm, 85 current->pid); 86 87 /* 88 * If ORANGEFS_OP_NO_MUTEX was set in flags, we need to avoid 89 * acquiring the request_mutex because we're servicing a 90 * high priority remount operation and the request_mutex is 91 * already taken. 92 */ 93 if (!(flags & ORANGEFS_OP_NO_MUTEX)) { 94 if (flags & ORANGEFS_OP_INTERRUPTIBLE) 95 ret = mutex_lock_interruptible(&orangefs_request_mutex); 96 else 97 ret = mutex_lock_killable(&orangefs_request_mutex); 98 /* 99 * check to see if we were interrupted while waiting for 100 * mutex 101 */ 102 if (ret < 0) { 103 op->downcall.status = ret; 104 gossip_debug(GOSSIP_WAIT_DEBUG, 105 "%s: service_operation interrupted.\n", 106 __func__); 107 return ret; 108 } 109 } 110 111 /* queue up the operation */ 112 spin_lock(&orangefs_request_list_lock); 113 spin_lock(&op->lock); 114 set_op_state_waiting(op); 115 gossip_debug(GOSSIP_DEV_DEBUG, 116 "%s: op:%s: op_state:%d: process:%s:\n", 117 __func__, 118 get_opname_string(op), 119 op->op_state, 120 current->comm); 121 /* add high priority remount op to the front of the line. */ 122 if (flags & ORANGEFS_OP_PRIORITY) 123 list_add(&op->list, &orangefs_request_list); 124 else 125 list_add_tail(&op->list, &orangefs_request_list); 126 spin_unlock(&op->lock); 127 wake_up_interruptible(&orangefs_request_list_waitq); 128 if (!__is_daemon_in_service()) { 129 gossip_debug(GOSSIP_WAIT_DEBUG, 130 "%s:client core is NOT in service.\n", 131 __func__); 132 /* 133 * Don't wait for the userspace component to return if 134 * the filesystem is being umounted anyway. 135 */ 136 if (op->upcall.type == ORANGEFS_VFS_OP_FS_UMOUNT) 137 timeout = 0; 138 else 139 timeout = op_timeout_secs * HZ; 140 } 141 spin_unlock(&orangefs_request_list_lock); 142 143 if (!(flags & ORANGEFS_OP_NO_MUTEX)) 144 mutex_unlock(&orangefs_request_mutex); 145 146 ret = wait_for_matching_downcall(op, timeout, 147 flags & ORANGEFS_OP_INTERRUPTIBLE); 148 149 gossip_debug(GOSSIP_WAIT_DEBUG, 150 "%s: wait_for_matching_downcall returned %d for %p\n", 151 __func__, 152 ret, 153 op); 154 155 /* got matching downcall; make sure status is in errno format */ 156 if (!ret) { 157 spin_unlock(&op->lock); 158 op->downcall.status = 159 orangefs_normalize_to_errno(op->downcall.status); 160 ret = op->downcall.status; 161 goto out; 162 } 163 164 /* failed to get matching downcall */ 165 if (ret == -ETIMEDOUT) { 166 gossip_err("%s: %s -- wait timed out; aborting attempt.\n", 167 __func__, 168 op_name); 169 } 170 171 /* 172 * remove a waiting op from the request list or 173 * remove an in-progress op from the in-progress list. 174 */ 175 orangefs_clean_up_interrupted_operation(op); 176 177 op->downcall.status = ret; 178 /* retry if operation has not been serviced and if requested */ 179 if (ret == -EAGAIN) { 180 op->attempts++; 181 timeout = op_timeout_secs * HZ; 182 gossip_debug(GOSSIP_WAIT_DEBUG, 183 "orangefs: tag %llu (%s)" 184 " -- operation to be retried (%d attempt)\n", 185 llu(op->tag), 186 op_name, 187 op->attempts); 188 189 /* 190 * io ops (ops that use the shared memory buffer) have 191 * to be returned to their caller for a retry. Other ops 192 * can just be recycled here. 193 */ 194 if (!op->uses_shared_memory) 195 goto retry_servicing; 196 } 197 198 out: 199 gossip_debug(GOSSIP_WAIT_DEBUG, 200 "%s: %s returning: %d for %p.\n", 201 __func__, 202 op_name, 203 ret, 204 op); 205 return ret; 206 } 207 208 /* This can get called on an I/O op if it had a bad service_operation. */ 209 bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op) 210 { 211 u64 tag = op->tag; 212 if (!op_state_in_progress(op)) 213 return false; 214 215 op->slot_to_free = op->upcall.req.io.buf_index; 216 memset(&op->upcall, 0, sizeof(op->upcall)); 217 memset(&op->downcall, 0, sizeof(op->downcall)); 218 op->upcall.type = ORANGEFS_VFS_OP_CANCEL; 219 op->upcall.req.cancel.op_tag = tag; 220 op->downcall.type = ORANGEFS_VFS_OP_INVALID; 221 op->downcall.status = -1; 222 orangefs_new_tag(op); 223 224 spin_lock(&orangefs_request_list_lock); 225 /* orangefs_request_list_lock is enough of a barrier here */ 226 if (!__is_daemon_in_service()) { 227 spin_unlock(&orangefs_request_list_lock); 228 return false; 229 } 230 spin_lock(&op->lock); 231 set_op_state_waiting(op); 232 gossip_debug(GOSSIP_DEV_DEBUG, 233 "%s: op:%s: op_state:%d: process:%s:\n", 234 __func__, 235 get_opname_string(op), 236 op->op_state, 237 current->comm); 238 list_add(&op->list, &orangefs_request_list); 239 spin_unlock(&op->lock); 240 spin_unlock(&orangefs_request_list_lock); 241 242 gossip_debug(GOSSIP_WAIT_DEBUG, 243 "Attempting ORANGEFS operation cancellation of tag %llu\n", 244 llu(tag)); 245 return true; 246 } 247 248 /* 249 * Change an op to the "given up" state and remove it from its list. 250 */ 251 static void 252 orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op) 253 __releases(op->lock) 254 { 255 /* 256 * handle interrupted cases depending on what state we were in when 257 * the interruption is detected. 258 * 259 * Called with op->lock held. 260 */ 261 262 /* 263 * List manipulation code elsewhere will ignore ops that 264 * have been given up upon. 265 */ 266 op->op_state |= OP_VFS_STATE_GIVEN_UP; 267 268 if (list_empty(&op->list)) { 269 /* caught copying to/from daemon */ 270 BUG_ON(op_state_serviced(op)); 271 spin_unlock(&op->lock); 272 wait_for_completion(&op->waitq); 273 } else if (op_state_waiting(op)) { 274 /* 275 * upcall hasn't been read; remove op from upcall request 276 * list. 277 */ 278 spin_unlock(&op->lock); 279 spin_lock(&orangefs_request_list_lock); 280 list_del_init(&op->list); 281 spin_unlock(&orangefs_request_list_lock); 282 gossip_debug(GOSSIP_WAIT_DEBUG, 283 "Interrupted: Removed op %p from request_list\n", 284 op); 285 } else if (op_state_in_progress(op)) { 286 /* op must be removed from the in progress htable */ 287 spin_unlock(&op->lock); 288 spin_lock(&orangefs_htable_ops_in_progress_lock); 289 list_del_init(&op->list); 290 spin_unlock(&orangefs_htable_ops_in_progress_lock); 291 gossip_debug(GOSSIP_WAIT_DEBUG, 292 "Interrupted: Removed op %p" 293 " from htable_ops_in_progress\n", 294 op); 295 } else { 296 spin_unlock(&op->lock); 297 gossip_err("interrupted operation is in a weird state 0x%x\n", 298 op->op_state); 299 } 300 reinit_completion(&op->waitq); 301 } 302 303 /* 304 * Sleeps on waitqueue waiting for matching downcall. 305 * If client-core finishes servicing, then we are good to go. 306 * else if client-core exits, we get woken up here, and retry with a timeout 307 * 308 * When this call returns to the caller, the specified op will no 309 * longer be in either the in_progress hash table or on the request list. 310 * 311 * Returns 0 on success and -errno on failure 312 * Errors are: 313 * EAGAIN in case we want the caller to requeue and try again.. 314 * EINTR/EIO/ETIMEDOUT indicating we are done trying to service this 315 * operation since client-core seems to be exiting too often 316 * or if we were interrupted. 317 * 318 * Returns with op->lock taken. 319 */ 320 static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op, 321 long timeout, 322 bool interruptible) 323 __acquires(op->lock) 324 { 325 long n; 326 327 /* 328 * There's a "schedule_timeout" inside of these wait 329 * primitives, during which the op is out of the hands of the 330 * user process that needs something done and is being 331 * manipulated by the client-core process. 332 */ 333 if (interruptible) 334 n = wait_for_completion_interruptible_timeout(&op->waitq, 335 timeout); 336 else 337 n = wait_for_completion_killable_timeout(&op->waitq, timeout); 338 339 spin_lock(&op->lock); 340 341 if (op_state_serviced(op)) 342 return 0; 343 344 if (unlikely(n < 0)) { 345 gossip_debug(GOSSIP_WAIT_DEBUG, 346 "%s: operation interrupted, tag %llu, %p\n", 347 __func__, 348 llu(op->tag), 349 op); 350 return -EINTR; 351 } 352 if (op_state_purged(op)) { 353 gossip_debug(GOSSIP_WAIT_DEBUG, 354 "%s: operation purged, tag %llu, %p, %d\n", 355 __func__, 356 llu(op->tag), 357 op, 358 op->attempts); 359 return (op->attempts < ORANGEFS_PURGE_RETRY_COUNT) ? 360 -EAGAIN : 361 -EIO; 362 } 363 /* must have timed out, then... */ 364 gossip_debug(GOSSIP_WAIT_DEBUG, 365 "%s: operation timed out, tag %llu, %p, %d)\n", 366 __func__, 367 llu(op->tag), 368 op, 369 op->attempts); 370 return -ETIMEDOUT; 371 } 372