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