diff options
Diffstat (limited to 'fs/xfs/xfs_mru_cache.c')
| -rw-r--r-- | fs/xfs/xfs_mru_cache.c | 151 | 
1 files changed, 63 insertions, 88 deletions
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index 4aff5639573..f99b4933dc2 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c @@ -100,14 +100,20 @@   * likely result in a loop in one of the lists.  That's a sure-fire recipe for   * an infinite loop in the code.   */ -typedef struct xfs_mru_cache_elem -{ -	struct list_head list_node; -	unsigned long	key; -	void		*value; -} xfs_mru_cache_elem_t; +struct xfs_mru_cache { +	struct radix_tree_root	store;     /* Core storage data structure.  */ +	struct list_head	*lists;    /* Array of lists, one per grp.  */ +	struct list_head	reap_list; /* Elements overdue for reaping. */ +	spinlock_t		lock;      /* Lock to protect this struct.  */ +	unsigned int		grp_count; /* Number of discrete groups.    */ +	unsigned int		grp_time;  /* Time period spanned by grps.  */ +	unsigned int		lru_grp;   /* Group containing time zero.   */ +	unsigned long		time_zero; /* Time first element was added. */ +	xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */ +	struct delayed_work	work;      /* Workqueue data for reaping.   */ +	unsigned int		queued;	   /* work has been queued */ +}; -static kmem_zone_t		*xfs_mru_elem_zone;  static struct workqueue_struct	*xfs_mru_reap_wq;  /* @@ -129,12 +135,12 @@ static struct workqueue_struct	*xfs_mru_reap_wq;   */  STATIC unsigned long  _xfs_mru_cache_migrate( -	xfs_mru_cache_t	*mru, -	unsigned long	now) +	struct xfs_mru_cache	*mru, +	unsigned long		now)  { -	unsigned int	grp; -	unsigned int	migrated = 0; -	struct list_head *lru_list; +	unsigned int		grp; +	unsigned int		migrated = 0; +	struct list_head	*lru_list;  	/* Nothing to do if the data store is empty. */  	if (!mru->time_zero) @@ -193,11 +199,11 @@ _xfs_mru_cache_migrate(   */  STATIC void  _xfs_mru_cache_list_insert( -	xfs_mru_cache_t		*mru, -	xfs_mru_cache_elem_t	*elem) +	struct xfs_mru_cache	*mru, +	struct xfs_mru_cache_elem *elem)  { -	unsigned int	grp = 0; -	unsigned long	now = jiffies; +	unsigned int		grp = 0; +	unsigned long		now = jiffies;  	/*  	 * If the data store is empty, initialise time zero, leave grp set to @@ -231,10 +237,10 @@ _xfs_mru_cache_list_insert(   */  STATIC void  _xfs_mru_cache_clear_reap_list( -	xfs_mru_cache_t		*mru) __releases(mru->lock) __acquires(mru->lock) - +	struct xfs_mru_cache	*mru) +		__releases(mru->lock) __acquires(mru->lock)  { -	xfs_mru_cache_elem_t	*elem, *next; +	struct xfs_mru_cache_elem *elem, *next;  	struct list_head	tmp;  	INIT_LIST_HEAD(&tmp); @@ -252,15 +258,8 @@ _xfs_mru_cache_clear_reap_list(  	spin_unlock(&mru->lock);  	list_for_each_entry_safe(elem, next, &tmp, list_node) { - -		/* Remove the element from the reap list. */  		list_del_init(&elem->list_node); - -		/* Call the client's free function with the key and value pointer. */ -		mru->free_func(elem->key, elem->value); - -		/* Free the element structure. */ -		kmem_zone_free(xfs_mru_elem_zone, elem); +		mru->free_func(elem);  	}  	spin_lock(&mru->lock); @@ -277,7 +276,8 @@ STATIC void  _xfs_mru_cache_reap(  	struct work_struct	*work)  { -	xfs_mru_cache_t		*mru = container_of(work, xfs_mru_cache_t, work.work); +	struct xfs_mru_cache	*mru = +		container_of(work, struct xfs_mru_cache, work.work);  	unsigned long		now, next;  	ASSERT(mru && mru->lists); @@ -304,28 +304,16 @@ _xfs_mru_cache_reap(  int  xfs_mru_cache_init(void)  { -	xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t), -	                                 "xfs_mru_cache_elem"); -	if (!xfs_mru_elem_zone) -		goto out; -  	xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);  	if (!xfs_mru_reap_wq) -		goto out_destroy_mru_elem_zone; - +		return -ENOMEM;  	return 0; - - out_destroy_mru_elem_zone: -	kmem_zone_destroy(xfs_mru_elem_zone); - out: -	return -ENOMEM;  }  void  xfs_mru_cache_uninit(void)  {  	destroy_workqueue(xfs_mru_reap_wq); -	kmem_zone_destroy(xfs_mru_elem_zone);  }  /* @@ -336,14 +324,14 @@ xfs_mru_cache_uninit(void)   */  int  xfs_mru_cache_create( -	xfs_mru_cache_t		**mrup, +	struct xfs_mru_cache	**mrup,  	unsigned int		lifetime_ms,  	unsigned int		grp_count,  	xfs_mru_cache_free_func_t free_func)  { -	xfs_mru_cache_t	*mru = NULL; -	int		err = 0, grp; -	unsigned int	grp_time; +	struct xfs_mru_cache	*mru = NULL; +	int			err = 0, grp; +	unsigned int		grp_time;  	if (mrup)  		*mrup = NULL; @@ -400,7 +388,7 @@ exit:   */  static void  xfs_mru_cache_flush( -	xfs_mru_cache_t		*mru) +	struct xfs_mru_cache	*mru)  {  	if (!mru || !mru->lists)  		return; @@ -420,7 +408,7 @@ xfs_mru_cache_flush(  void  xfs_mru_cache_destroy( -	xfs_mru_cache_t		*mru) +	struct xfs_mru_cache	*mru)  {  	if (!mru || !mru->lists)  		return; @@ -438,38 +426,30 @@ xfs_mru_cache_destroy(   */  int  xfs_mru_cache_insert( -	xfs_mru_cache_t	*mru, -	unsigned long	key, -	void		*value) +	struct xfs_mru_cache	*mru, +	unsigned long		key, +	struct xfs_mru_cache_elem *elem)  { -	xfs_mru_cache_elem_t *elem; +	int			error;  	ASSERT(mru && mru->lists);  	if (!mru || !mru->lists)  		return EINVAL; -	elem = kmem_zone_zalloc(xfs_mru_elem_zone, KM_SLEEP); -	if (!elem) +	if (radix_tree_preload(GFP_KERNEL))  		return ENOMEM; -	if (radix_tree_preload(GFP_KERNEL)) { -		kmem_zone_free(xfs_mru_elem_zone, elem); -		return ENOMEM; -	} -  	INIT_LIST_HEAD(&elem->list_node);  	elem->key = key; -	elem->value = value;  	spin_lock(&mru->lock); - -	radix_tree_insert(&mru->store, key, elem); +	error = -radix_tree_insert(&mru->store, key, elem);  	radix_tree_preload_end(); -	_xfs_mru_cache_list_insert(mru, elem); - +	if (!error) +		_xfs_mru_cache_list_insert(mru, elem);  	spin_unlock(&mru->lock); -	return 0; +	return error;  }  /* @@ -478,13 +458,12 @@ xfs_mru_cache_insert(   * the client data pointer for the removed element is returned, otherwise this   * function will return a NULL pointer.   */ -void * +struct xfs_mru_cache_elem *  xfs_mru_cache_remove( -	xfs_mru_cache_t	*mru, -	unsigned long	key) +	struct xfs_mru_cache	*mru, +	unsigned long		key)  { -	xfs_mru_cache_elem_t *elem; -	void		*value = NULL; +	struct xfs_mru_cache_elem *elem;  	ASSERT(mru && mru->lists);  	if (!mru || !mru->lists) @@ -492,17 +471,11 @@ xfs_mru_cache_remove(  	spin_lock(&mru->lock);  	elem = radix_tree_delete(&mru->store, key); -	if (elem) { -		value = elem->value; +	if (elem)  		list_del(&elem->list_node); -	} -  	spin_unlock(&mru->lock); -	if (elem) -		kmem_zone_free(xfs_mru_elem_zone, elem); - -	return value; +	return elem;  }  /* @@ -511,13 +484,14 @@ xfs_mru_cache_remove(   */  void  xfs_mru_cache_delete( -	xfs_mru_cache_t	*mru, -	unsigned long	key) +	struct xfs_mru_cache	*mru, +	unsigned long		key)  { -	void		*value = xfs_mru_cache_remove(mru, key); +	struct xfs_mru_cache_elem *elem; -	if (value) -		mru->free_func(key, value); +	elem = xfs_mru_cache_remove(mru, key); +	if (elem) +		mru->free_func(elem);  }  /* @@ -540,12 +514,12 @@ xfs_mru_cache_delete(   * status, we need to help it get it right by annotating the path that does   * not release the lock.   */ -void * +struct xfs_mru_cache_elem *  xfs_mru_cache_lookup( -	xfs_mru_cache_t	*mru, -	unsigned long	key) +	struct xfs_mru_cache	*mru, +	unsigned long		key)  { -	xfs_mru_cache_elem_t *elem; +	struct xfs_mru_cache_elem *elem;  	ASSERT(mru && mru->lists);  	if (!mru || !mru->lists) @@ -560,7 +534,7 @@ xfs_mru_cache_lookup(  	} else  		spin_unlock(&mru->lock); -	return elem ? elem->value : NULL; +	return elem;  }  /* @@ -570,7 +544,8 @@ xfs_mru_cache_lookup(   */  void  xfs_mru_cache_done( -	xfs_mru_cache_t	*mru) __releases(mru->lock) +	struct xfs_mru_cache	*mru) +		__releases(mru->lock)  {  	spin_unlock(&mru->lock);  }  | 
