1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21182fca3SMike Marshall /*
31182fca3SMike Marshall * (C) 2001 Clemson University and The University of Chicago
41182fca3SMike Marshall * (C) 2011 Omnibond Systems
51182fca3SMike Marshall *
61182fca3SMike Marshall * Changes by Acxiom Corporation to implement generic service_operation()
71182fca3SMike Marshall * function, Copyright Acxiom Corporation, 2005.
81182fca3SMike Marshall *
91182fca3SMike Marshall * See COPYING in top-level directory.
101182fca3SMike Marshall */
111182fca3SMike Marshall
121182fca3SMike Marshall /*
131182fca3SMike Marshall * In-kernel waitqueue operations.
141182fca3SMike Marshall */
151182fca3SMike Marshall
161182fca3SMike Marshall #include "protocol.h"
17575e9461SMike Marshall #include "orangefs-kernel.h"
18575e9461SMike Marshall #include "orangefs-bufmap.h"
191182fca3SMike Marshall
20b1116bc0SMike Marshall static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
21b1116bc0SMike Marshall long timeout,
22*0dcac0f7SMartin Brandenburg int flags)
23b1116bc0SMike Marshall __acquires(op->lock);
24b1116bc0SMike Marshall static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op)
25b1116bc0SMike Marshall __releases(op->lock);
26ade3d781SAl Viro
271182fca3SMike Marshall /*
281182fca3SMike Marshall * What we do in this function is to walk the list of operations that are
291182fca3SMike Marshall * present in the request queue and mark them as purged.
301182fca3SMike Marshall * NOTE: This is called from the device close after client-core has
311182fca3SMike Marshall * guaranteed that no new operations could appear on the list since the
321182fca3SMike Marshall * client-core is anyway going to exit.
331182fca3SMike Marshall */
purge_waiting_ops(void)341182fca3SMike Marshall void purge_waiting_ops(void)
351182fca3SMike Marshall {
360afc0decSMartin Brandenburg struct orangefs_kernel_op_s *op, *tmp;
371182fca3SMike Marshall
388bb8aefdSYi Liu spin_lock(&orangefs_request_list_lock);
390afc0decSMartin Brandenburg list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) {
401182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
411182fca3SMike Marshall "pvfs2-client-core: purging op tag %llu %s\n",
421182fca3SMike Marshall llu(op->tag),
431182fca3SMike Marshall get_opname_string(op));
441182fca3SMike Marshall set_op_state_purged(op);
459d9e7ba9SMike Marshall gossip_debug(GOSSIP_DEV_DEBUG,
469d9e7ba9SMike Marshall "%s: op:%s: op_state:%d: process:%s:\n",
479d9e7ba9SMike Marshall __func__,
489d9e7ba9SMike Marshall get_opname_string(op),
499d9e7ba9SMike Marshall op->op_state,
509d9e7ba9SMike Marshall current->comm);
511182fca3SMike Marshall }
528bb8aefdSYi Liu spin_unlock(&orangefs_request_list_lock);
531182fca3SMike Marshall }
541182fca3SMike Marshall
551182fca3SMike Marshall /*
568bb8aefdSYi Liu * submits a ORANGEFS operation and waits for it to complete
571182fca3SMike Marshall *
581182fca3SMike Marshall * Note op->downcall.status will contain the status of the operation (in
591182fca3SMike Marshall * errno format), whether provided by pvfs2-client or a result of failure to
601182fca3SMike Marshall * service the operation. If the caller wishes to distinguish, then
611182fca3SMike Marshall * op->state can be checked to see if it was serviced or not.
621182fca3SMike Marshall *
631182fca3SMike Marshall * Returns contents of op->downcall.status for convenience
641182fca3SMike Marshall */
service_operation(struct orangefs_kernel_op_s * op,const char * op_name,int flags)658bb8aefdSYi Liu int service_operation(struct orangefs_kernel_op_s *op,
661182fca3SMike Marshall const char *op_name,
671182fca3SMike Marshall int flags)
681182fca3SMike Marshall {
6905b39a8bSAl Viro long timeout = MAX_SCHEDULE_TIMEOUT;
701182fca3SMike Marshall int ret = 0;
711182fca3SMike Marshall
72ce6c414eSMike Marshall DEFINE_WAIT(wait_entry);
731182fca3SMike Marshall
741182fca3SMike Marshall op->upcall.tgid = current->tgid;
751182fca3SMike Marshall op->upcall.pid = current->pid;
761182fca3SMike Marshall
771182fca3SMike Marshall retry_servicing:
781182fca3SMike Marshall op->downcall.status = 0;
791182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
805253487eSMike Marshall "%s: %s op:%p: process:%s: pid:%d:\n",
815253487eSMike Marshall __func__,
821182fca3SMike Marshall op_name,
835253487eSMike Marshall op,
841182fca3SMike Marshall current->comm,
851182fca3SMike Marshall current->pid);
861182fca3SMike Marshall
87adcf34a2SMike Marshall /*
88adcf34a2SMike Marshall * If ORANGEFS_OP_NO_MUTEX was set in flags, we need to avoid
89ca9f518eSMike Marshall * acquiring the request_mutex because we're servicing a
90adcf34a2SMike Marshall * high priority remount operation and the request_mutex is
91adcf34a2SMike Marshall * already taken.
92adcf34a2SMike Marshall */
93adcf34a2SMike Marshall if (!(flags & ORANGEFS_OP_NO_MUTEX)) {
94c72f15b7SAl Viro if (flags & ORANGEFS_OP_INTERRUPTIBLE)
951d503617SMartin Brandenburg ret = mutex_lock_interruptible(&orangefs_request_mutex);
96c72f15b7SAl Viro else
971d503617SMartin Brandenburg ret = mutex_lock_killable(&orangefs_request_mutex);
981182fca3SMike Marshall /*
991182fca3SMike Marshall * check to see if we were interrupted while waiting for
100adcf34a2SMike Marshall * mutex
1011182fca3SMike Marshall */
1021182fca3SMike Marshall if (ret < 0) {
1031182fca3SMike Marshall op->downcall.status = ret;
1041182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
105ca9f518eSMike Marshall "%s: service_operation interrupted.\n",
106ca9f518eSMike Marshall __func__);
1071182fca3SMike Marshall return ret;
1081182fca3SMike Marshall }
1091182fca3SMike Marshall }
1101182fca3SMike Marshall
11198815adeSAl Viro /* queue up the operation */
11298815adeSAl Viro spin_lock(&orangefs_request_list_lock);
11398815adeSAl Viro spin_lock(&op->lock);
11498815adeSAl Viro set_op_state_waiting(op);
1159d9e7ba9SMike Marshall gossip_debug(GOSSIP_DEV_DEBUG,
1169d9e7ba9SMike Marshall "%s: op:%s: op_state:%d: process:%s:\n",
1179d9e7ba9SMike Marshall __func__,
1189d9e7ba9SMike Marshall get_opname_string(op),
1199d9e7ba9SMike Marshall op->op_state,
1209d9e7ba9SMike Marshall current->comm);
121adcf34a2SMike Marshall /* add high priority remount op to the front of the line. */
12298815adeSAl Viro if (flags & ORANGEFS_OP_PRIORITY)
12398815adeSAl Viro list_add(&op->list, &orangefs_request_list);
12498815adeSAl Viro else
12598815adeSAl Viro list_add_tail(&op->list, &orangefs_request_list);
12698815adeSAl Viro spin_unlock(&op->lock);
12798815adeSAl Viro wake_up_interruptible(&orangefs_request_list_waitq);
12898815adeSAl Viro if (!__is_daemon_in_service()) {
1291182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
13098815adeSAl Viro "%s:client core is NOT in service.\n",
13198815adeSAl Viro __func__);
132b5a9d61eSMartin Brandenburg /*
133b5a9d61eSMartin Brandenburg * Don't wait for the userspace component to return if
134b5a9d61eSMartin Brandenburg * the filesystem is being umounted anyway.
135b5a9d61eSMartin Brandenburg */
136b5a9d61eSMartin Brandenburg if (op->upcall.type == ORANGEFS_VFS_OP_FS_UMOUNT)
137b5a9d61eSMartin Brandenburg timeout = 0;
138b5a9d61eSMartin Brandenburg else
13905b39a8bSAl Viro timeout = op_timeout_secs * HZ;
1401182fca3SMike Marshall }
14198815adeSAl Viro spin_unlock(&orangefs_request_list_lock);
1421182fca3SMike Marshall
143adcf34a2SMike Marshall if (!(flags & ORANGEFS_OP_NO_MUTEX))
1441d503617SMartin Brandenburg mutex_unlock(&orangefs_request_mutex);
1451182fca3SMike Marshall
146*0dcac0f7SMartin Brandenburg ret = wait_for_matching_downcall(op, timeout, flags);
1475253487eSMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
1485253487eSMike Marshall "%s: wait_for_matching_downcall returned %d for %p\n",
1495253487eSMike Marshall __func__,
1505253487eSMike Marshall ret,
1515253487eSMike Marshall op);
1525253487eSMike Marshall
153ca9f518eSMike Marshall /* got matching downcall; make sure status is in errno format */
15405b39a8bSAl Viro if (!ret) {
15505b39a8bSAl Viro spin_unlock(&op->lock);
15605b39a8bSAl Viro op->downcall.status =
15705b39a8bSAl Viro orangefs_normalize_to_errno(op->downcall.status);
15805b39a8bSAl Viro ret = op->downcall.status;
15905b39a8bSAl Viro goto out;
16005b39a8bSAl Viro }
1611182fca3SMike Marshall
1621182fca3SMike Marshall /* failed to get matching downcall */
1631182fca3SMike Marshall if (ret == -ETIMEDOUT) {
164adcf34a2SMike Marshall gossip_err("%s: %s -- wait timed out; aborting attempt.\n",
165adcf34a2SMike Marshall __func__,
1661182fca3SMike Marshall op_name);
1671182fca3SMike Marshall }
168adcf34a2SMike Marshall
169adcf34a2SMike Marshall /*
170ca9f518eSMike Marshall * remove a waiting op from the request list or
171ca9f518eSMike Marshall * remove an in-progress op from the in-progress list.
172adcf34a2SMike Marshall */
173d2d87a3bSAl Viro orangefs_clean_up_interrupted_operation(op);
174adcf34a2SMike Marshall
1751182fca3SMike Marshall op->downcall.status = ret;
1761182fca3SMike Marshall /* retry if operation has not been serviced and if requested */
17705b39a8bSAl Viro if (ret == -EAGAIN) {
17805b39a8bSAl Viro op->attempts++;
17905b39a8bSAl Viro timeout = op_timeout_secs * HZ;
1801182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
1818bb8aefdSYi Liu "orangefs: tag %llu (%s)"
1821182fca3SMike Marshall " -- operation to be retried (%d attempt)\n",
1831182fca3SMike Marshall llu(op->tag),
1841182fca3SMike Marshall op_name,
18505b39a8bSAl Viro op->attempts);
1861182fca3SMike Marshall
1871182fca3SMike Marshall /*
188adcf34a2SMike Marshall * io ops (ops that use the shared memory buffer) have
189adcf34a2SMike Marshall * to be returned to their caller for a retry. Other ops
190adcf34a2SMike Marshall * can just be recycled here.
1911182fca3SMike Marshall */
192adcf34a2SMike Marshall if (!op->uses_shared_memory)
1931182fca3SMike Marshall goto retry_servicing;
1941182fca3SMike Marshall }
1951182fca3SMike Marshall
19605b39a8bSAl Viro out:
1971182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
1989d9e7ba9SMike Marshall "%s: %s returning: %d for %p.\n",
1999d9e7ba9SMike Marshall __func__,
2001182fca3SMike Marshall op_name,
2011182fca3SMike Marshall ret,
2021182fca3SMike Marshall op);
2031182fca3SMike Marshall return ret;
2041182fca3SMike Marshall }
2051182fca3SMike Marshall
206ca9f518eSMike Marshall /* 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)20778699e29SAl Viro bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op)
20878699e29SAl Viro {
20978699e29SAl Viro u64 tag = op->tag;
21078699e29SAl Viro if (!op_state_in_progress(op))
21178699e29SAl Viro return false;
21278699e29SAl Viro
21378699e29SAl Viro op->slot_to_free = op->upcall.req.io.buf_index;
21478699e29SAl Viro memset(&op->upcall, 0, sizeof(op->upcall));
21578699e29SAl Viro memset(&op->downcall, 0, sizeof(op->downcall));
21678699e29SAl Viro op->upcall.type = ORANGEFS_VFS_OP_CANCEL;
21778699e29SAl Viro op->upcall.req.cancel.op_tag = tag;
21878699e29SAl Viro op->downcall.type = ORANGEFS_VFS_OP_INVALID;
21978699e29SAl Viro op->downcall.status = -1;
22078699e29SAl Viro orangefs_new_tag(op);
22178699e29SAl Viro
22278699e29SAl Viro spin_lock(&orangefs_request_list_lock);
22378699e29SAl Viro /* orangefs_request_list_lock is enough of a barrier here */
22478699e29SAl Viro if (!__is_daemon_in_service()) {
22578699e29SAl Viro spin_unlock(&orangefs_request_list_lock);
22678699e29SAl Viro return false;
22778699e29SAl Viro }
22898815adeSAl Viro spin_lock(&op->lock);
22998815adeSAl Viro set_op_state_waiting(op);
2309d9e7ba9SMike Marshall gossip_debug(GOSSIP_DEV_DEBUG,
2319d9e7ba9SMike Marshall "%s: op:%s: op_state:%d: process:%s:\n",
2329d9e7ba9SMike Marshall __func__,
2339d9e7ba9SMike Marshall get_opname_string(op),
2349d9e7ba9SMike Marshall op->op_state,
2359d9e7ba9SMike Marshall current->comm);
23698815adeSAl Viro list_add(&op->list, &orangefs_request_list);
23798815adeSAl Viro spin_unlock(&op->lock);
23878699e29SAl Viro spin_unlock(&orangefs_request_list_lock);
23978699e29SAl Viro
240ca9f518eSMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
24178699e29SAl Viro "Attempting ORANGEFS operation cancellation of tag %llu\n",
24278699e29SAl Viro llu(tag));
24378699e29SAl Viro return true;
24478699e29SAl Viro }
24578699e29SAl Viro
246ca9f518eSMike Marshall /*
247ca9f518eSMike Marshall * Change an op to the "given up" state and remove it from its list.
248ca9f518eSMike Marshall */
249ca9f518eSMike Marshall static void
orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s * op)250ca9f518eSMike Marshall orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s *op)
251b1116bc0SMike Marshall __releases(op->lock)
2521182fca3SMike Marshall {
2531182fca3SMike Marshall /*
2541182fca3SMike Marshall * handle interrupted cases depending on what state we were in when
255ca9f518eSMike Marshall * the interruption is detected.
2561182fca3SMike Marshall *
257eab9b389SAl Viro * Called with op->lock held.
2581182fca3SMike Marshall */
259ca9f518eSMike Marshall
260ca9f518eSMike Marshall /*
261ca9f518eSMike Marshall * List manipulation code elsewhere will ignore ops that
262ca9f518eSMike Marshall * have been given up upon.
263ca9f518eSMike Marshall */
264ed42fe05SAl Viro op->op_state |= OP_VFS_STATE_GIVEN_UP;
265ca9f518eSMike Marshall
26605a50a5bSAl Viro if (list_empty(&op->list)) {
26705a50a5bSAl Viro /* caught copying to/from daemon */
26805a50a5bSAl Viro BUG_ON(op_state_serviced(op));
26905a50a5bSAl Viro spin_unlock(&op->lock);
27005a50a5bSAl Viro wait_for_completion(&op->waitq);
27105a50a5bSAl Viro } else if (op_state_waiting(op)) {
2721182fca3SMike Marshall /*
2731182fca3SMike Marshall * upcall hasn't been read; remove op from upcall request
2741182fca3SMike Marshall * list.
2751182fca3SMike Marshall */
2761182fca3SMike Marshall spin_unlock(&op->lock);
277ed42fe05SAl Viro spin_lock(&orangefs_request_list_lock);
27805a50a5bSAl Viro list_del_init(&op->list);
279ed42fe05SAl Viro spin_unlock(&orangefs_request_list_lock);
2801182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
2811182fca3SMike Marshall "Interrupted: Removed op %p from request_list\n",
2821182fca3SMike Marshall op);
2831182fca3SMike Marshall } else if (op_state_in_progress(op)) {
2841182fca3SMike Marshall /* op must be removed from the in progress htable */
2851182fca3SMike Marshall spin_unlock(&op->lock);
2861d503617SMartin Brandenburg spin_lock(&orangefs_htable_ops_in_progress_lock);
28705a50a5bSAl Viro list_del_init(&op->list);
2881d503617SMartin Brandenburg spin_unlock(&orangefs_htable_ops_in_progress_lock);
2891182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
2901182fca3SMike Marshall "Interrupted: Removed op %p"
2911182fca3SMike Marshall " from htable_ops_in_progress\n",
2921182fca3SMike Marshall op);
29305a50a5bSAl Viro } else {
2941182fca3SMike Marshall spin_unlock(&op->lock);
2951182fca3SMike Marshall gossip_err("interrupted operation is in a weird state 0x%x\n",
2961182fca3SMike Marshall op->op_state);
2971182fca3SMike Marshall }
298d2d87a3bSAl Viro reinit_completion(&op->waitq);
2991182fca3SMike Marshall }
3001182fca3SMike Marshall
3011182fca3SMike Marshall /*
302ca9f518eSMike Marshall * Sleeps on waitqueue waiting for matching downcall.
303ca9f518eSMike Marshall * If client-core finishes servicing, then we are good to go.
3041182fca3SMike Marshall * else if client-core exits, we get woken up here, and retry with a timeout
3051182fca3SMike Marshall *
306ca9f518eSMike Marshall * When this call returns to the caller, the specified op will no
307ca9f518eSMike Marshall * longer be in either the in_progress hash table or on the request list.
3081182fca3SMike Marshall *
3091182fca3SMike Marshall * Returns 0 on success and -errno on failure
3101182fca3SMike Marshall * Errors are:
3111182fca3SMike Marshall * EAGAIN in case we want the caller to requeue and try again..
3121182fca3SMike Marshall * EINTR/EIO/ETIMEDOUT indicating we are done trying to service this
3131182fca3SMike Marshall * operation since client-core seems to be exiting too often
3141182fca3SMike Marshall * or if we were interrupted.
315d2d87a3bSAl Viro *
316d2d87a3bSAl Viro * Returns with op->lock taken.
3171182fca3SMike Marshall */
wait_for_matching_downcall(struct orangefs_kernel_op_s * op,long timeout,int flags)318c72f15b7SAl Viro static int wait_for_matching_downcall(struct orangefs_kernel_op_s *op,
31905b39a8bSAl Viro long timeout,
320*0dcac0f7SMartin Brandenburg int flags)
321b1116bc0SMike Marshall __acquires(op->lock)
3221182fca3SMike Marshall {
32305b39a8bSAl Viro long n;
324*0dcac0f7SMartin Brandenburg int writeback = flags & ORANGEFS_OP_WRITEBACK,
325*0dcac0f7SMartin Brandenburg interruptible = flags & ORANGEFS_OP_INTERRUPTIBLE;
326c72f15b7SAl Viro
327ca9f518eSMike Marshall /*
328ca9f518eSMike Marshall * There's a "schedule_timeout" inside of these wait
329ca9f518eSMike Marshall * primitives, during which the op is out of the hands of the
330ca9f518eSMike Marshall * user process that needs something done and is being
331ca9f518eSMike Marshall * manipulated by the client-core process.
332ca9f518eSMike Marshall */
333*0dcac0f7SMartin Brandenburg if (writeback)
334*0dcac0f7SMartin Brandenburg n = wait_for_completion_io_timeout(&op->waitq, timeout);
335*0dcac0f7SMartin Brandenburg else if (!writeback && interruptible)
336adcf34a2SMike Marshall n = wait_for_completion_interruptible_timeout(&op->waitq,
337adcf34a2SMike Marshall timeout);
338*0dcac0f7SMartin Brandenburg else /* !writeback && !interruptible but compiler complains */
339c72f15b7SAl Viro n = wait_for_completion_killable_timeout(&op->waitq, timeout);
340c72f15b7SAl Viro
3411182fca3SMike Marshall spin_lock(&op->lock);
3421182fca3SMike Marshall
343d2d87a3bSAl Viro if (op_state_serviced(op))
344d2d87a3bSAl Viro return 0;
345d2d87a3bSAl Viro
346d2d87a3bSAl Viro if (unlikely(n < 0)) {
34770c6ea26SAl Viro gossip_debug(GOSSIP_WAIT_DEBUG,
3489d9e7ba9SMike Marshall "%s: operation interrupted, tag %llu, %p\n",
34970c6ea26SAl Viro __func__,
35070c6ea26SAl Viro llu(op->tag),
35170c6ea26SAl Viro op);
352d2d87a3bSAl Viro return -EINTR;
35370c6ea26SAl Viro }
3541182fca3SMike Marshall if (op_state_purged(op)) {
3551182fca3SMike Marshall gossip_debug(GOSSIP_WAIT_DEBUG,
3569d9e7ba9SMike Marshall "%s: operation purged, tag %llu, %p, %d\n",
3571182fca3SMike Marshall __func__,
3581182fca3SMike Marshall llu(op->tag),
3591182fca3SMike Marshall op,
3601182fca3SMike Marshall op->attempts);
361d2d87a3bSAl Viro return (op->attempts < ORANGEFS_PURGE_RETRY_COUNT) ?
362d2d87a3bSAl Viro -EAGAIN :
363d2d87a3bSAl Viro -EIO;
3641182fca3SMike Marshall }
365d2d87a3bSAl Viro /* must have timed out, then... */
366d2d87a3bSAl Viro gossip_debug(GOSSIP_WAIT_DEBUG,
3679d9e7ba9SMike Marshall "%s: operation timed out, tag %llu, %p, %d)\n",
368d2d87a3bSAl Viro __func__,
369d2d87a3bSAl Viro llu(op->tag),
370d2d87a3bSAl Viro op,
371d2d87a3bSAl Viro op->attempts);
372d2d87a3bSAl Viro return -ETIMEDOUT;
3731182fca3SMike Marshall }
374