Previously init_dinode() always allocated the bh with bget() which meant less control over memory allocation higher up. This patch changes the signature of init_dinode to accept a bh pointer and only allocates a new bh if it is NULL. Also adds error checking to init_dinode()'s callers.
Signed-off-by: Andrew Price <anpr...@redhat.com> --- gfs2/convert/gfs2_convert.c | 7 +++++-- gfs2/fsck/initialize.c | 12 ++++++++---- gfs2/libgfs2/fs_ops.c | 42 ++++++++++++++++++++++++------------------ gfs2/libgfs2/libgfs2.h | 6 ++---- gfs2/libgfs2/structures.c | 13 +++++++++---- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c index 61ed320..19a9839 100644 --- a/gfs2/convert/gfs2_convert.c +++ b/gfs2/convert/gfs2_convert.c @@ -1389,7 +1389,7 @@ static int fix_cdpn_symlinks(struct gfs2_sbd *sbp, osi_list_t *cdpn_to_fix) osi_list_foreach_safe(tmp, cdpn_to_fix, x) { struct gfs2_inum fix, dir; struct inode_dir_block *l_fix; - struct gfs2_buffer_head *bh; + struct gfs2_buffer_head *bh = NULL; struct gfs2_inode *fix_inode; uint64_t eablk; @@ -1411,7 +1411,10 @@ static int fix_cdpn_symlinks(struct gfs2_sbd *sbp, osi_list_t *cdpn_to_fix) } /* initialize the symlink inode to be a directory */ - bh = init_dinode(sbp, &fix, S_IFDIR | 0755, 0, &dir); + error = init_dinode(sbp, &bh, &fix, S_IFDIR | 0755, 0, &dir); + if (error != 0) + return -1; + fix_inode = lgfs2_inode_get(sbp, bh); if (fix_inode == NULL) return -1; diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c index 02ecd3f..4dedec2 100644 --- a/gfs2/fsck/initialize.c +++ b/gfs2/fsck/initialize.c @@ -419,7 +419,7 @@ static void check_rgrps_integrity(struct gfs2_sbd *sdp) static int rebuild_master(struct gfs2_sbd *sdp) { struct gfs2_inum inum; - struct gfs2_buffer_head *bh; + struct gfs2_buffer_head *bh = NULL; int err = 0; log_err(_("The system master directory seems to be destroyed.\n")); @@ -430,7 +430,9 @@ static int rebuild_master(struct gfs2_sbd *sdp) log_err(_("Trying to rebuild the master directory.\n")); inum.no_formal_ino = sdp->md.next_inum++; inum.no_addr = sdp->sd_sb.sb_master_dir.no_addr; - bh = init_dinode(sdp, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum); + err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum); + if (err != 0) + return -1; sdp->master_dir = lgfs2_inode_get(sdp, bh); if (sdp->master_dir == NULL) { log_crit(_("Error reading master: %s\n"), strerror(errno)); @@ -1210,7 +1212,7 @@ static int sb_repair(struct gfs2_sbd *sdp) sdp->md.rooti = lgfs2_inode_read(sdp, possible_root); if (!sdp->md.rooti || sdp->md.rooti->i_di.di_header.mh_magic != GFS2_MAGIC) { - struct gfs2_buffer_head *bh; + struct gfs2_buffer_head *bh = NULL; log_err(_("The root dinode block is destroyed.\n")); log_err(_("At this point I recommend " @@ -1225,7 +1227,9 @@ static int sb_repair(struct gfs2_sbd *sdp) } inum.no_formal_ino = 1; inum.no_addr = possible_root; - bh = init_dinode(sdp, &inum, S_IFDIR | 0755, 0, &inum); + error = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, 0, &inum); + if (error != 0) + return -1; brelse(bh); } } diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c index aa95aa8..c8b90ad 100644 --- a/gfs2/libgfs2/fs_ops.c +++ b/gfs2/libgfs2/fs_ops.c @@ -1273,24 +1273,30 @@ int dir_add(struct gfs2_inode *dip, const char *filename, int len, return err; } -static struct gfs2_buffer_head *__init_dinode(struct gfs2_sbd *sdp, - struct gfs2_inum *inum, - unsigned int mode, - uint32_t flags, - struct gfs2_inum *parent, - int gfs1) +static int __init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum, + unsigned int mode, uint32_t flags, struct gfs2_inum *parent, int gfs1) { struct gfs2_buffer_head *bh; - struct gfs2_dinode di; + struct gfs2_dinode di = {{0}}; int is_dir; if (gfs1) is_dir = (IF2DT(mode) == GFS_FILE_DIR); else is_dir = S_ISDIR(mode); - bh = bget(sdp, inum->no_addr); - memset(&di, 0, sizeof(struct gfs2_dinode)); + errno = EINVAL; + if (bhp == NULL) + return 1; + + if (*bhp == NULL) { + *bhp = bget(sdp, inum->no_addr); + if (*bhp == NULL) + return 1; + } + + bh = *bhp; + di.di_header.mh_magic = GFS2_MAGIC; di.di_header.mh_type = GFS2_METATYPE_DI; di.di_header.mh_format = GFS2_FORMAT_DI; @@ -1340,15 +1346,13 @@ static struct gfs2_buffer_head *__init_dinode(struct gfs2_sbd *sdp, gfs2_dinode_out(&di, bh); - return bh; + return 0; } -struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp, - struct gfs2_inum *inum, - unsigned int mode, uint32_t flags, - struct gfs2_inum *parent) +int init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum, + unsigned int mode, uint32_t flags, struct gfs2_inum *parent) { - return __init_dinode(sdp, inum, mode, flags, parent, 0); + return __init_dinode(sdp, bhp, inum, mode, flags, parent, 0); } static struct gfs2_inode *__createi(struct gfs2_inode *dip, @@ -1358,7 +1362,7 @@ static struct gfs2_inode *__createi(struct gfs2_inode *dip, struct gfs2_sbd *sdp = dip->i_sbd; uint64_t bn; struct gfs2_inum inum; - struct gfs2_buffer_head *bh; + struct gfs2_buffer_head *bh = NULL; struct gfs2_inode *ip; int err = 0; int is_dir; @@ -1388,8 +1392,10 @@ static struct gfs2_inode *__createi(struct gfs2_inode *dip, dip->i_di.di_nlink++; } - bh = __init_dinode(sdp, &inum, mode, flags, &dip->i_di.di_num, - if_gfs1); + err = __init_dinode(sdp, &bh, &inum, mode, flags, &dip->i_di.di_num, if_gfs1); + if (err != 0) + return NULL; + ip = lgfs2_inode_get(sdp, bh); if (ip == NULL) return NULL; diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h index ed1030c..9b1bdc2 100644 --- a/gfs2/libgfs2/libgfs2.h +++ b/gfs2/libgfs2/libgfs2.h @@ -462,10 +462,8 @@ extern int __gfs2_writei(struct gfs2_inode *ip, void *buf, uint64_t offset, unsigned int size, int resize); extern struct gfs2_buffer_head *get_file_buf(struct gfs2_inode *ip, uint64_t lbn, int prealloc); -extern struct gfs2_buffer_head *init_dinode(struct gfs2_sbd *sdp, - struct gfs2_inum *inum, - unsigned int mode, uint32_t flags, - struct gfs2_inum *parent); +extern int init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum, + unsigned int mode, uint32_t flags, struct gfs2_inum *parent); extern struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename, unsigned int mode, uint32_t flags); extern struct gfs2_inode *gfs_createi(struct gfs2_inode *dip, diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c index 9d90657..1836255 100644 --- a/gfs2/libgfs2/structures.c +++ b/gfs2/libgfs2/structures.c @@ -20,7 +20,7 @@ int build_master(struct gfs2_sbd *sdp) { struct gfs2_inum inum; uint64_t bn; - struct gfs2_buffer_head *bh; + struct gfs2_buffer_head *bh = NULL; int err = lgfs2_dinode_alloc(sdp, 1, &bn); if (err != 0) @@ -29,7 +29,9 @@ int build_master(struct gfs2_sbd *sdp) inum.no_formal_ino = sdp->md.next_inum++; inum.no_addr = bn; - bh = init_dinode(sdp, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum); + err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, GFS2_DIF_SYSTEM, &inum); + if (err != 0) + return -1; sdp->master_dir = lgfs2_inode_get(sdp, bh); if (sdp->master_dir == NULL) @@ -479,7 +481,7 @@ int build_root(struct gfs2_sbd *sdp) { struct gfs2_inum inum; uint64_t bn; - struct gfs2_buffer_head *bh; + struct gfs2_buffer_head *bh = NULL; int err = lgfs2_dinode_alloc(sdp, 1, &bn); if (err != 0) @@ -488,7 +490,10 @@ int build_root(struct gfs2_sbd *sdp) inum.no_formal_ino = sdp->md.next_inum++; inum.no_addr = bn; - bh = init_dinode(sdp, &inum, S_IFDIR | 0755, 0, &inum); + err = init_dinode(sdp, &bh, &inum, S_IFDIR | 0755, 0, &inum); + if (err != 0) + return -1; + sdp->md.rooti = lgfs2_inode_get(sdp, bh); if (sdp->md.rooti == NULL) return -1; -- 1.9.3