Commit | Line | Data |
---|---|---|
b6bd2fb9 CS |
1 | /* |
2 | * zfcp device driver | |
3 | * | |
4 | * Data structure and helper functions for tracking pending FSF | |
5 | * requests. | |
6 | * | |
7 | * Copyright IBM Corporation 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 | ||
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 | #endif /* ZFCP_REQLIST_H */ |