1e7fd4179SDavid Teigland /****************************************************************************** 2e7fd4179SDavid Teigland ******************************************************************************* 3e7fd4179SDavid Teigland ** 4e7fd4179SDavid Teigland ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. 5e7fd4179SDavid Teigland ** 6e7fd4179SDavid Teigland ** This copyrighted material is made available to anyone wishing to use, 7e7fd4179SDavid Teigland ** modify, copy, or redistribute it subject to the terms and conditions 8e7fd4179SDavid Teigland ** of the GNU General Public License v.2. 9e7fd4179SDavid Teigland ** 10e7fd4179SDavid Teigland ******************************************************************************* 11e7fd4179SDavid Teigland ******************************************************************************/ 12e7fd4179SDavid Teigland 13e7fd4179SDavid Teigland #include "dlm_internal.h" 14e7fd4179SDavid Teigland #include "member.h" 15e7fd4179SDavid Teigland #include "lock.h" 16e7fd4179SDavid Teigland #include "dir.h" 17e7fd4179SDavid Teigland #include "config.h" 18e7fd4179SDavid Teigland #include "requestqueue.h" 19e7fd4179SDavid Teigland 20e7fd4179SDavid Teigland struct rq_entry { 21e7fd4179SDavid Teigland struct list_head list; 22e7fd4179SDavid Teigland int nodeid; 23e7fd4179SDavid Teigland char request[1]; 24e7fd4179SDavid Teigland }; 25e7fd4179SDavid Teigland 26e7fd4179SDavid Teigland /* 27e7fd4179SDavid Teigland * Requests received while the lockspace is in recovery get added to the 28e7fd4179SDavid Teigland * request queue and processed when recovery is complete. This happens when 29e7fd4179SDavid Teigland * the lockspace is suspended on some nodes before it is on others, or the 30e7fd4179SDavid Teigland * lockspace is enabled on some while still suspended on others. 31e7fd4179SDavid Teigland */ 32e7fd4179SDavid Teigland 33d4400156SDavid Teigland int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd) 34e7fd4179SDavid Teigland { 35e7fd4179SDavid Teigland struct rq_entry *e; 36e7fd4179SDavid Teigland int length = hd->h_length; 37d4400156SDavid Teigland int rv = 0; 38e7fd4179SDavid Teigland 39e7fd4179SDavid Teigland e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); 40e7fd4179SDavid Teigland if (!e) { 41e7fd4179SDavid Teigland log_print("dlm_add_requestqueue: out of memory\n"); 42d4400156SDavid Teigland return 0; 43e7fd4179SDavid Teigland } 44e7fd4179SDavid Teigland 45e7fd4179SDavid Teigland e->nodeid = nodeid; 46e7fd4179SDavid Teigland memcpy(e->request, hd, length); 47e7fd4179SDavid Teigland 48d4400156SDavid Teigland /* We need to check dlm_locking_stopped() after taking the mutex to 49d4400156SDavid Teigland avoid a race where dlm_recoverd enables locking and runs 50d4400156SDavid Teigland process_requestqueue between our earlier dlm_locking_stopped check 51d4400156SDavid Teigland and this addition to the requestqueue. */ 52d4400156SDavid Teigland 5390135925SDavid Teigland mutex_lock(&ls->ls_requestqueue_mutex); 54d4400156SDavid Teigland if (dlm_locking_stopped(ls)) 55e7fd4179SDavid Teigland list_add_tail(&e->list, &ls->ls_requestqueue); 56d4400156SDavid Teigland else { 57d4400156SDavid Teigland log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid); 58d4400156SDavid Teigland kfree(e); 59d4400156SDavid Teigland rv = -EAGAIN; 60d4400156SDavid Teigland } 6190135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 62d4400156SDavid Teigland return rv; 63e7fd4179SDavid Teigland } 64e7fd4179SDavid Teigland 65e7fd4179SDavid Teigland int dlm_process_requestqueue(struct dlm_ls *ls) 66e7fd4179SDavid Teigland { 67e7fd4179SDavid Teigland struct rq_entry *e; 68e7fd4179SDavid Teigland struct dlm_header *hd; 69e7fd4179SDavid Teigland int error = 0; 70e7fd4179SDavid Teigland 7190135925SDavid Teigland mutex_lock(&ls->ls_requestqueue_mutex); 72e7fd4179SDavid Teigland 73e7fd4179SDavid Teigland for (;;) { 74e7fd4179SDavid Teigland if (list_empty(&ls->ls_requestqueue)) { 7590135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 76e7fd4179SDavid Teigland error = 0; 77e7fd4179SDavid Teigland break; 78e7fd4179SDavid Teigland } 79e7fd4179SDavid Teigland e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list); 8090135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 81e7fd4179SDavid Teigland 82e7fd4179SDavid Teigland hd = (struct dlm_header *) e->request; 8390135925SDavid Teigland error = dlm_receive_message(hd, e->nodeid, 1); 84e7fd4179SDavid Teigland 85e7fd4179SDavid Teigland if (error == -EINTR) { 86e7fd4179SDavid Teigland /* entry is left on requestqueue */ 87e7fd4179SDavid Teigland log_debug(ls, "process_requestqueue abort eintr"); 88e7fd4179SDavid Teigland break; 89e7fd4179SDavid Teigland } 90e7fd4179SDavid Teigland 9190135925SDavid Teigland mutex_lock(&ls->ls_requestqueue_mutex); 92e7fd4179SDavid Teigland list_del(&e->list); 93e7fd4179SDavid Teigland kfree(e); 94e7fd4179SDavid Teigland 95e7fd4179SDavid Teigland if (dlm_locking_stopped(ls)) { 96e7fd4179SDavid Teigland log_debug(ls, "process_requestqueue abort running"); 9790135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 98e7fd4179SDavid Teigland error = -EINTR; 99e7fd4179SDavid Teigland break; 100e7fd4179SDavid Teigland } 101e7fd4179SDavid Teigland schedule(); 102e7fd4179SDavid Teigland } 103e7fd4179SDavid Teigland 104e7fd4179SDavid Teigland return error; 105e7fd4179SDavid Teigland } 106e7fd4179SDavid Teigland 107e7fd4179SDavid Teigland /* 108e7fd4179SDavid Teigland * After recovery is done, locking is resumed and dlm_recoverd takes all the 109e7fd4179SDavid Teigland * saved requests and processes them as they would have been by dlm_recvd. At 110e7fd4179SDavid Teigland * the same time, dlm_recvd will start receiving new requests from remote 111e7fd4179SDavid Teigland * nodes. We want to delay dlm_recvd processing new requests until 112e7fd4179SDavid Teigland * dlm_recoverd has finished processing the old saved requests. 113e7fd4179SDavid Teigland */ 114e7fd4179SDavid Teigland 115e7fd4179SDavid Teigland void dlm_wait_requestqueue(struct dlm_ls *ls) 116e7fd4179SDavid Teigland { 117e7fd4179SDavid Teigland for (;;) { 11890135925SDavid Teigland mutex_lock(&ls->ls_requestqueue_mutex); 119e7fd4179SDavid Teigland if (list_empty(&ls->ls_requestqueue)) 120e7fd4179SDavid Teigland break; 121e7fd4179SDavid Teigland if (dlm_locking_stopped(ls)) 122e7fd4179SDavid Teigland break; 12390135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 124e7fd4179SDavid Teigland schedule(); 125e7fd4179SDavid Teigland } 12690135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 127e7fd4179SDavid Teigland } 128e7fd4179SDavid Teigland 129e7fd4179SDavid Teigland static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid) 130e7fd4179SDavid Teigland { 131e7fd4179SDavid Teigland uint32_t type = ms->m_type; 132e7fd4179SDavid Teigland 133*2896ee37SDavid Teigland /* the ls is being cleaned up and freed by release_lockspace */ 134*2896ee37SDavid Teigland if (!ls->ls_count) 135*2896ee37SDavid Teigland return 1; 136*2896ee37SDavid Teigland 137e7fd4179SDavid Teigland if (dlm_is_removed(ls, nodeid)) 138e7fd4179SDavid Teigland return 1; 139e7fd4179SDavid Teigland 140e7fd4179SDavid Teigland /* directory operations are always purged because the directory is 141e7fd4179SDavid Teigland always rebuilt during recovery and the lookups resent */ 142e7fd4179SDavid Teigland 143e7fd4179SDavid Teigland if (type == DLM_MSG_REMOVE || 144e7fd4179SDavid Teigland type == DLM_MSG_LOOKUP || 145e7fd4179SDavid Teigland type == DLM_MSG_LOOKUP_REPLY) 146e7fd4179SDavid Teigland return 1; 147e7fd4179SDavid Teigland 148e7fd4179SDavid Teigland if (!dlm_no_directory(ls)) 149e7fd4179SDavid Teigland return 0; 150e7fd4179SDavid Teigland 151e7fd4179SDavid Teigland /* with no directory, the master is likely to change as a part of 152e7fd4179SDavid Teigland recovery; requests to/from the defunct master need to be purged */ 153e7fd4179SDavid Teigland 154e7fd4179SDavid Teigland switch (type) { 155e7fd4179SDavid Teigland case DLM_MSG_REQUEST: 156e7fd4179SDavid Teigland case DLM_MSG_CONVERT: 157e7fd4179SDavid Teigland case DLM_MSG_UNLOCK: 158e7fd4179SDavid Teigland case DLM_MSG_CANCEL: 159e7fd4179SDavid Teigland /* we're no longer the master of this resource, the sender 160e7fd4179SDavid Teigland will resend to the new master (see waiter_needs_recovery) */ 161e7fd4179SDavid Teigland 162e7fd4179SDavid Teigland if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid()) 163e7fd4179SDavid Teigland return 1; 164e7fd4179SDavid Teigland break; 165e7fd4179SDavid Teigland 166e7fd4179SDavid Teigland case DLM_MSG_REQUEST_REPLY: 167e7fd4179SDavid Teigland case DLM_MSG_CONVERT_REPLY: 168e7fd4179SDavid Teigland case DLM_MSG_UNLOCK_REPLY: 169e7fd4179SDavid Teigland case DLM_MSG_CANCEL_REPLY: 170e7fd4179SDavid Teigland case DLM_MSG_GRANT: 171e7fd4179SDavid Teigland /* this reply is from the former master of the resource, 172e7fd4179SDavid Teigland we'll resend to the new master if needed */ 173e7fd4179SDavid Teigland 174e7fd4179SDavid Teigland if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid) 175e7fd4179SDavid Teigland return 1; 176e7fd4179SDavid Teigland break; 177e7fd4179SDavid Teigland } 178e7fd4179SDavid Teigland 179e7fd4179SDavid Teigland return 0; 180e7fd4179SDavid Teigland } 181e7fd4179SDavid Teigland 182e7fd4179SDavid Teigland void dlm_purge_requestqueue(struct dlm_ls *ls) 183e7fd4179SDavid Teigland { 184e7fd4179SDavid Teigland struct dlm_message *ms; 185e7fd4179SDavid Teigland struct rq_entry *e, *safe; 186e7fd4179SDavid Teigland 18790135925SDavid Teigland mutex_lock(&ls->ls_requestqueue_mutex); 188e7fd4179SDavid Teigland list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) { 189e7fd4179SDavid Teigland ms = (struct dlm_message *) e->request; 190e7fd4179SDavid Teigland 191e7fd4179SDavid Teigland if (purge_request(ls, ms, e->nodeid)) { 192e7fd4179SDavid Teigland list_del(&e->list); 193e7fd4179SDavid Teigland kfree(e); 194e7fd4179SDavid Teigland } 195e7fd4179SDavid Teigland } 19690135925SDavid Teigland mutex_unlock(&ls->ls_requestqueue_mutex); 197e7fd4179SDavid Teigland } 198e7fd4179SDavid Teigland 199