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