/* * zfcp device driver * * Data structure and helper functions for tracking pending FSF * requests. * * Copyright IBM Corporation 2009 */ #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); } #endif /* ZFCP_REQLIST_H */