1 /*
2 * zfcp device driver
3 *
4 * Data structure and helper functions for tracking pending FSF
5 * requests.
6 *
7 * Copyright IBM Corp. 2009
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
zfcp_reqlist_hash(unsigned long req_id)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 */
zfcp_reqlist_alloc(void)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 */
zfcp_reqlist_isempty(struct zfcp_reqlist * rl)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 */
zfcp_reqlist_free(struct zfcp_reqlist * rl)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 *
_zfcp_reqlist_find(struct zfcp_reqlist * rl,unsigned long req_id)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 *
zfcp_reqlist_find(struct zfcp_reqlist * rl,unsigned long req_id)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 *
zfcp_reqlist_find_rm(struct zfcp_reqlist * rl,unsigned long req_id)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 */
zfcp_reqlist_add(struct zfcp_reqlist * rl,struct zfcp_fsf_req * req)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 */
zfcp_reqlist_move(struct zfcp_reqlist * rl,struct list_head * list)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 #endif /* ZFCP_REQLIST_H */
184