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 
zfcp_reqlist_hash(unsigned long req_id)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  */
zfcp_reqlist_alloc(void)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  */
zfcp_reqlist_isempty(struct zfcp_reqlist * rl)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  */
zfcp_reqlist_free(struct zfcp_reqlist * rl)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 *
_zfcp_reqlist_find(struct zfcp_reqlist * rl,unsigned long req_id)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 *
zfcp_reqlist_find(struct zfcp_reqlist * rl,unsigned long req_id)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 *
zfcp_reqlist_find_rm(struct zfcp_reqlist * rl,unsigned long req_id)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  */
zfcp_reqlist_add(struct zfcp_reqlist * rl,struct zfcp_fsf_req * req)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  */
zfcp_reqlist_move(struct zfcp_reqlist * rl,struct list_head * list)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
zfcp_reqlist_apply_for_all(struct zfcp_reqlist * rl,void (* f)(struct zfcp_fsf_req *,void *),void * data)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