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 * @list: Array of hashbuckets, each is a list of requests in this bucket 21 */ 22 struct zfcp_reqlist { 23 spinlock_t lock; 24 struct list_head buckets[ZFCP_REQ_LIST_BUCKETS]; 25 }; 26 27 static 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 */ 38 static 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 */ 61 static 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 */ 75 static 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 83 static 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 */ 104 static inline struct zfcp_fsf_req * 105 zfcp_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 */ 129 static inline struct zfcp_fsf_req * 130 zfcp_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 */ 154 static 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 */ 172 static 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 */ 197 static inline void 198 zfcp_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 */ 213