162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago
462306a36Sopenharmony_ci * (C) 2011 Omnibond Systems
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Changes by Acxiom Corporation to implement generic service_operation()
762306a36Sopenharmony_ci * function, Copyright Acxiom Corporation, 2005.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * See COPYING in top-level directory.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci *  In-kernel waitqueue operations.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "protocol.h"
1762306a36Sopenharmony_ci#include "orangefs-kernel.h"
1862306a36Sopenharmony_ci#include "orangefs-bufmap.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
2162306a36Sopenharmony_ci		long timeout,
2262306a36Sopenharmony_ci		int flags)
2362306a36Sopenharmony_ci			__acquires(op->lock);
2462306a36Sopenharmony_cistatic void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op)
2562306a36Sopenharmony_ci	__releases(op->lock);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * What we do in this function is to walk the list of operations that are
2962306a36Sopenharmony_ci * present in the request queue and mark them as purged.
3062306a36Sopenharmony_ci * NOTE: This is called from the device close after client-core has
3162306a36Sopenharmony_ci * guaranteed that no new operations could appear on the list since the
3262306a36Sopenharmony_ci * client-core is anyway going to exit.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_civoid purge_waiting_ops(void)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct orangefs_kernel_op_s *op, *tmp;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	spin_lock(&orangefs_request_list_lock);
3962306a36Sopenharmony_ci	list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) {
4062306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
4162306a36Sopenharmony_ci			     "pvfs2-client-core: purging op tag %llu %s\n",
4262306a36Sopenharmony_ci			     llu(op->tag),
4362306a36Sopenharmony_ci			     get_opname_string(op));
4462306a36Sopenharmony_ci		set_op_state_purged(op);
4562306a36Sopenharmony_ci		gossip_debug(GOSSIP_DEV_DEBUG,
4662306a36Sopenharmony_ci			     "%s: op:%s: op_state:%d: process:%s:\n",
4762306a36Sopenharmony_ci			     __func__,
4862306a36Sopenharmony_ci			     get_opname_string(op),
4962306a36Sopenharmony_ci			     op->op_state,
5062306a36Sopenharmony_ci			     current->comm);
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	spin_unlock(&orangefs_request_list_lock);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * submits a ORANGEFS operation and waits for it to complete
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * Note op->downcall.status will contain the status of the operation (in
5962306a36Sopenharmony_ci * errno format), whether provided by pvfs2-client or a result of failure to
6062306a36Sopenharmony_ci * service the operation.  If the caller wishes to distinguish, then
6162306a36Sopenharmony_ci * op->state can be checked to see if it was serviced or not.
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * Returns contents of op->downcall.status for convenience
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ciint service_operation(struct orangefs_kernel_op_s *op,
6662306a36Sopenharmony_ci		      const char *op_name,
6762306a36Sopenharmony_ci		      int flags)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	long timeout = MAX_SCHEDULE_TIMEOUT;
7062306a36Sopenharmony_ci	int ret = 0;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	DEFINE_WAIT(wait_entry);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	op->upcall.tgid = current->tgid;
7562306a36Sopenharmony_ci	op->upcall.pid = current->pid;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciretry_servicing:
7862306a36Sopenharmony_ci	op->downcall.status = 0;
7962306a36Sopenharmony_ci	gossip_debug(GOSSIP_WAIT_DEBUG,
8062306a36Sopenharmony_ci		     "%s: %s op:%p: process:%s: pid:%d:\n",
8162306a36Sopenharmony_ci		     __func__,
8262306a36Sopenharmony_ci		     op_name,
8362306a36Sopenharmony_ci		     op,
8462306a36Sopenharmony_ci		     current->comm,
8562306a36Sopenharmony_ci		     current->pid);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/*
8862306a36Sopenharmony_ci	 * If ORANGEFS_OP_NO_MUTEX was set in flags, we need to avoid
8962306a36Sopenharmony_ci	 * acquiring the request_mutex because we're servicing a
9062306a36Sopenharmony_ci	 * high priority remount operation and the request_mutex is
9162306a36Sopenharmony_ci	 * already taken.
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	if (!(flags & ORANGEFS_OP_NO_MUTEX)) {
9462306a36Sopenharmony_ci		if (flags & ORANGEFS_OP_INTERRUPTIBLE)
9562306a36Sopenharmony_ci			ret = mutex_lock_interruptible(&orangefs_request_mutex);
9662306a36Sopenharmony_ci		else
9762306a36Sopenharmony_ci			ret = mutex_lock_killable(&orangefs_request_mutex);
9862306a36Sopenharmony_ci		/*
9962306a36Sopenharmony_ci		 * check to see if we were interrupted while waiting for
10062306a36Sopenharmony_ci		 * mutex
10162306a36Sopenharmony_ci		 */
10262306a36Sopenharmony_ci		if (ret < 0) {
10362306a36Sopenharmony_ci			op->downcall.status = ret;
10462306a36Sopenharmony_ci			gossip_debug(GOSSIP_WAIT_DEBUG,
10562306a36Sopenharmony_ci				     "%s: service_operation interrupted.\n",
10662306a36Sopenharmony_ci				     __func__);
10762306a36Sopenharmony_ci			return ret;
10862306a36Sopenharmony_ci		}
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* queue up the operation */
11262306a36Sopenharmony_ci	spin_lock(&orangefs_request_list_lock);
11362306a36Sopenharmony_ci	spin_lock(&op->lock);
11462306a36Sopenharmony_ci	set_op_state_waiting(op);
11562306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEV_DEBUG,
11662306a36Sopenharmony_ci		     "%s: op:%s: op_state:%d: process:%s:\n",
11762306a36Sopenharmony_ci		     __func__,
11862306a36Sopenharmony_ci		     get_opname_string(op),
11962306a36Sopenharmony_ci		     op->op_state,
12062306a36Sopenharmony_ci		     current->comm);
12162306a36Sopenharmony_ci	/* add high priority remount op to the front of the line. */
12262306a36Sopenharmony_ci	if (flags & ORANGEFS_OP_PRIORITY)
12362306a36Sopenharmony_ci		list_add(&op->list, &orangefs_request_list);
12462306a36Sopenharmony_ci	else
12562306a36Sopenharmony_ci		list_add_tail(&op->list, &orangefs_request_list);
12662306a36Sopenharmony_ci	spin_unlock(&op->lock);
12762306a36Sopenharmony_ci	wake_up_interruptible(&orangefs_request_list_waitq);
12862306a36Sopenharmony_ci	if (!__is_daemon_in_service()) {
12962306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
13062306a36Sopenharmony_ci			     "%s:client core is NOT in service.\n",
13162306a36Sopenharmony_ci			     __func__);
13262306a36Sopenharmony_ci		/*
13362306a36Sopenharmony_ci		 * Don't wait for the userspace component to return if
13462306a36Sopenharmony_ci		 * the filesystem is being umounted anyway.
13562306a36Sopenharmony_ci		 */
13662306a36Sopenharmony_ci		if (op->upcall.type == ORANGEFS_VFS_OP_FS_UMOUNT)
13762306a36Sopenharmony_ci			timeout = 0;
13862306a36Sopenharmony_ci		else
13962306a36Sopenharmony_ci			timeout = op_timeout_secs * HZ;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	spin_unlock(&orangefs_request_list_lock);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (!(flags & ORANGEFS_OP_NO_MUTEX))
14462306a36Sopenharmony_ci		mutex_unlock(&orangefs_request_mutex);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	ret = wait_for_matching_downcall(op, timeout, flags);
14762306a36Sopenharmony_ci	gossip_debug(GOSSIP_WAIT_DEBUG,
14862306a36Sopenharmony_ci		     "%s: wait_for_matching_downcall returned %d for %p\n",
14962306a36Sopenharmony_ci		     __func__,
15062306a36Sopenharmony_ci		     ret,
15162306a36Sopenharmony_ci		     op);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* got matching downcall; make sure status is in errno format */
15462306a36Sopenharmony_ci	if (!ret) {
15562306a36Sopenharmony_ci		spin_unlock(&op->lock);
15662306a36Sopenharmony_ci		op->downcall.status =
15762306a36Sopenharmony_ci		    orangefs_normalize_to_errno(op->downcall.status);
15862306a36Sopenharmony_ci		ret = op->downcall.status;
15962306a36Sopenharmony_ci		goto out;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* failed to get matching downcall */
16362306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
16462306a36Sopenharmony_ci		gossip_err("%s: %s -- wait timed out; aborting attempt.\n",
16562306a36Sopenharmony_ci			   __func__,
16662306a36Sopenharmony_ci			   op_name);
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/*
17062306a36Sopenharmony_ci	 * remove a waiting op from the request list or
17162306a36Sopenharmony_ci	 * remove an in-progress op from the in-progress list.
17262306a36Sopenharmony_ci	 */
17362306a36Sopenharmony_ci	orangefs_clean_up_interrupted_operation(op);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	op->downcall.status = ret;
17662306a36Sopenharmony_ci	/* retry if operation has not been serviced and if requested */
17762306a36Sopenharmony_ci	if (ret == -EAGAIN) {
17862306a36Sopenharmony_ci		op->attempts++;
17962306a36Sopenharmony_ci		timeout = op_timeout_secs * HZ;
18062306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
18162306a36Sopenharmony_ci			     "orangefs: tag %llu (%s)"
18262306a36Sopenharmony_ci			     " -- operation to be retried (%d attempt)\n",
18362306a36Sopenharmony_ci			     llu(op->tag),
18462306a36Sopenharmony_ci			     op_name,
18562306a36Sopenharmony_ci			     op->attempts);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		/*
18862306a36Sopenharmony_ci		 * io ops (ops that use the shared memory buffer) have
18962306a36Sopenharmony_ci		 * to be returned to their caller for a retry. Other ops
19062306a36Sopenharmony_ci		 * can just be recycled here.
19162306a36Sopenharmony_ci		 */
19262306a36Sopenharmony_ci		if (!op->uses_shared_memory)
19362306a36Sopenharmony_ci			goto retry_servicing;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ciout:
19762306a36Sopenharmony_ci	gossip_debug(GOSSIP_WAIT_DEBUG,
19862306a36Sopenharmony_ci		     "%s: %s returning: %d for %p.\n",
19962306a36Sopenharmony_ci		     __func__,
20062306a36Sopenharmony_ci		     op_name,
20162306a36Sopenharmony_ci		     ret,
20262306a36Sopenharmony_ci		     op);
20362306a36Sopenharmony_ci	return ret;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/* This can get called on an I/O op if it had a bad service_operation. */
20762306a36Sopenharmony_cibool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	u64 tag = op->tag;
21062306a36Sopenharmony_ci	if (!op_state_in_progress(op))
21162306a36Sopenharmony_ci		return false;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	op->slot_to_free = op->upcall.req.io.buf_index;
21462306a36Sopenharmony_ci	memset(&op->upcall, 0, sizeof(op->upcall));
21562306a36Sopenharmony_ci	memset(&op->downcall, 0, sizeof(op->downcall));
21662306a36Sopenharmony_ci	op->upcall.type = ORANGEFS_VFS_OP_CANCEL;
21762306a36Sopenharmony_ci	op->upcall.req.cancel.op_tag = tag;
21862306a36Sopenharmony_ci	op->downcall.type = ORANGEFS_VFS_OP_INVALID;
21962306a36Sopenharmony_ci	op->downcall.status = -1;
22062306a36Sopenharmony_ci	orangefs_new_tag(op);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	spin_lock(&orangefs_request_list_lock);
22362306a36Sopenharmony_ci	/* orangefs_request_list_lock is enough of a barrier here */
22462306a36Sopenharmony_ci	if (!__is_daemon_in_service()) {
22562306a36Sopenharmony_ci		spin_unlock(&orangefs_request_list_lock);
22662306a36Sopenharmony_ci		return false;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci	spin_lock(&op->lock);
22962306a36Sopenharmony_ci	set_op_state_waiting(op);
23062306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEV_DEBUG,
23162306a36Sopenharmony_ci		     "%s: op:%s: op_state:%d: process:%s:\n",
23262306a36Sopenharmony_ci		     __func__,
23362306a36Sopenharmony_ci		     get_opname_string(op),
23462306a36Sopenharmony_ci		     op->op_state,
23562306a36Sopenharmony_ci		     current->comm);
23662306a36Sopenharmony_ci	list_add(&op->list, &orangefs_request_list);
23762306a36Sopenharmony_ci	spin_unlock(&op->lock);
23862306a36Sopenharmony_ci	spin_unlock(&orangefs_request_list_lock);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	gossip_debug(GOSSIP_WAIT_DEBUG,
24162306a36Sopenharmony_ci		     "Attempting ORANGEFS operation cancellation of tag %llu\n",
24262306a36Sopenharmony_ci		     llu(tag));
24362306a36Sopenharmony_ci	return true;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/*
24762306a36Sopenharmony_ci * Change an op to the "given up" state and remove it from its list.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_cistatic void
25062306a36Sopenharmony_ci	orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op)
25162306a36Sopenharmony_ci		__releases(op->lock)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	/*
25462306a36Sopenharmony_ci	 * handle interrupted cases depending on what state we were in when
25562306a36Sopenharmony_ci	 * the interruption is detected.
25662306a36Sopenharmony_ci	 *
25762306a36Sopenharmony_ci	 * Called with op->lock held.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * List manipulation code elsewhere will ignore ops that
26262306a36Sopenharmony_ci	 * have been given up upon.
26362306a36Sopenharmony_ci	 */
26462306a36Sopenharmony_ci	op->op_state |= OP_VFS_STATE_GIVEN_UP;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (list_empty(&op->list)) {
26762306a36Sopenharmony_ci		/* caught copying to/from daemon */
26862306a36Sopenharmony_ci		BUG_ON(op_state_serviced(op));
26962306a36Sopenharmony_ci		spin_unlock(&op->lock);
27062306a36Sopenharmony_ci		wait_for_completion(&op->waitq);
27162306a36Sopenharmony_ci	} else if (op_state_waiting(op)) {
27262306a36Sopenharmony_ci		/*
27362306a36Sopenharmony_ci		 * upcall hasn't been read; remove op from upcall request
27462306a36Sopenharmony_ci		 * list.
27562306a36Sopenharmony_ci		 */
27662306a36Sopenharmony_ci		spin_unlock(&op->lock);
27762306a36Sopenharmony_ci		spin_lock(&orangefs_request_list_lock);
27862306a36Sopenharmony_ci		list_del_init(&op->list);
27962306a36Sopenharmony_ci		spin_unlock(&orangefs_request_list_lock);
28062306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
28162306a36Sopenharmony_ci			     "Interrupted: Removed op %p from request_list\n",
28262306a36Sopenharmony_ci			     op);
28362306a36Sopenharmony_ci	} else if (op_state_in_progress(op)) {
28462306a36Sopenharmony_ci		/* op must be removed from the in progress htable */
28562306a36Sopenharmony_ci		spin_unlock(&op->lock);
28662306a36Sopenharmony_ci		spin_lock(&orangefs_htable_ops_in_progress_lock);
28762306a36Sopenharmony_ci		list_del_init(&op->list);
28862306a36Sopenharmony_ci		spin_unlock(&orangefs_htable_ops_in_progress_lock);
28962306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
29062306a36Sopenharmony_ci			     "Interrupted: Removed op %p"
29162306a36Sopenharmony_ci			     " from htable_ops_in_progress\n",
29262306a36Sopenharmony_ci			     op);
29362306a36Sopenharmony_ci	} else {
29462306a36Sopenharmony_ci		spin_unlock(&op->lock);
29562306a36Sopenharmony_ci		gossip_err("interrupted operation is in a weird state 0x%x\n",
29662306a36Sopenharmony_ci			   op->op_state);
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	reinit_completion(&op->waitq);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/*
30262306a36Sopenharmony_ci * Sleeps on waitqueue waiting for matching downcall.
30362306a36Sopenharmony_ci * If client-core finishes servicing, then we are good to go.
30462306a36Sopenharmony_ci * else if client-core exits, we get woken up here, and retry with a timeout
30562306a36Sopenharmony_ci *
30662306a36Sopenharmony_ci * When this call returns to the caller, the specified op will no
30762306a36Sopenharmony_ci * longer be in either the in_progress hash table or on the request list.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Returns 0 on success and -errno on failure
31062306a36Sopenharmony_ci * Errors are:
31162306a36Sopenharmony_ci * EAGAIN in case we want the caller to requeue and try again..
31262306a36Sopenharmony_ci * EINTR/EIO/ETIMEDOUT indicating we are done trying to service this
31362306a36Sopenharmony_ci * operation since client-core seems to be exiting too often
31462306a36Sopenharmony_ci * or if we were interrupted.
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Returns with op->lock taken.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
31962306a36Sopenharmony_ci		long timeout,
32062306a36Sopenharmony_ci		int flags)
32162306a36Sopenharmony_ci			__acquires(op->lock)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	long n;
32462306a36Sopenharmony_ci	int writeback = flags & ORANGEFS_OP_WRITEBACK,
32562306a36Sopenharmony_ci	    interruptible = flags & ORANGEFS_OP_INTERRUPTIBLE;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * There's a "schedule_timeout" inside of these wait
32962306a36Sopenharmony_ci	 * primitives, during which the op is out of the hands of the
33062306a36Sopenharmony_ci	 * user process that needs something done and is being
33162306a36Sopenharmony_ci	 * manipulated by the client-core process.
33262306a36Sopenharmony_ci	 */
33362306a36Sopenharmony_ci	if (writeback)
33462306a36Sopenharmony_ci		n = wait_for_completion_io_timeout(&op->waitq, timeout);
33562306a36Sopenharmony_ci	else if (!writeback && interruptible)
33662306a36Sopenharmony_ci		n = wait_for_completion_interruptible_timeout(&op->waitq,
33762306a36Sopenharmony_ci								      timeout);
33862306a36Sopenharmony_ci	else /* !writeback && !interruptible but compiler complains */
33962306a36Sopenharmony_ci		n = wait_for_completion_killable_timeout(&op->waitq, timeout);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	spin_lock(&op->lock);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (op_state_serviced(op))
34462306a36Sopenharmony_ci		return 0;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (unlikely(n < 0)) {
34762306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
34862306a36Sopenharmony_ci			     "%s: operation interrupted, tag %llu, %p\n",
34962306a36Sopenharmony_ci			     __func__,
35062306a36Sopenharmony_ci			     llu(op->tag),
35162306a36Sopenharmony_ci			     op);
35262306a36Sopenharmony_ci		return -EINTR;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci	if (op_state_purged(op)) {
35562306a36Sopenharmony_ci		gossip_debug(GOSSIP_WAIT_DEBUG,
35662306a36Sopenharmony_ci			     "%s: operation purged, tag %llu, %p, %d\n",
35762306a36Sopenharmony_ci			     __func__,
35862306a36Sopenharmony_ci			     llu(op->tag),
35962306a36Sopenharmony_ci			     op,
36062306a36Sopenharmony_ci			     op->attempts);
36162306a36Sopenharmony_ci		return (op->attempts < ORANGEFS_PURGE_RETRY_COUNT) ?
36262306a36Sopenharmony_ci			 -EAGAIN :
36362306a36Sopenharmony_ci			 -EIO;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	/* must have timed out, then... */
36662306a36Sopenharmony_ci	gossip_debug(GOSSIP_WAIT_DEBUG,
36762306a36Sopenharmony_ci		     "%s: operation timed out, tag %llu, %p, %d)\n",
36862306a36Sopenharmony_ci		     __func__,
36962306a36Sopenharmony_ci		     llu(op->tag),
37062306a36Sopenharmony_ci		     op,
37162306a36Sopenharmony_ci		     op->attempts);
37262306a36Sopenharmony_ci	return -ETIMEDOUT;
37362306a36Sopenharmony_ci}
374