Re: [PATCH 2/9] nilfs2: add simple cache for modifications to SUFILE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 24 Feb 2015 20:01:37 +0100, Andreas Rohner wrote:
> This patch adds a simple, small cache that can be used to accumulate
> modifications to SUFILE entries. This is for example useful for
> keeping track of reclaimable blocks, because most of the
> modifications consist of small increments or decrements. By adding
> these up and temporarily storing them in a small cache, the
> performance can be improved. Additionally lock contention is
> reduced.
> 
> Signed-off-by: Andreas Rohner <andreas.rohner@xxxxxxx>
> ---
>  fs/nilfs2/sufile.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/nilfs2/sufile.h |  44 +++++++++++++
>  2 files changed, 222 insertions(+)
> 
> diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
> index 1e8cac6..a369c30 100644
> --- a/fs/nilfs2/sufile.c
> +++ b/fs/nilfs2/sufile.c
> @@ -1168,6 +1168,184 @@ out_sem:
>  }
>  
>  /**
> + * nilfs_sufile_mc_init - inits segusg modification cache
> + * @mc: modification cache
> + * @capacity: maximum capacity of the mod cache
> + *
> + * Description: Allocates memory for an array of nilfs_sufile_mod structures
> + * according to @capacity. This memory must be freed with
> + * nilfs_sufile_mc_destroy().
> + *
> + * Return Value: On success, 0 is returned. On error, one of the following
> + * negative error codes is returned.
> + *
> + * %-ENOMEM - Insufficient amount of memory available.
> + *
> + * %-EINVAL - Invalid capacity.
> + */
> +int nilfs_sufile_mc_init(struct nilfs_sufile_mod_cache *mc, size_t capacity)
> +{
> +	mc->mc_capacity = capacity;
> +	if (!capacity)
> +		return -EINVAL;
> +
> +	mc->mc_mods = kmalloc(capacity * sizeof(struct nilfs_sufile_mod),
> +			      GFP_KERNEL);

GFP_NOFS must be used instead of GFP_KERNEL to avoid initiating other
filesystem operations.

The abbreviation "mc" is not good, which is already used as the
abbreviation of "minimum clean" in userland.

> +	if (!mc->mc_mods)
> +		return -ENOMEM;
> +
> +	mc->mc_size = 0;
> +
> +	return 0;
> +}
> +
> +/**
> + * nilfs_sufile_mc_add - add signed value to segusg modification cache
> + * @mc: modification cache
> + * @segnum: segment number
> + * @value: signed value (can be positive and negative)
> + *
> + * Description: nilfs_sufile_mc_add() tries to add a pair of @segnum and
> + * @value to the modification cache. If the cache already contains a
> + * segment number equal to @segnum, then @value is simply added to the
> + * existing value. This way thousands of small modifications can be
> + * accumulated into one value. If @segnum cannot be found and the
> + * capacity allows it, a new element is added to the cache. If the
> + * capacity is reached an error value is returned.
> + *
> + * Return Value: On success, 0 is returned. On error, one of the following
> + * negative error codes is returned.
> + *
> + * %-ENOSPC - The mod cache has reached its capacity and must be flushed.
> + */
> +static inline int nilfs_sufile_mc_add(struct nilfs_sufile_mod_cache *mc,
> +				      __u64 segnum, __s64 value)
> +{
> +	struct nilfs_sufile_mod *mods = mc->mc_mods;
> +	int i;
> +
> +	for (i = 0; i < mc->mc_size; ++i, ++mods) {
> +		if (mods->m_segnum == segnum) {
> +			mods->m_value += value;
> +			return 0;
> +		}
> +	}
> +
> +	if (mc->mc_size < mc->mc_capacity) {
> +		mods->m_segnum = segnum;
> +		mods->m_value = value;
> +		mc->mc_size++;
> +		return 0;
> +	}
> +
> +	return -ENOSPC;
> +}
> +
> +/**
> + * nilfs_sufile_mc_clear - set mc_size to 0
> + * @mc: modification cache
> + *
> + * Description: nilfs_sufile_mc_clear() sets mc_size to 0, which enables
> + * nilfs_sufile_mc_add() to overwrite the elements in @mc.
> + */
> +static inline void nilfs_sufile_mc_clear(struct nilfs_sufile_mod_cache *mc)
> +{
> +	mc->mc_size = 0;
> +}
> +
> +/**
> + * nilfs_sufile_mc_reset - clear cache and add one element
> + * @mc: modification cache
> + * @segnum: segment number
> + * @value: signed value (can be positive and negative)
> + *
> + * Description: Clears the modification cache in @mc and adds a new pair of
> + * @segnum and @value to it at the same time.
> + */
> +static inline void nilfs_sufile_mc_reset(struct nilfs_sufile_mod_cache *mc,
> +					 __u64 segnum, __s64 value)
> +{
> +	struct nilfs_sufile_mod *mods = mc->mc_mods;
> +
> +	mods->m_segnum = segnum;
> +	mods->m_value = value;
> +	mc->mc_size = 1;
> +}

The name of this function is confusing.  Actual meaning of this
function is "reset" and "add", and that can be replaced with mc_clear
and mc_add.  Remove this function to simplify interface.

