zfcp_reqlist.h 5.4 KB

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