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