Regards,
Ryusuke Konishi

> +/**
> + * nilfs_sufile_mc_flush - flush modification cache
> + * @sufile: inode of segment usage file
> + * @mc: modification cache
> + * @dofunc: primitive operation for the update
> + *
> + * Description: nilfs_sufile_mc_flush() flushes the cached modifications
> + * and applies them to the segment usages on disk. It persists the cached
> + * changes, by calling @dofunc for every element in the cache. @dofunc also
> + * determines the interpretation of the cached values and how they should
> + * be applied to the corresponding segment usage entries.
> + *
> + * Return Value: On success, zero is returned.  On error, one of the
> + * following negative error codes is returned.
> + *
> + * %-EIO - I/O error.
> + *
> + * %-ENOMEM - Insufficient amount of memory available.
> + *
> + * %-ENOENT - Given segment usage is in hole block
> + *
> + * %-EINVAL - Invalid segment usage number
> + */
> +static inline int nilfs_sufile_mc_flush(struct inode *sufile,
> +					struct nilfs_sufile_mod_cache *mc,
> +					void (*dofunc)(struct inode *,
> +						struct nilfs_sufile_mod *,
> +						struct buffer_head *,
> +						struct buffer_head *))
> +{
> +	return nilfs_sufile_updatev(sufile, mc->mc_mods,
> +				    sizeof(struct nilfs_sufile_mod),
> +				    offsetof(struct nilfs_sufile_mod, m_segnum),
> +				    mc->mc_size, 0, NULL, (void *)dofunc);
> +}
> +
> +/**
> + * nilfs_sufile_mc_update - immediately applies modification
> + * @sufile: inode of segment usage file
> + * @segnum: segment number
> + * @value: signed value (can be positive and negative)
> + * @dofunc: primitive operation for the update
> + *
> + * Description: nilfs_sufile_mc_update() is a helper function, that
> + * creates a temporary nilfs_sufile_mod structure out of @segnum and @value
> + * and immediately flushes it using @dofunc, without the use of a
> + * modification cache.
> + *
> + * Return Value: On success, zero is returned.  On error, one of the
> + * following negative error codes is returned.
> + *
> + * %-EIO - I/O error.
> + *
> + * %-ENOMEM - Insufficient amount of memory available.
> + *
> + * %-ENOENT - Given segment usage is in hole block
> + *
> + * %-EINVAL - Invalid segment usage number
> + */
> +static inline int nilfs_sufile_mc_update(struct inode *sufile,
> +					 __u64 segnum, __s64 value,
> +					 void (*dofunc)(struct inode *,
> +						struct nilfs_sufile_mod *,
> +						struct buffer_head *,
> +						struct buffer_head *))
> +{
> +	struct nilfs_sufile_mod m = {.m_segnum = segnum, .m_value = value};
> +
> +	return nilfs_sufile_update(sufile, &m,
> +				   offsetof(struct nilfs_sufile_mod, m_segnum),
> +				   0, (void *)dofunc);
> +}
> +
> +/**
>   * nilfs_sufile_read - read or get sufile inode
>   * @sb: super block instance
>   * @susize: size of a segment usage entry
> diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h
> index 2df6c71..c446325 100644
> --- a/fs/nilfs2/sufile.h
> +++ b/fs/nilfs2/sufile.h
> @@ -146,4 +146,48 @@ static inline int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum)
>  				   (void *)nilfs_sufile_do_set_error);
>  }
>  
> +#define NILFS_SUFILE_MC_SIZE_DEFAULT	5
> +#define NILFS_SUFILE_MC_SIZE_EXT	10
> +
> +/**
> + * struct nilfs_sufile_mod - segment usage modification
> + * @m_segnum: segment number
> + * @m_value: signed value that gets added to respective segusg field
> + */
> +struct nilfs_sufile_mod {
> +	__u64 m_segnum;
> +	__s64 m_value;
> +};
> +
> +/**
> + * struct nilfs_sufile_mod_cache - segment usage modification cache
> + * @mc_mods: array of modifications to segments
> + * @mc_capacity: maximum number of elements that fit in @mc_mods
> + * @mc_size: number of elements currently filled with valid data
> + */
> +struct nilfs_sufile_mod_cache {
> +	struct nilfs_sufile_mod *mc_mods;
> +	size_t mc_capacity;
> +	size_t mc_size;
> +};
> +
> +int nilfs_sufile_mc_init(struct nilfs_sufile_mod_cache *, size_t);
> +
> +/**
> + * nilfs_sufile_mc_destroy - destroy segusg modification cache
> + * @mc: modification cache
> + *
> + * Description: Releases the memory allocated by nilfs_sufile_mc_init and
> + * sets the size and capacity to 0. @mc should not be used after a call to
> + * this function.
> + */
> +static inline void nilfs_sufile_mc_destroy(struct nilfs_sufile_mod_cache *mc)
> +{
> +	if (mc) {
> +		kfree(mc->mc_mods);
> +		mc->mc_capacity = 0;
> +		mc->mc_size = 0;
> +	}
> +}
> +
>  #endif	/* _NILFS_SUFILE_H */
> -- 
> 2.3.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux