Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22328d71 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Dave Chinner
Browse files

xfs: embedd mru_elem into parent structure



There is no need to do a separate allocation for each mru element, just
embedd the structure into the parent one in the user.  Besides saving
a memory allocation and the infrastructure required for it this also
simplifies the API.

While we do major surgery on xfs_mru_cache.c also de-typedef it and
make struct mru_cache private to the implementation file.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent ce695c65
Loading
Loading
Loading
Loading
+34 −33
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ static kmem_zone_t *item_zone;
 */
typedef struct fstrm_item
{
	struct xfs_mru_cache_elem mru;
	xfs_agnumber_t	ag;	/* AG currently in use for the file/directory. */
	xfs_inode_t	*ip;	/* inode self-pointer. */
	xfs_inode_t	*pip;	/* Parent directory inode pointer. */
@@ -335,10 +336,10 @@ _xfs_filestream_update_ag(
{
	int		err = 0;
	xfs_mount_t	*mp;
	xfs_mru_cache_t	*cache;
	fstrm_item_t	*item;
	xfs_agnumber_t	old_ag;
	xfs_inode_t	*old_pip;
	struct xfs_mru_cache_elem *mru;

	/*
	 * Either ip is a regular file and pip is a directory, or ip is a
@@ -349,16 +350,17 @@ _xfs_filestream_update_ag(
	              (S_ISDIR(ip->i_d.di_mode) && !pip)));

	mp = ip->i_mount;
	cache = mp->m_filestream;

	item = xfs_mru_cache_lookup(cache, ip->i_ino);
	if (item) {
	mru = xfs_mru_cache_lookup(mp->m_filestream, ip->i_ino);
	if (mru) {
		item = container_of(mru, fstrm_item_t, mru);

		ASSERT(item->ip == ip);
		old_ag = item->ag;
		item->ag = ag;
		old_pip = item->pip;
		item->pip = pip;
		xfs_mru_cache_done(cache);
		xfs_mru_cache_done(mp->m_filestream);

		/*
		 * If the AG has changed, drop the old ref and take a new one,
@@ -391,7 +393,7 @@ _xfs_filestream_update_ag(
	item->ip = ip;
	item->pip = pip;

	err = xfs_mru_cache_insert(cache, ip->i_ino, item);
	err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
	if (err) {
		kmem_zone_free(item_zone, item);
		return err;
@@ -422,14 +424,12 @@ _xfs_filestream_update_ag(
/* xfs_fstrm_free_func(): callback for freeing cached stream items. */
STATIC void
xfs_fstrm_free_func(
	unsigned long	ino,
	void		*data)
	struct xfs_mru_cache_elem *mru)
{
	fstrm_item_t	*item  = (fstrm_item_t *)data;
	fstrm_item_t	*item =
		container_of(mru, fstrm_item_t, mru);
	xfs_inode_t	*ip = item->ip;

	ASSERT(ip->i_ino == ino);

	xfs_iflags_clear(ip, XFS_IFILESTREAM);

	/* Drop the reference taken on the AG when the item was added. */
@@ -532,7 +532,8 @@ xfs_agnumber_t
xfs_filestream_lookup_ag(
	xfs_inode_t	*ip)
{
	xfs_mru_cache_t	*cache;
	struct xfs_mount *mp = ip->i_mount;
	struct xfs_mru_cache_elem *mru;
	fstrm_item_t	*item;
	xfs_agnumber_t	ag;
	int		ref;
@@ -542,17 +543,17 @@ xfs_filestream_lookup_ag(
		return NULLAGNUMBER;
	}

	cache = ip->i_mount->m_filestream;
	item = xfs_mru_cache_lookup(cache, ip->i_ino);
	if (!item) {
	mru = xfs_mru_cache_lookup(mp->m_filestream, ip->i_ino);
	if (!mru) {
		TRACE_LOOKUP(ip->i_mount, ip, NULL, NULLAGNUMBER, 0);
		return NULLAGNUMBER;
	}

	item = container_of(mru, fstrm_item_t, mru);
	ASSERT(ip == item->ip);
	ag = item->ag;
	ref = xfs_filestream_peek_ag(ip->i_mount, ag);
	xfs_mru_cache_done(cache);
	xfs_mru_cache_done(mp->m_filestream);

	TRACE_LOOKUP(ip->i_mount, ip, item->pip, ag, ref);
	return ag;
@@ -573,8 +574,8 @@ xfs_filestream_associate(
	xfs_inode_t	*pip,
	xfs_inode_t	*ip)
{
	struct xfs_mru_cache_elem *mru;
	xfs_mount_t	*mp;
	xfs_mru_cache_t	*cache;
	fstrm_item_t	*item;
	xfs_agnumber_t	ag, rotorstep, startag;
	int		err = 0;
@@ -585,7 +586,6 @@ xfs_filestream_associate(
		return -EINVAL;

	mp = pip->i_mount;
	cache = mp->m_filestream;

	/*
	 * We have a problem, Houston.
@@ -606,11 +606,13 @@ xfs_filestream_associate(
		return 1;

	/* If the parent directory is already in the cache, use its AG. */
	item = xfs_mru_cache_lookup(cache, pip->i_ino);
	if (item) {
	mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
	if (mru) {
		item = container_of(mru, fstrm_item_t, mru);

		ASSERT(item->ip == pip);
		ag = item->ag;
		xfs_mru_cache_done(cache);
		xfs_mru_cache_done(mp->m_filestream);

		TRACE_LOOKUP(mp, pip, pip, ag, xfs_filestream_peek_ag(mp, ag));
		err = _xfs_filestream_update_ag(ip, pip, ag);
@@ -671,17 +673,16 @@ xfs_filestream_new_ag(
	struct xfs_bmalloca	*ap,
	xfs_agnumber_t		*agp)
{
	struct xfs_mru_cache_elem *mru, *mru2;
	int		flags, err;
	xfs_inode_t	*ip, *pip = NULL;
	xfs_mount_t	*mp;
	xfs_mru_cache_t	*cache;
	xfs_extlen_t	minlen;
	fstrm_item_t	*dir, *file;
	xfs_agnumber_t	ag = NULLAGNUMBER;

	ip = ap->ip;
	mp = ip->i_mount;
	cache = mp->m_filestream;
	minlen = ap->length;
	*agp = NULLAGNUMBER;

@@ -689,8 +690,9 @@ xfs_filestream_new_ag(
	 * Look for the file in the cache, removing it if it's found.  Doing
	 * this allows it to be held across the dir lookup that follows.
	 */
	file = xfs_mru_cache_remove(cache, ip->i_ino);
	if (file) {
	mru = xfs_mru_cache_remove(mp->m_filestream, ip->i_ino);
	if (mru) {
		file = container_of(mru, fstrm_item_t, mru);
		ASSERT(ip == file->ip);

		/* Save the file's parent inode and old AG number for later. */
@@ -698,8 +700,9 @@ xfs_filestream_new_ag(
		ag = file->ag;

		/* Look for the file's directory in the cache. */
		dir = xfs_mru_cache_lookup(cache, pip->i_ino);
		if (dir) {
		mru2 = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
		if (mru2) {
			dir = container_of(mru2, fstrm_item_t, mru);
			ASSERT(pip == dir->ip);

			/*
@@ -714,7 +717,7 @@ xfs_filestream_new_ag(
				*agp = file->ag = dir->ag;
			}

			xfs_mru_cache_done(cache);
			xfs_mru_cache_done(mp->m_filestream);
		}

		/*
@@ -722,9 +725,9 @@ xfs_filestream_new_ag(
		 * function needs to be called to tidy up in the same way as if
		 * the item had simply expired from the cache.
		 */
		err = xfs_mru_cache_insert(cache, ip->i_ino, file);
		err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, mru);
		if (err) {
			xfs_fstrm_free_func(ip->i_ino, file);
			xfs_fstrm_free_func(mru);
			return err;
		}

@@ -818,7 +821,5 @@ void
xfs_filestream_deassociate(
	xfs_inode_t	*ip)
{
	xfs_mru_cache_t	*cache = ip->i_mount->m_filestream;

	xfs_mru_cache_delete(cache, ip->i_ino);
	xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
}
+61 −94
Original line number Diff line number Diff line
@@ -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,7 +135,7 @@ static struct workqueue_struct *xfs_mru_reap_wq;
 */
STATIC unsigned long
_xfs_mru_cache_migrate(
	xfs_mru_cache_t	*mru,
	struct xfs_mru_cache	*mru,
	unsigned long		now)
{
	unsigned int		grp;
@@ -193,8 +199,8 @@ _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;
@@ -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 0;

 out_destroy_mru_elem_zone:
	kmem_zone_destroy(xfs_mru_elem_zone);
 out:
		return -ENOMEM;
	return 0;
}

void
xfs_mru_cache_uninit(void)
{
	destroy_workqueue(xfs_mru_reap_wq);
	kmem_zone_destroy(xfs_mru_elem_zone);
}

/*
@@ -336,12 +324,12 @@ 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;
	struct xfs_mru_cache	*mru = NULL;
	int			err = 0, grp;
	unsigned int		grp_time;

@@ -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,45 +426,29 @@ xfs_mru_cache_destroy(
 */
int
xfs_mru_cache_insert(
	xfs_mru_cache_t	*mru,
	struct xfs_mru_cache	*mru,
	unsigned long		key,
	void		*value)
	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)) {
		error = ENOMEM;
		goto out_free_item;
	}

	INIT_LIST_HEAD(&elem->list_node);
	elem->key = key;
	elem->value = value;

	spin_lock(&mru->lock);

	error = -radix_tree_insert(&mru->store, key, elem);
	radix_tree_preload_end();
	if (error) {
		spin_unlock(&mru->lock);
		goto out_free_item;
	}
	if (!error)
		_xfs_mru_cache_list_insert(mru, elem);

	spin_unlock(&mru->lock);

	return 0;
out_free_item:
	kmem_zone_free(xfs_mru_elem_zone, elem);
	return error;
}

@@ -486,13 +458,12 @@ out_free_item:
 * 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,
	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)
@@ -500,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;
}

/*
@@ -519,13 +484,14 @@ xfs_mru_cache_remove(
 */
void
xfs_mru_cache_delete(
	xfs_mru_cache_t	*mru,
	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);
}

/*
@@ -548,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,
	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)
@@ -568,7 +534,7 @@ xfs_mru_cache_lookup(
	} else
		spin_unlock(&mru->lock);

	return elem ? elem->value : NULL;
	return elem;
}

/*
@@ -578,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);
}
+12 −19
Original line number Diff line number Diff line
@@ -18,24 +18,15 @@
#ifndef __XFS_MRU_CACHE_H__
#define __XFS_MRU_CACHE_H__

struct xfs_mru_cache;

/* Function pointer type for callback to free a client's data pointer. */
typedef void (*xfs_mru_cache_free_func_t)(unsigned long, void*);
struct xfs_mru_cache_elem {
	struct list_head list_node;
	unsigned long	key;
};

typedef 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 */
} xfs_mru_cache_t;
/* Function pointer type for callback to free a client's data pointer. */
typedef void (*xfs_mru_cache_free_func_t)(struct xfs_mru_cache_elem *elem);

int xfs_mru_cache_init(void);
void xfs_mru_cache_uninit(void);
@@ -44,10 +35,12 @@ int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
			     xfs_mru_cache_free_func_t free_func);
void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
				void *value);
void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
		struct xfs_mru_cache_elem *elem);
struct xfs_mru_cache_elem *
xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key);
void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
struct xfs_mru_cache_elem *
xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
void xfs_mru_cache_done(struct xfs_mru_cache *mru);

#endif /* __XFS_MRU_CACHE_H__ */