212 lines
5.4 KiB
C
212 lines
5.4 KiB
C
|
/*
|
||
|
* zfcp device driver
|
||
|
*
|
||
|
* Data structure and helper functions for tracking pending FSF
|
||
|
* requests.
|
||
|
*
|
||
|
* Copyright IBM Corp. 2009, 2016
|
||
|
*/
|
||
|
|
||
|
#ifndef ZFCP_REQLIST_H
|
||
|
#define ZFCP_REQLIST_H
|
||
|
|
||
|
/* number of hash buckets */
|
||
|
#define ZFCP_REQ_LIST_BUCKETS 128
|
||
|
|
||
|
/**
|
||
|
* struct zfcp_reqlist - Container for request list (reqlist)
|
||
|
* @lock: Spinlock for protecting the hash list
|
||
|
* @list: Array of hashbuckets, each is a list of requests in this bucket
|
||
|
*/
|
||
|
struct zfcp_reqlist {
|
||
|
spinlock_t lock;
|
||
|
struct list_head buckets[ZFCP_REQ_LIST_BUCKETS];
|
||
|
};
|
||
|
|
||
|
static inline int zfcp_reqlist_hash(unsigned long req_id)
|
||
|
{
|
||
|
return req_id % ZFCP_REQ_LIST_BUCKETS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_alloc - Allocate and initialize reqlist
|
||
|
*
|
||
|
* Returns pointer to allocated reqlist on success, or NULL on
|
||
|
* allocation failure.
|
||
|
*/
|
||
|
static inline struct zfcp_reqlist *zfcp_reqlist_alloc(void)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
struct zfcp_reqlist *rl;
|
||
|
|
||
|
rl = kzalloc(sizeof(struct zfcp_reqlist), GFP_KERNEL);
|
||
|
if (!rl)
|
||
|
return NULL;
|
||
|
|
||
|
spin_lock_init(&rl->lock);
|
||
|
|
||
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
||
|
INIT_LIST_HEAD(&rl->buckets[i]);
|
||
|
|
||
|
return rl;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_isempty - Check whether the request list empty
|
||
|
* @rl: pointer to reqlist
|
||
|
*
|
||
|
* Returns: 1 if list is empty, 0 if not
|
||
|
*/
|
||
|
static inline int zfcp_reqlist_isempty(struct zfcp_reqlist *rl)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
|
||
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
||
|
if (!list_empty(&rl->buckets[i]))
|
||
|
return 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_free - Free allocated memory for reqlist
|
||
|
* @rl: The reqlist where to free memory
|
||
|
*/
|
||
|
static inline void zfcp_reqlist_free(struct zfcp_reqlist *rl)
|
||
|
{
|
||
|
/* sanity check */
|
||
|
BUG_ON(!zfcp_reqlist_isempty(rl));
|
||
|
|
||
|
kfree(rl);
|
||
|
}
|
||
|
|
||
|
static inline struct zfcp_fsf_req *
|
||
|
_zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
|
||
|
{
|
||
|
struct zfcp_fsf_req *req;
|
||
|
unsigned int i;
|
||
|
|
||
|
i = zfcp_reqlist_hash(req_id);
|
||
|
list_for_each_entry(req, &rl->buckets[i], list)
|
||
|
if (req->req_id == req_id)
|
||
|
return req;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_find - Lookup FSF request by its request id
|
||
|
* @rl: The reqlist where to lookup the FSF request
|
||
|
* @req_id: The request id to look for
|
||
|
*
|
||
|
* Returns a pointer to the FSF request with the specified request id
|
||
|
* or NULL if there is no known FSF request with this id.
|
||
|
*/
|
||
|
static inline struct zfcp_fsf_req *
|
||
|
zfcp_reqlist_find(struct zfcp_reqlist *rl, unsigned long req_id)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
struct zfcp_fsf_req *req;
|
||
|
|
||
|
spin_lock_irqsave(&rl->lock, flags);
|
||
|
req = _zfcp_reqlist_find(rl, req_id);
|
||
|
spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
|
||
|
return req;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_find_rm - Lookup request by id and remove it from reqlist
|
||
|
* @rl: reqlist where to search and remove entry
|
||
|
* @req_id: The request id of the request to look for
|
||
|
*
|
||
|
* This functions tries to find the FSF request with the specified
|
||
|
* id and then removes it from the reqlist. The reqlist lock is held
|
||
|
* during both steps of the operation.
|
||
|
*
|
||
|
* Returns: Pointer to the FSF request if the request has been found,
|
||
|
* NULL if it has not been found.
|
||
|
*/
|
||
|
static inline struct zfcp_fsf_req *
|
||
|
zfcp_reqlist_find_rm(struct zfcp_reqlist *rl, unsigned long req_id)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
struct zfcp_fsf_req *req;
|
||
|
|
||
|
spin_lock_irqsave(&rl->lock, flags);
|
||
|
req = _zfcp_reqlist_find(rl, req_id);
|
||
|
if (req)
|
||
|
list_del(&req->list);
|
||
|
spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
|
||
|
return req;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_add - Add entry to reqlist
|
||
|
* @rl: reqlist where to add the entry
|
||
|
* @req: The entry to add
|
||
|
*
|
||
|
* The request id always increases. As an optimization new requests
|
||
|
* are added here with list_add_tail at the end of the bucket lists
|
||
|
* while old requests are looked up starting at the beginning of the
|
||
|
* lists.
|
||
|
*/
|
||
|
static inline void zfcp_reqlist_add(struct zfcp_reqlist *rl,
|
||
|
struct zfcp_fsf_req *req)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
unsigned long flags;
|
||
|
|
||
|
i = zfcp_reqlist_hash(req->req_id);
|
||
|
|
||
|
spin_lock_irqsave(&rl->lock, flags);
|
||
|
list_add_tail(&req->list, &rl->buckets[i]);
|
||
|
spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_move - Move all entries from reqlist to simple list
|
||
|
* @rl: The zfcp_reqlist where to remove all entries
|
||
|
* @list: The list where to move all entries
|
||
|
*/
|
||
|
static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
|
||
|
struct list_head *list)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
unsigned long flags;
|
||
|
|
||
|
spin_lock_irqsave(&rl->lock, flags);
|
||
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
||
|
list_splice_init(&rl->buckets[i], list);
|
||
|
spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* zfcp_reqlist_apply_for_all() - apply a function to every request.
|
||
|
* @rl: the requestlist that contains the target requests.
|
||
|
* @f: the function to apply to each request; the first parameter of the
|
||
|
* function will be the target-request; the second parameter is the same
|
||
|
* pointer as given with the argument @data.
|
||
|
* @data: freely chosen argument; passed through to @f as second parameter.
|
||
|
*
|
||
|
* Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash-
|
||
|
* table (not a 'safe' variant, so don't modify the list).
|
||
|
*
|
||
|
* Holds @rl->lock over the entire request-iteration.
|
||
|
*/
|
||
|
static inline void
|
||
|
zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl,
|
||
|
void (*f)(struct zfcp_fsf_req *, void *), void *data)
|
||
|
{
|
||
|
struct zfcp_fsf_req *req;
|
||
|
unsigned long flags;
|
||
|
unsigned int i;
|
||
|
|
||
|
spin_lock_irqsave(&rl->lock, flags);
|
||
|
for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
||
|
list_for_each_entry(req, &rl->buckets[i], list)
|
||
|
f(req, data);
|
||
|
spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
}
|
||
|
|
||
|
#endif /* ZFCP_REQLIST_H */
|