brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · 59fbb1b Raw
215 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * zfcp device driver4 *5 * Data structure and helper functions for tracking pending FSF6 * requests.7 *8 * Copyright IBM Corp. 2009, 20239 */10 11#ifndef ZFCP_REQLIST_H12#define ZFCP_REQLIST_H13 14#include <linux/types.h>15 16/* number of hash buckets */17#define ZFCP_REQ_LIST_BUCKETS 128u18 19/**20 * struct zfcp_reqlist - Container for request list (reqlist)21 * @lock: Spinlock for protecting the hash list22 * @buckets: Array of hashbuckets, each is a list of requests in this bucket23 */24struct zfcp_reqlist {25	spinlock_t lock;26	struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];27};28 29static 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 reqlist36 *37 * Returns pointer to allocated reqlist on success, or NULL on38 * allocation failure.39 */40static 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 empty59 * @rl: pointer to reqlist60 *61 * Returns: 1 if list is empty, 0 if not62 */63static 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 reqlist75 * @rl: The reqlist where to free memory76 */77static 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 85static 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 id100 * @rl: The reqlist where to lookup the FSF request101 * @req_id: The request id to look for102 *103 * Returns a pointer to the FSF request with the specified request id104 * or NULL if there is no known FSF request with this id.105 */106static inline struct zfcp_fsf_req *107zfcp_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 reqlist121 * @rl: reqlist where to search and remove entry122 * @req_id: The request id of the request to look for123 *124 * This functions tries to find the FSF request with the specified125 * id and then removes it from the reqlist. The reqlist lock is held126 * 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 */131static inline struct zfcp_fsf_req *132zfcp_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 reqlist148 * @rl: reqlist where to add the entry149 * @req: The entry to add150 *151 * The request id always increases. As an optimization new requests152 * are added here with list_add_tail at the end of the bucket lists153 * while old requests are looked up starting at the beginning of the154 * lists.155 */156static 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 list171 * @rl: The zfcp_reqlist where to remove all entries172 * @list: The list where to move all entries173 */174static 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 the190 *     function will be the target-request; the second parameter is the same191 *     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 */199static inline void200zfcp_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