On Tue, 24 Feb 2015 20:01:36 +0100, Andreas Rohner wrote:
> This patch refactors nilfs_sufile_updatev() to take an array of
> arbitrary data structures instead of an array of segment numbers as
> input parameter. With this  change it is reusable for cases, where
> it is necessary to pass extra data to the update function. The only
> requirement for the data structures passed as input is, that they
> contain the segment number within the structure. By passing the
> offset to the segment number as another input parameter,
> nilfs_sufile_updatev() can be oblivious to the actual type of the
> input structures in the array.
> 
> Signed-off-by: Andreas Rohner <andreas.roh...@gmx.net>
> ---
>  fs/nilfs2/sufile.c | 79 
> ++++++++++++++++++++++++++++++++----------------------
>  fs/nilfs2/sufile.h | 39 ++++++++++++++-------------
>  2 files changed, 68 insertions(+), 50 deletions(-)
> 
> diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
> index 2a869c3..1e8cac6 100644
> --- a/fs/nilfs2/sufile.c
> +++ b/fs/nilfs2/sufile.c
> @@ -138,14 +138,18 @@ unsigned long nilfs_sufile_get_ncleansegs(struct inode 
> *sufile)
>  /**
>   * nilfs_sufile_updatev - modify multiple segment usages at a time
>   * @sufile: inode of segment usage file
> - * @segnumv: array of segment numbers
> - * @nsegs: size of @segnumv array
> + * @datav: array of segment numbers
> + * @datasz: size of elements in @datav
> + * @segoff: offset to segnum within the elements of @datav
> + * @ndata: size of @datav array
>   * @create: creation flag
>   * @ndone: place to store number of modified segments on @segnumv
>   * @dofunc: primitive operation for the update
>   *
>   * Description: nilfs_sufile_updatev() repeatedly calls @dofunc
> - * against the given array of segments.  The @dofunc is called with
> + * against the given array of data elements. Every data element has
> + * to contain a valid segment number and @segoff should be the offset
> + * to that within the data structure. The @dofunc is called with
>   * buffers of a header block and the sufile block in which the target
>   * segment usage entry is contained.  If @ndone is given, the number
>   * of successfully modified segments from the head is stored in the
> @@ -163,50 +167,55 @@ unsigned long nilfs_sufile_get_ncleansegs(struct inode 
> *sufile)
>   *
>   * %-EINVAL - Invalid segment usage number
>   */
> -int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
> -                      int create, size_t *ndone,
> -                      void (*dofunc)(struct inode *, __u64,
> +int nilfs_sufile_updatev(struct inode *sufile, void *datav, size_t datasz,
> +                      size_t segoff, size_t ndata, int create,
> +                      size_t *ndone,
> +                      void (*dofunc)(struct inode *, void *,
>                                       struct buffer_head *,
>                                       struct buffer_head *))

Using offset byte of the data like segoff is nasty.

Please consider defining a template structure and its variation:

struct nilfs_sufile_update_data {
       __u64 segnum;
       /* Optional data comes after segnum */
};

/**
 * struct nilfs_sufile_update_count - data type of nilfs_sufile_do_xxx
 * @segnum: segment number
 * @nadd: additional value to a counter
 * Description: This structure derives from nilfs_sufile_update_data
 * struct.
 */
struct nilfs_sufile_update_count {
       __u64 segnum;
       __u64 nadd;
};

int nilfs_sufile_updatev(struct inode *sufile,
                         struct nilfs_sufile_update_data *datav,
                         size_t datasz,
                         size_t ndata, int create, size_t *ndone,
                         void (*dofunc)(struct inode *,
                                        struct nilfs_sufile_update_data *,
                                        struct buffer_head *,
                                        struct buffer_head *))
{
        ...
}

If you need define segnum in the middle of structure, you can use
container_of():

Example:

struct nilfs_sufile_update_xxx {
       __u32 item_a;
       __u32 item_b;
       struct nilfs_sufile_update_data u_data;
};

static inline struct nilfs_sufile_update_xxx *
NILFS_SU_UPDATE_XXX(struct nilfs_sufile_update_data *data)
{
        return container_of(data, struct nilfs_sufile_update_xxx, u_data);
}

void nilfs_sufile_do_xxx(...)
{
   struct nilfs_sufile_update_xxx *xxx;

   xxx = NILFS_SU_UPDATA_XXX(data);
   ...
}

I believe the former technique is enough in your case. (you can
suppose that segnum is always the first member of data, right ?).


>  {
>       struct buffer_head *header_bh, *bh;
>       unsigned long blkoff, prev_blkoff;
>       __u64 *seg;
> -     size_t nerr = 0, n = 0;
> +     void *data, *dataend = datav + ndata * datasz;
> +     size_t n = 0;
>       int ret = 0;
>  
> -     if (unlikely(nsegs == 0))
> +     if (unlikely(ndata == 0))
>               goto out;
>  
> -     down_write(&NILFS_MDT(sufile)->mi_sem);
> -     for (seg = segnumv; seg < segnumv + nsegs; seg++) {
> +
> +     for (data = datav; data < dataend; data += datasz) {
> +             seg = data + segoff;
>               if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
>                       printk(KERN_WARNING
>                              "%s: invalid segment number: %llu\n", __func__,
>                              (unsigned long long)*seg);
> -                     nerr++;
> +                     ret = -EINVAL;
> +                     goto out;
>               }
>       }
> -     if (nerr > 0) {
> -             ret = -EINVAL;
> -             goto out_sem;
> -     }
>  
> +     down_write(&NILFS_MDT(sufile)->mi_sem);
>       ret = nilfs_sufile_get_header_block(sufile, &header_bh);
>       if (ret < 0)
>               goto out_sem;
>  
> -     seg = segnumv;
> +     data = datav;
> +     seg = data + segoff;
>       blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
>       ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
>       if (ret < 0)
>               goto out_header;
>  
>       for (;;) {
> -             dofunc(sufile, *seg, header_bh, bh);
> +             dofunc(sufile, data, header_bh, bh);
>  
> -             if (++seg >= segnumv + nsegs)
> +             ++n;
> +             data += datasz;
> +             if (data >= dataend)
>                       break;
> +             seg = data + segoff;
>               prev_blkoff = blkoff;
>               blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
>               if (blkoff == prev_blkoff)
> @@ -220,28 +229,30 @@ int nilfs_sufile_updatev(struct inode *sufile, __u64 
> *segnumv, size_t nsegs,
>       }
>       brelse(bh);
>  
> - out_header:
> -     n = seg - segnumv;
> +out_header:
>       brelse(header_bh);
> - out_sem:
> +out_sem:
>       up_write(&NILFS_MDT(sufile)->mi_sem);
> - out:
> +out:
>       if (ndone)
>               *ndone = n;
>       return ret;
>  }
>  
> -int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
> -                     void (*dofunc)(struct inode *, __u64,
> +int nilfs_sufile_update(struct inode *sufile, void *data, size_t segoff,
> +                     int create,
> +                     void (*dofunc)(struct inode *, void *,
>                                      struct buffer_head *,
>                                      struct buffer_head *))

ditto.

>  {
>       struct buffer_head *header_bh, *bh;
> +     __u64 *seg;
>       int ret;
>  
> -     if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
> +     seg = data + segoff;
> +     if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
>               printk(KERN_WARNING "%s: invalid segment number: %llu\n",
> -                    __func__, (unsigned long long)segnum);
> +                    __func__, (unsigned long long)*seg);
>               return -EINVAL;
>       }

You can remove these nasty changes.

>       down_write(&NILFS_MDT(sufile)->mi_sem);
> @@ -250,9 +261,9 @@ int nilfs_sufile_update(struct inode *sufile, __u64 
> segnum, int create,
>       if (ret < 0)
>               goto out_sem;
>  
> -     ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, create, &bh);
> +     ret = nilfs_sufile_get_segment_usage_block(sufile, *seg, create, &bh);

ditto.

>       if (!ret) {
> -             dofunc(sufile, segnum, header_bh, bh);
> +             dofunc(sufile, data, header_bh, bh);
>               brelse(bh);
>       }
>       brelse(header_bh);
> @@ -406,12 +417,13 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 
> *segnump)
>       return ret;
>  }
>  
> -void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
> +void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 *data,
>                                struct buffer_head *header_bh,
>                                struct buffer_head *su_bh)
>  {
>       struct nilfs_segment_usage *su;
>       void *kaddr;
> +     __u64 segnum = *data;
>  
>       kaddr = kmap_atomic(su_bh->b_page);
>       su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
> @@ -431,13 +443,14 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, 
> __u64 segnum,
>       nilfs_mdt_mark_dirty(sufile);
>  }
>  
> -void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
> +void nilfs_sufile_do_scrap(struct inode *sufile, __u64 *data,
>                          struct buffer_head *header_bh,
>                          struct buffer_head *su_bh)
>  {
>       struct nilfs_segment_usage *su;
>       void *kaddr;
>       int clean, dirty;
> +     __u64 segnum = *data;

This can be converted to as follows:

        __u64 segnum = data->segnum;

>  
>       kaddr = kmap_atomic(su_bh->b_page);
>       su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
> @@ -462,13 +475,14 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 
> segnum,
>       nilfs_mdt_mark_dirty(sufile);
>  }
>  
> -void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
> +void nilfs_sufile_do_free(struct inode *sufile, __u64 *data,
>                         struct buffer_head *header_bh,
>                         struct buffer_head *su_bh)
>  {
>       struct nilfs_segment_usage *su;
>       void *kaddr;
>       int sudirty;
> +     __u64 segnum = *data;
>  
>       kaddr = kmap_atomic(su_bh->b_page);
>       su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
> @@ -596,13 +610,14 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct 
> nilfs_sustat *sustat)
>       return ret;
>  }
>  
> -void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum,
> +void nilfs_sufile_do_set_error(struct inode *sufile, __u64 *data,
>                              struct buffer_head *header_bh,
>                              struct buffer_head *su_bh)
>  {
>       struct nilfs_segment_usage *su;
>       void *kaddr;
>       int suclean;
> +     __u64 segnum = *data;
>  
>       kaddr = kmap_atomic(su_bh->b_page);
>       su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
> diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h
> index b8afd72..2df6c71 100644
> --- a/fs/nilfs2/sufile.h
> +++ b/fs/nilfs2/sufile.h
> @@ -46,21 +46,21 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, 
> void *, unsigned,
>                               size_t);
>  ssize_t nilfs_sufile_set_suinfo(struct inode *, void *, unsigned , size_t);
>  
> -int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
> -                      void (*dofunc)(struct inode *, __u64,
> -                                     struct buffer_head *,
> -                                     struct buffer_head *));
> -int nilfs_sufile_update(struct inode *, __u64, int,
> -                     void (*dofunc)(struct inode *, __u64,
> +int nilfs_sufile_updatev(struct inode *, void *, size_t, size_t, size_t, int,
> +                      size_t *, void (*dofunc)(struct inode *, void *,
> +                                               struct buffer_head *,
> +                                               struct buffer_head *));
> +int nilfs_sufile_update(struct inode *, void *, size_t, int,
> +                     void (*dofunc)(struct inode *, void *,
>                                      struct buffer_head *,
>                                      struct buffer_head *));

> -void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *,
> +void nilfs_sufile_do_scrap(struct inode *, __u64 *, struct buffer_head *,
>                          struct buffer_head *);
> -void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *,
> +void nilfs_sufile_do_free(struct inode *, __u64 *, struct buffer_head *,
>                         struct buffer_head *);
> -void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *,
> +void nilfs_sufile_do_cancel_free(struct inode *, __u64 *, struct buffer_head 
> *,
>                                struct buffer_head *);
> -void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *,
> +void nilfs_sufile_do_set_error(struct inode *, __u64 *, struct buffer_head *,
>                              struct buffer_head *);

Please, use "struct nilfs_sufile_update_data *" type for the second
argument of these declaration.

>  
>  int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs);
> @@ -75,7 +75,8 @@ int nilfs_sufile_trim_fs(struct inode *sufile, struct 
> fstrim_range *range);
>   */
>  static inline int nilfs_sufile_scrap(struct inode *sufile, __u64 segnum)
>  {
> -     return nilfs_sufile_update(sufile, segnum, 1, nilfs_sufile_do_scrap);
> +     return nilfs_sufile_update(sufile, &segnum, 0, 1,
> +                                (void *)nilfs_sufile_do_scrap);
>  }

Then you can avoid this nasty (void *) cast to the callback function.

>  
>  /**
> @@ -85,7 +86,8 @@ static inline int nilfs_sufile_scrap(struct inode *sufile, 
> __u64 segnum)
>   */
>  static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum)
>  {
> -     return nilfs_sufile_update(sufile, segnum, 0, nilfs_sufile_do_free);
> +     return nilfs_sufile_update(sufile, &segnum, 0, 0,
> +                                (void *)nilfs_sufile_do_free);
>  }

