linux/drivers/s390/scsi/zfcp_reqlist.h
<<
>>
Prefs
   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 * @buckets: Array of hashbuckets, each is a list of requests in this bucket
  21 */
  22struct zfcp_reqlist {
  23        spinlock_t lock;
  24        struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
  25};
  26
  27static 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 */
  38static 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 */
  61static 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 */
  75static 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
  83static inline struct zfcp_fsf_req *
  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 */
 104static inline struct zfcp_fsf_req *
 105zfcp_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 */
 129static inline struct zfcp_fsf_req *
 130zfcp_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 */
 154static 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 */
 172static 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 */
 197static inline void
 198zfcp_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