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