Hi,

This patch introduces file read-ahead to pass1.

Regards,

Bob Peterson
Red Hat File Systems

Signed-off-by: Bob Peterson <rpete...@redhat.com> 
---
 gfs2/fsck/metawalk.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 gfs2/fsck/metawalk.h |  1 +
 gfs2/fsck/pass1.c    |  1 +
 3 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 659af4e..8da17c6 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1184,6 +1184,59 @@ static void free_metalist(struct gfs2_inode *ip, 
osi_list_t *mlp)
        }
 }
 
+static void file_ra(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
+                   int head_size, int maxptrs, int h)
+{
+       struct gfs2_sbd *sdp = ip->i_sbd;
+       uint64_t *p, sblock = 0, block;
+       int extlen = 0;
+
+       if (h + 2 == ip->i_di.di_height) {
+               p = (uint64_t *)(bh->b_data + head_size);
+               if (*p && *(p + 1)) {
+                       sblock = be64_to_cpu(*p);
+                       p++;
+                       block = be64_to_cpu(*p);
+                       extlen = block - sblock;
+                       if (extlen > 1 && extlen <= maxptrs) {
+                               posix_fadvise(sdp->device_fd,
+                                             sblock * sdp->bsize,
+                                             (extlen + 1) * sdp->bsize,
+                                             POSIX_FADV_WILLNEED);
+                               return;
+                       }
+               }
+               extlen = 0;
+       }
+       for (p = (uint64_t *)(bh->b_data + head_size);
+            p < (uint64_t *)(bh->b_data + sdp->bsize); p++) {
+               if (*p) {
+                       if (!sblock) {
+                               sblock = be64_to_cpu(*p);
+                               extlen = 1;
+                               continue;
+                       }
+                       block = be64_to_cpu(*p);
+                       if (block == sblock + extlen) {
+                               extlen++;
+                               continue;
+                       }
+               }
+               if (extlen && sblock) {
+                       if (extlen > 1)
+                               extlen--;
+                       posix_fadvise(sdp->device_fd, sblock * sdp->bsize,
+                                     extlen * sdp->bsize,
+                                     POSIX_FADV_WILLNEED);
+                       extlen = 0;
+                       p--;
+               }
+       }
+       if (extlen)
+               posix_fadvise(sdp->device_fd, sblock * sdp->bsize,
+                             extlen * sdp->bsize, POSIX_FADV_WILLNEED);
+}
+
 /**
  * build_and_check_metalist - check a bunch of indirect blocks
  *                            This includes hash table blocks for directories
@@ -1204,6 +1257,7 @@ static int build_and_check_metalist(struct gfs2_inode 
*ip, osi_list_t *mlp,
        int h, head_size, iblk_type;
        uint64_t *ptr, block;
        int error, was_duplicate, is_valid;
+       int maxptrs;
 
        osi_list_add(&metabh->b_altlist, &mlp[0]);
 
@@ -1225,13 +1279,18 @@ static int build_and_check_metalist(struct gfs2_inode 
*ip, osi_list_t *mlp,
                                iblk_type = GFS2_METATYPE_JD;
                        else
                                iblk_type = GFS2_METATYPE_IN;
-                       if (ip->i_sbd->gfs1)
+                       if (ip->i_sbd->gfs1) {
                                head_size = sizeof(struct gfs_indirect);
-                       else
+                               maxptrs = (ip->i_sbd->bsize - head_size) /
+                                       sizeof(uint64_t);
+                       } else {
                                head_size = sizeof(struct gfs2_meta_header);
+                               maxptrs = ip->i_sbd->sd_inptrs;
+                       }
                } else {
                        iblk_type = GFS2_METATYPE_DI;
                        head_size = sizeof(struct gfs2_dinode);
+                       maxptrs = ip->i_sbd->sd_diptrs;
                }
                prev_list = &mlp[h - 1];
                cur_list = &mlp[h];
@@ -1246,6 +1305,8 @@ static int build_and_check_metalist(struct gfs2_inode 
*ip, osi_list_t *mlp,
                                continue;
                        }
 
+                       if (pass->readahead)
+                               file_ra(ip, bh, head_size, maxptrs, h);
                        /* Now check the metadata itself */
                        for (ptr = (uint64_t *)(bh->b_data + head_size);
                             (char *)ptr < (bh->b_data + ip->i_sbd->bsize);
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 5e30bfe..a4e0676 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -94,6 +94,7 @@ enum meta_check_rc {
 struct metawalk_fxns {
        void *private;
        int invalid_meta_is_fatal;
+       int readahead;
        int (*check_leaf_depth) (struct gfs2_inode *ip, uint64_t leaf_no,
                                 int ref_count, struct gfs2_buffer_head *lbh);
        int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 4f1b77a..fec2f64 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1055,6 +1055,7 @@ static int rangecheck_eattr_leaf(struct gfs2_inode *ip, 
uint64_t block,
 
 struct metawalk_fxns rangecheck_fxns = {
         .private = NULL,
+       .readahead = 1,
         .check_metalist = rangecheck_metadata,
         .check_data = rangecheck_data,
         .check_leaf = rangecheck_leaf,

Reply via email to