zfcp_reqlist.h (5552B)
1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * zfcp device driver 4 * 5 * Data structure and helper functions for tracking pending FSF 6 * requests. 7 * 8 * Copyright IBM Corp. 2009, 2016 9 */ 10 11#ifndef ZFCP_REQLIST_H 12#define ZFCP_REQLIST_H 13 14/* number of hash buckets */ 15#define ZFCP_REQ_LIST_BUCKETS 128 16 17/** 18 * struct zfcp_reqlist - Container for request list (reqlist) 19 * @lock: Spinlock for protecting the hash list 20 * @buckets: Array of hashbuckets, each is a list of requests in this bucket 21 */ 22struct zfcp_reqlist { 23 spinlock_t lock; 24 struct list_head buckets[ZFCP_REQ_LIST_BUCKETS]; 25}; 26 27static inline int zfcp_reqlist_hash(unsigned long req_id) 28{ 29 return req_id % ZFCP_REQ_LIST_BUCKETS; 30} 31 32/** 33 * zfcp_reqlist_alloc - Allocate and initialize reqlist 34 * 35 * Returns pointer to allocated reqlist on success, or NULL on 36 * allocation failure. 37 */ 38static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void) 39{ 40 unsigned int i; 41 struct zfcp_reqlist *rl; 42 43 rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL); 44 if (!rl) 45 return NULL; 46 47 spin_lock_init(&rl->lock); 48 49 for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++) 50 INIT_LIST_HEAD(&rl->buckets[i]); 51 52 return rl; 53} 54 55/** 56 * zfcp_reqlist_isempty - Check whether the request list empty 57 * @rl: pointer to reqlist 58 * 59 * Returns: 1 if list is empty, 0 if not 60 */ 61static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl) 62{ 63 unsigned int i; 64 65 for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++) 66 if (!list_empty(&rl->buckets[i])) 67 return 0; 68 return 1; 69} 70 71/** 72 * zfcp_reqlist_free - Free allocated memory for reqlist 73 * @rl: The reqlist where to free memory 74 */ 75static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl) 76{ 77 /* sanity check */ 78 BUG_ON(!zfcp_reqlist_isempty(rl)); 79 80 kfree(rl); 81} 82 83static inline struct zfcp_fsf_req * 84_zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id) 85{ 86 struct zfcp_fsf_req *req; 87 unsigned int i; 88 89 i = zfcp_reqlist_hash(req_id); 90 list_for_each_entry(req, &rl->buckets[i], list) 91 if (req->req_id == req_id) 92 return req; 93 return NULL; 94} 95 96/** 97 * zfcp_reqlist_find - Lookup FSF request by its request id 98 * @rl: The reqlist where to lookup the FSF request 99 * @req_id: The request id to look for 100 * 101 * Returns a pointer to the FSF request with the specified request id 102 * or NULL if there is no known FSF request with this id. 103 */ 104static inline struct zfcp_fsf_req * 105zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id) 106{ 107 unsigned long flags; 108 struct zfcp_fsf_req *req; 109 110 spin_lock_irqsave(&rl->lock, flags); 111 req = _zfcp_reqlist_find(rl, req_id); 112 spin_unlock_irqrestore(&rl->lock, flags); 113 114 return req; 115} 116 117/** 118 * zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist 119 * @rl: reqlist where to search and remove entry 120 * @req_id: The request id of the request to look for 121 * 122 * This functions tries to find the FSF request with the specified 123 * id and then removes it from the reqlist. The reqlist lock is held 124 * during both steps of the operation. 125 * 126 * Returns: Pointer to the FSF request if the request has been found, 127 * NULL if it has not been found. 128 */ 129static inline struct zfcp_fsf_req * 130zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, unsigned long req_id) 131{ 132 unsigned long flags; 133 struct zfcp_fsf_req *req; 134 135 spin_lock_irqsave(&rl->lock, flags); 136 req = _zfcp_reqlist_find(rl, req_id); 137 if (req) 138 list_del(&req->list); 139 spin_unlock_irqrestore(&rl->lock, flags); 140 141 return req; 142} 143 144/** 145 * zfcp_reqlist_add - Add entry to reqlist 146 * @rl: reqlist where to add the entry 147 * @req: The entry to add 148 * 149 * The request id always increases. As an optimization new requests 150 * are added here with list_add_tail at the end of the bucket lists 151 * while old requests are looked up starting at the beginning of the 152 * lists. 153 */ 154static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl, 155 struct zfcp_fsf_req *req) 156{ 157 unsigned int i; 158 unsigned long flags; 159 160 i = zfcp_reqlist_hash(req->req_id); 161 162 spin_lock_irqsave(&rl->lock, flags); 163 list_add_tail(&req->list, &rl->buckets[i]); 164 spin_unlock_irqrestore(&rl->lock, flags); 165} 166 167/** 168 * zfcp_reqlist_move - Move all entries from reqlist to simple list 169 * @rl: The zfcp_reqlist where to remove all entries 170 * @list: The list where to move all entries 171 */ 172static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl, 173 struct list_head *list) 174{ 175 unsigned int i; 176 unsigned long flags; 177 178 spin_lock_irqsave(&rl->lock, flags); 179 for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++) 180 list_splice_init(&rl->buckets[i], list); 181 spin_unlock_irqrestore(&rl->lock, flags); 182} 183 184/** 185 * zfcp_reqlist_apply_for_all() - apply a function to every request. 186 * @rl: the requestlist that contains the target requests. 187 * @f: the function to apply to each request; the first parameter of the 188 * function will be the target-request; the second parameter is the same 189 * pointer as given with the argument @data. 190 * @data: freely chosen argument; passed through to @f as second parameter. 191 * 192 * Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash- 193 * table (not a 'safe' variant, so don't modify the list). 194 * 195 * Holds @rl->lock over the entire request-iteration. 196 */ 197static inline void 198zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl, 199 void (*f)(struct zfcp_fsf_req *, void *), void *data) 200{ 201 struct zfcp_fsf_req *req; 202 unsigned long flags; 203 unsigned int i; 204 205 spin_lock_irqsave(&rl->lock, flags); 206 for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++) 207 list_for_each_entry(req, &rl->buckets[i], list) 208 f(req, data); 209 spin_unlock_irqrestore(&rl->lock, flags); 210} 211 212#endif /* ZFCP_REQLIST_H */