Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * zfcp device driver
0004  *
0005  * Data structure and helper functions for tracking pending FSF
0006  * requests.
0007  *
0008  * Copyright IBM Corp. 2009, 2016
0009  */
0010 
0011 #ifndef ZFCP_REQLIST_H
0012 #define ZFCP_REQLIST_H
0013 
0014 /* number of hash buckets */
0015 #define ZFCP_REQ_LIST_BUCKETS 128
0016 
0017 /**
0018  * struct zfcp_reqlist - Container for request list (reqlist)
0019  * @lock: Spinlock for protecting the hash list
0020  * @buckets: Array of hashbuckets, each is a list of requests in this bucket
0021  */
0022 struct zfcp_reqlist {
0023     spinlock_t lock;
0024     struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
0025 };
0026 
0027 static inline int zfcp_reqlist_hash(unsigned long req_id)
0028 {
0029     return req_id % ZFCP_REQ_LIST_BUCKETS;
0030 }
0031 
0032 /**
0033  * zfcp_reqlist_alloc - Allocate and initialize reqlist
0034  *
0035  * Returns pointer to allocated reqlist on success, or NULL on
0036  * allocation failure.
0037  */
0038 static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void)
0039 {
0040     unsigned int i;
0041     struct zfcp_reqlist *rl;
0042 
0043     rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL);
0044     if (!rl)
0045         return NULL;
0046 
0047     spin_lock_init(&rl->lock);
0048 
0049     for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
0050         INIT_LIST_HEAD(&rl->buckets[i]);
0051 
0052     return rl;
0053 }
0054 
0055 /**
0056  * zfcp_reqlist_isempty - Check whether the request list empty
0057  * @rl: pointer to reqlist
0058  *
0059  * Returns: 1 if list is empty, 0 if not
0060  */
0061 static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl)
0062 {
0063     unsigned int i;
0064 
0065     for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
0066         if (!list_empty(&rl->buckets[i]))
0067             return 0;
0068     return 1;
0069 }
0070 
0071 /**
0072  * zfcp_reqlist_free - Free allocated memory for reqlist
0073  * @rl: The reqlist where to free memory
0074  */
0075 static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl)
0076 {
0077     /* sanity check */
0078     BUG_ON(!zfcp_reqlist_isempty(rl));
0079 
0080     kfree(rl);
0081 }
0082 
0083 static inline struct zfcp_fsf_req *
0084 _zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
0085 {
0086     struct zfcp_fsf_req *req;
0087     unsigned int i;
0088 
0089     i = zfcp_reqlist_hash(req_id);
0090     list_for_each_entry(req, &rl->buckets[i], list)
0091         if (req->req_id == req_id)
0092             return req;
0093     return NULL;
0094 }
0095 
0096 /**
0097  * zfcp_reqlist_find - Lookup FSF request by its request id
0098  * @rl: The reqlist where to lookup the FSF request
0099  * @req_id: The request id to look for
0100  *
0101  * Returns a pointer to the FSF request with the specified request id
0102  * or NULL if there is no known FSF request with this id.
0103  */
0104 static inline struct zfcp_fsf_req *
0105 zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
0106 {
0107     unsigned long flags;
0108     struct zfcp_fsf_req *req;
0109 
0110     spin_lock_irqsave(&rl->lock, flags);
0111     req = _zfcp_reqlist_find(rl, req_id);
0112     spin_unlock_irqrestore(&rl->lock, flags);
0113 
0114     return req;
0115 }
0116 
0117 /**
0118  * zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist
0119  * @rl: reqlist where to search and remove entry
0120  * @req_id: The request id of the request to look for
0121  *
0122  * This functions tries to find the FSF request with the specified
0123  * id and then removes it from the reqlist. The reqlist lock is held
0124  * during both steps of the operation.
0125  *
0126  * Returns: Pointer to the FSF request if the request has been found,
0127  * NULL if it has not been found.
0128  */
0129 static inline struct zfcp_fsf_req *
0130 zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, unsigned long req_id)
0131 {
0132     unsigned long flags;
0133     struct zfcp_fsf_req *req;
0134 
0135     spin_lock_irqsave(&rl->lock, flags);
0136     req = _zfcp_reqlist_find(rl, req_id);
0137     if (req)
0138         list_del(&req->list);
0139     spin_unlock_irqrestore(&rl->lock, flags);
0140 
0141     return req;
0142 }
0143 
0144 /**
0145  * zfcp_reqlist_add - Add entry to reqlist
0146  * @rl: reqlist where to add the entry
0147  * @req: The entry to add
0148  *
0149  * The request id always increases. As an optimization new requests
0150  * are added here with list_add_tail at the end of the bucket lists
0151  * while old requests are looked up starting at the beginning of the
0152  * lists.
0153  */
0154 static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl,
0155                     struct zfcp_fsf_req *req)
0156 {
0157     unsigned int i;
0158     unsigned long flags;
0159 
0160     i = zfcp_reqlist_hash(req->req_id);
0161 
0162     spin_lock_irqsave(&rl->lock, flags);
0163     list_add_tail(&req->list, &rl->buckets[i]);
0164     spin_unlock_irqrestore(&rl->lock, flags);
0165 }
0166 
0167 /**
0168  * zfcp_reqlist_move - Move all entries from reqlist to simple list
0169  * @rl: The zfcp_reqlist where to remove all entries
0170  * @list: The list where to move all entries
0171  */
0172 static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
0173                      struct list_head *list)
0174 {
0175     unsigned int i;
0176     unsigned long flags;
0177 
0178     spin_lock_irqsave(&rl->lock, flags);
0179     for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
0180         list_splice_init(&rl->buckets[i], list);
0181     spin_unlock_irqrestore(&rl->lock, flags);
0182 }
0183 
0184 /**
0185  * zfcp_reqlist_apply_for_all() - apply a function to every request.
0186  * @rl: the requestlist that contains the target requests.
0187  * @f: the function to apply to each request; the first parameter of the
0188  *     function will be the target-request; the second parameter is the same
0189  *     pointer as given with the argument @data.
0190  * @data: freely chosen argument; passed through to @f as second parameter.
0191  *
0192  * Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash-
0193  * table (not a 'safe' variant, so don't modify the list).
0194  *
0195  * Holds @rl->lock over the entire request-iteration.
0196  */
0197 static inline void
0198 zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl,
0199                void (*f)(struct zfcp_fsf_req *, void *), void *data)
0200 {
0201     struct zfcp_fsf_req *req;
0202     unsigned long flags;
0203     unsigned int i;
0204 
0205     spin_lock_irqsave(&rl->lock, flags);
0206     for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
0207         list_for_each_entry(req, &rl->buckets[i], list)
0208             f(req, data);
0209     spin_unlock_irqrestore(&rl->lock, flags);
0210 }
0211 
0212 #endif /* ZFCP_REQLIST_H */