ditto

>  /**
> @@ -98,8 +100,8 @@ static inline int nilfs_sufile_free(struct inode *sufile, 
> __u64 segnum)
>  static inline int nilfs_sufile_freev(struct inode *sufile, __u64 *segnumv,
>                                    size_t nsegs, size_t *ndone)
>  {
> -     return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone,
> -                                 nilfs_sufile_do_free);
> +     return nilfs_sufile_updatev(sufile, segnumv, sizeof(__u64), 0, nsegs,
> +                                 0, ndone, (void *)nilfs_sufile_do_free);
>  }

ditto

>  /**
> @@ -116,8 +118,9 @@ static inline int nilfs_sufile_cancel_freev(struct inode 
> *sufile,
>                                           __u64 *segnumv, size_t nsegs,
>                                           size_t *ndone)
>  {
> -     return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone,
> -                                 nilfs_sufile_do_cancel_free);
> +     return nilfs_sufile_updatev(sufile, segnumv, sizeof(__u64), 0, nsegs,
> +                                 0, ndone,
> +                                 (void *)nilfs_sufile_do_cancel_free);
>  }

ditto

>  /**
> @@ -139,8 +142,8 @@ static inline int nilfs_sufile_cancel_freev(struct inode 
> *sufile,
>   */
>  static inline int nilfs_sufile_set_error(struct inode *sufile, __u64 segnum)
>  {
> -     return nilfs_sufile_update(sufile, segnum, 0,
> -                                nilfs_sufile_do_set_error);
> +     return nilfs_sufile_update(sufile, &segnum, 0, 0,
> +                                (void *)nilfs_sufile_do_set_error);
>  }
>  
>  #endif       /* _NILFS_SUFILE_H */

ditto


Regards,
Ryusuke Konishi

> -- 
> 2.3.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
> the body of a message to majord...@vger.kernel.org
> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to