[PATCH v2 for-4.19 1/2] xarray: Replace exceptional entries

Gao Xiang gaoxiang25 at huawei.com
Tue Feb 26 23:43:43 AEDT 2019


Hi Matthew,

On 2019/2/26 13:14, Gao Xiang wrote:
> From: Matthew Wilcox <willy at infradead.org>
> 
> commit 3159f943aafdbacb2f94c38fdaadabf2bbde2a14 upstream.
> 
> Introduce xarray value entries and tagged pointers to replace radix
> tree exceptional entries.  This is a slight change in encoding to allow
> the use of an extra bit (we can now store BITS_PER_LONG - 1 bits in a
> value entry).  It is also a change in emphasis; exceptional entries are
> intimidating and different.  As the comment explains, you can choose
> to store values or pointers in the xarray and they are both first-class
> citizens.
> 
> Signed-off-by: Matthew Wilcox <willy at infradead.org>
> Reviewed-by: Josef Bacik <jbacik at fb.com>
> [ take the minimum subset of tagged pointer support only. ]
> Cc: Matthew Wilcox <willy at infradead.org>
> Signed-off-by: Gao Xiang <gaoxiang25 at huawei.com>
> ---
> change log v2:
>  - fix tagged pointer apis to make it work properly pointed out by Matthew;

Is this version ok? Could you kindly give an "Acked-by" tag for this patch?

The following patch is important for erofs, I'd like to backport it ASAP...
 staging: erofs: fix race when the managed cache is enabled

It will be of great help. Thanks in advance!

Thanks,
Gao Xiang

> 
>  drivers/staging/erofs/utils.c | 18 +++++----------
>  include/linux/xarray.h        | 52 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 58 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c
> index 595cf90af9bb..bdee9bd09f11 100644
> --- a/drivers/staging/erofs/utils.c
> +++ b/drivers/staging/erofs/utils.c
> @@ -35,7 +35,6 @@ static atomic_long_t erofs_global_shrink_cnt;
>  
>  #ifdef CONFIG_EROFS_FS_ZIP
>  
> -/* radix_tree and the future XArray both don't use tagptr_t yet */
>  struct erofs_workgroup *erofs_find_workgroup(
>  	struct super_block *sb, pgoff_t index, bool *tag)
>  {
> @@ -47,9 +46,8 @@ struct erofs_workgroup *erofs_find_workgroup(
>  	rcu_read_lock();
>  	grp = radix_tree_lookup(&sbi->workstn_tree, index);
>  	if (grp != NULL) {
> -		*tag = radix_tree_exceptional_entry(grp);
> -		grp = (void *)((unsigned long)grp &
> -			~RADIX_TREE_EXCEPTIONAL_ENTRY);
> +		*tag = xa_pointer_tag(grp);
> +		grp = xa_untag_pointer(grp);
>  
>  		if (erofs_workgroup_get(grp, &oldcount)) {
>  			/* prefer to relax rcu read side */
> @@ -83,9 +81,7 @@ int erofs_register_workgroup(struct super_block *sb,
>  	sbi = EROFS_SB(sb);
>  	erofs_workstn_lock(sbi);
>  
> -	if (tag)
> -		grp = (void *)((unsigned long)grp |
> -			1UL << RADIX_TREE_EXCEPTIONAL_SHIFT);
> +	grp = xa_tag_pointer(grp, tag);
>  
>  	err = radix_tree_insert(&sbi->workstn_tree,
>  		grp->index, grp);
> @@ -131,9 +127,7 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
>  
>  	for (i = 0; i < found; ++i) {
>  		int cnt;
> -		struct erofs_workgroup *grp = (void *)
> -			((unsigned long)batch[i] &
> -				~RADIX_TREE_EXCEPTIONAL_ENTRY);
> +		struct erofs_workgroup *grp = xa_untag_pointer(batch[i]);
>  
>  		first_index = grp->index + 1;
>  
> @@ -150,8 +144,8 @@ unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
>  #endif
>  			continue;
>  
> -		if (radix_tree_delete(&sbi->workstn_tree,
> -			grp->index) != grp) {
> +		if (xa_untag_pointer(radix_tree_delete(&sbi->workstn_tree,
> +			grp->index)) != grp) {
>  #ifdef EROFS_FS_HAS_MANAGED_CACHE
>  skip:
>  			erofs_workgroup_unfreeze(grp, 1);
> diff --git a/include/linux/xarray.h b/include/linux/xarray.h
> index 2dfc8006fe64..51ae9779d08b 100644
> --- a/include/linux/xarray.h
> +++ b/include/linux/xarray.h
> @@ -9,6 +9,58 @@
>  
>  #include <linux/spinlock.h>
>  
> +/**
> + * xa_tag_pointer() - Create an XArray entry for a tagged pointer.
> + * @p: Plain pointer.
> + * @tag: Tag value (0 or 1).
> + *
> + * If the user of the XArray prefers, they can tag their pointers instead
> + * of storing value entries.  Two tags are available (0 and 1).
> + * These are distinct from the xa_mark_t as they are not replicated up
> + * through the array and cannot be searched for.
> + *
> + * Context: Any context.
> + * Return: An XArray entry.
> + */
> +static inline void *xa_tag_pointer(void *p, unsigned long tag)
> +{
> +	if (__builtin_constant_p(tag))
> +		BUILD_BUG_ON(tag > 1);
> +	else
> +		BUG_ON(tag > 1);
> +	return (void *)((unsigned long)p | (tag << 1));
> +}
> +
> +/**
> + * xa_untag_pointer() - Turn an XArray entry into a plain pointer.
> + * @entry: XArray entry.
> + *
> + * If you have stored a tagged pointer in the XArray, call this function
> + * to get the untagged version of the pointer.
> + *
> + * Context: Any context.
> + * Return: A pointer.
> + */
> +static inline void *xa_untag_pointer(void *entry)
> +{
> +	return (void *)((unsigned long)entry & ~3UL);
> +}
> +
> +/**
> + * xa_pointer_tag() - Get the tag stored in an XArray entry.
> + * @entry: XArray entry.
> + *
> + * If you have stored a tagged pointer in the XArray, call this function
> + * to get the tag of that pointer.
> + *
> + * Context: Any context.
> + * Return: A tag.
> + */
> +static inline unsigned int xa_pointer_tag(void *entry)
> +{
> +	return ((unsigned long)entry & 3UL) >> 1;
> +}
> +
>  #define xa_trylock(xa)		spin_trylock(&(xa)->xa_lock)
>  #define xa_lock(xa)		spin_lock(&(xa)->xa_lock)
>  #define xa_unlock(xa)		spin_unlock(&(xa)->xa_lock)
> 


More information about the Linux-erofs mailing list