📄 rgrp.c
字号:
} sdp->sd_rindex_vn = ip->i_gl->gl_vn; return 0;}/** * gfs2_ri_update_special - Pull in a new resource index from the disk * * This is a special version that's safe to call from gfs2_inplace_reserve_i. * In this case we know that we don't have any resource groups in memory yet. * * @ip: pointer to the rindex inode * * Returns: 0 on successful update, error code otherwise */static int gfs2_ri_update_special(struct gfs2_inode *ip){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *inode = &ip->i_inode; struct file_ra_state ra_state; int error; file_ra_state_init(&ra_state, inode->i_mapping); for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) { /* Ignore partials */ if ((sdp->sd_rgrps + 1) * sizeof(struct gfs2_rindex) > ip->i_di.di_size) break; error = read_rindex_entry(ip, &ra_state); if (error) { clear_rgrpdi(sdp); return error; } } sdp->sd_rindex_vn = ip->i_gl->gl_vn; return 0;}/** * gfs2_rindex_hold - Grab a lock on the rindex * @sdp: The GFS2 superblock * @ri_gh: the glock holder * * We grab a lock on the rindex inode to make sure that it doesn't * change whilst we are performing an operation. We keep this lock * for quite long periods of time compared to other locks. This * doesn't matter, since it is shared and it is very, very rarely * accessed in the exclusive mode (i.e. only when expanding the filesystem). * * This makes sure that we're using the latest copy of the resource index * special file, which might have been updated if someone expanded the * filesystem (via gfs2_grow utility), which adds new resource groups. * * Returns: 0 on success, error code otherwise */int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh){ struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex); struct gfs2_glock *gl = ip->i_gl; int error; error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh); if (error) return error; /* Read new copy from disk if we don't have the latest */ if (sdp->sd_rindex_vn != gl->gl_vn) { mutex_lock(&sdp->sd_rindex_mutex); if (sdp->sd_rindex_vn != gl->gl_vn) { error = gfs2_ri_update(ip); if (error) gfs2_glock_dq_uninit(ri_gh); } mutex_unlock(&sdp->sd_rindex_mutex); } return error;}static void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf){ const struct gfs2_rgrp *str = buf; rg->rg_flags = be32_to_cpu(str->rg_flags); rg->rg_free = be32_to_cpu(str->rg_free); rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);}static void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf){ struct gfs2_rgrp *str = buf; str->rg_flags = cpu_to_be32(rg->rg_flags); str->rg_free = cpu_to_be32(rg->rg_free); str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); str->__pad = cpu_to_be32(0); str->rg_igeneration = cpu_to_be64(rg->rg_igeneration); memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));}/** * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps * @rgd: the struct gfs2_rgrpd describing the RG to read in * * Read in all of a Resource Group's header and bitmap blocks. * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps. * * Returns: errno */int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd){ struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_glock *gl = rgd->rd_gl; unsigned int length = rgd->rd_length; struct gfs2_bitmap *bi; unsigned int x, y; int error; mutex_lock(&rgd->rd_mutex); spin_lock(&sdp->sd_rindex_spin); if (rgd->rd_bh_count) { rgd->rd_bh_count++; spin_unlock(&sdp->sd_rindex_spin); mutex_unlock(&rgd->rd_mutex); return 0; } spin_unlock(&sdp->sd_rindex_spin); for (x = 0; x < length; x++) { bi = rgd->rd_bits + x; error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh); if (error) goto fail; } for (y = length; y--;) { bi = rgd->rd_bits + y; error = gfs2_meta_wait(sdp, bi->bi_bh); if (error) goto fail; if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB : GFS2_METATYPE_RG)) { error = -EIO; goto fail; } } if (rgd->rd_rg_vn != gl->gl_vn) { gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data); rgd->rd_rg_vn = gl->gl_vn; } spin_lock(&sdp->sd_rindex_spin); rgd->rd_free_clone = rgd->rd_rg.rg_free; rgd->rd_bh_count++; spin_unlock(&sdp->sd_rindex_spin); mutex_unlock(&rgd->rd_mutex); return 0;fail: while (x--) { bi = rgd->rd_bits + x; brelse(bi->bi_bh); bi->bi_bh = NULL; gfs2_assert_warn(sdp, !bi->bi_clone); } mutex_unlock(&rgd->rd_mutex); return error;}void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd){ struct gfs2_sbd *sdp = rgd->rd_sbd; spin_lock(&sdp->sd_rindex_spin); gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count); rgd->rd_bh_count++; spin_unlock(&sdp->sd_rindex_spin);}/** * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get() * @rgd: the struct gfs2_rgrpd describing the RG to read in * */void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd){ struct gfs2_sbd *sdp = rgd->rd_sbd; int x, length = rgd->rd_length; spin_lock(&sdp->sd_rindex_spin); gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count); if (--rgd->rd_bh_count) { spin_unlock(&sdp->sd_rindex_spin); return; } for (x = 0; x < length; x++) { struct gfs2_bitmap *bi = rgd->rd_bits + x; kfree(bi->bi_clone); bi->bi_clone = NULL; brelse(bi->bi_bh); bi->bi_bh = NULL; } spin_unlock(&sdp->sd_rindex_spin);}void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd){ struct gfs2_sbd *sdp = rgd->rd_sbd; unsigned int length = rgd->rd_length; unsigned int x; for (x = 0; x < length; x++) { struct gfs2_bitmap *bi = rgd->rd_bits + x; if (!bi->bi_clone) continue; memcpy(bi->bi_clone + bi->bi_offset, bi->bi_bh->b_data + bi->bi_offset, bi->bi_len); } spin_lock(&sdp->sd_rindex_spin); rgd->rd_free_clone = rgd->rd_rg.rg_free; spin_unlock(&sdp->sd_rindex_spin);}/** * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode * @ip: the incore GFS2 inode structure * * Returns: the struct gfs2_alloc */struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip){ struct gfs2_alloc *al = &ip->i_alloc; /* FIXME: Should assert that the correct locks are held here... */ memset(al, 0, sizeof(*al)); return al;}/** * try_rgrp_fit - See if a given reservation will fit in a given RG * @rgd: the RG data * @al: the struct gfs2_alloc structure describing the reservation * * If there's room for the requested blocks to be allocated from the RG: * Sets the $al_rgd field in @al. * * Returns: 1 on success (it fits), 0 on failure (it doesn't fit) */static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al){ struct gfs2_sbd *sdp = rgd->rd_sbd; int ret = 0; if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC) return 0; spin_lock(&sdp->sd_rindex_spin); if (rgd->rd_free_clone >= al->al_requested) { al->al_rgd = rgd; ret = 1; } spin_unlock(&sdp->sd_rindex_spin); return ret;}/** * try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes * @rgd: The rgrp * * Returns: The inode, if one has been found */static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked){ struct inode *inode; u32 goal = 0, block; u64 no_addr; struct gfs2_sbd *sdp = rgd->rd_sbd; for(;;) { if (goal >= rgd->rd_data) break; down_write(&sdp->sd_log_flush_lock); block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, GFS2_BLKST_UNLINKED); up_write(&sdp->sd_log_flush_lock); if (block == BFITNOENT) break; /* rgblk_search can return a block < goal, so we need to keep it marching forward. */ no_addr = block + rgd->rd_data0; goal++; if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) continue; *last_unlinked = no_addr; inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, no_addr, -1, 1); if (!IS_ERR(inode)) return inode; } rgd->rd_flags &= ~GFS2_RDF_CHECK; return NULL;}/** * recent_rgrp_first - get first RG from "recent" list * @sdp: The GFS2 superblock * @rglast: address of the rgrp used last * * Returns: The first rgrp in the recent list */static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp, u64 rglast){ struct gfs2_rgrpd *rgd = NULL; spin_lock(&sdp->sd_rindex_spin); if (list_empty(&sdp->sd_rindex_recent_list)) goto out; if (!rglast) goto first; list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) { if (rgd->rd_addr == rglast) goto out; }first: rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd, rd_recent);out: spin_unlock(&sdp->sd_rindex_spin); return rgd;}/** * recent_rgrp_next - get next RG from "recent" list * @cur_rgd: current rgrp * @remove: * * Returns: The next rgrp in the recent list */static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd, int remove){ struct gfs2_sbd *sdp = cur_rgd->rd_sbd; struct list_head *head; struct gfs2_rgrpd *rgd; spin_lock(&sdp->sd_rindex_spin); head = &sdp->sd_rindex_recent_list; list_for_each_entry(rgd, head, rd_recent) { if (rgd == cur_rgd) { if (cur_rgd->rd_recent.next != head) rgd = list_entry(cur_rgd->rd_recent.next, struct gfs2_rgrpd, rd_recent); else rgd = NULL; if (remove) list_del(&cur_rgd->rd_recent); goto out; } } rgd = NULL; if (!list_empty(head)) rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);out: spin_unlock(&sdp->sd_rindex_spin); return rgd;}/** * recent_rgrp_add - add an RG to tail of "recent" list * @new_rgd: The rgrp to add * */static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd){ struct gfs2_sbd *sdp = new_rgd->rd_sbd; struct gfs2_rgrpd *rgd; unsigned int count = 0; unsigned int max = sdp->sd_rgrps / gfs2_jindex_size(sdp); spin_lock(&sdp->sd_rindex_spin); list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) { if (rgd == new_rgd) goto out; if (++count >= max) goto out; } list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list);out: spin_unlock(&sdp->sd_rindex_spin);}/** * forward_rgrp_get - get an rgrp to try next from full list * @sdp: The GFS2 superblock * * Returns: The rgrp to try next */static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp){ struct gfs2_rgrpd *rgd; unsigned int journals = gfs2_jindex_size(sdp); unsigned int rg = 0, x; spin_lock(&sdp->sd_rindex_spin); rgd = sdp->sd_rindex_forward; if (!rgd) { if (sdp->sd_rgrps >= journals) rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals; for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg; x++, rgd = gfs2_rgrpd_get_next(rgd)) /* Do Nothing */; sdp->sd_rindex_forward = rgd; } spin_unlock(&sdp->sd_rindex_spin); return rgd;}/** * forward_rgrp_set - set the forward rgrp pointer * @sdp: the filesystem * @rgd: The new forward rgrp * */static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd){ spin_lock(&sdp->sd_rindex_spin); sdp->sd_rindex_forward = rgd; spin_unlock(&sdp->sd_rindex_spin);}/** * get_local_rgrp - Choose and lock a rgrp for allocation * @ip: the inode to reserve space for * @rgp: the chosen and locked rgrp * * Try to acquire rgrp in way which avoids contending with others. * * Returns: errno */static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked){ struct inode *inode = NULL; struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrpd *rgd, *begin = NULL; struct gfs2_alloc *al = &ip->i_alloc; int flags = LM_FLAG_TRY; int skipped = 0; int loops = 0; int error; /* Try recently successful rgrps */ rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); while (rgd) { error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY, &al->al_rgd_gh); switch (error) { case 0: if (try_rgrp_fit(rgd, al)) goto out; if (rgd->rd_flags & GFS2_RDF_CHECK) inode = try_rgrp_unlink(rgd, last_unlinked); gfs2_glock_dq_uninit(&al->al_rgd_gh); if (inode) return inode; rgd = recent_rgrp_next(rgd, 1); break; case GLR_TRYFAILED: rgd = recent_rgrp_next(rgd, 0); break; default: return ERR_PTR(error); } } /* Go through full list of rgrps */ begin = rgd = forward_rgrp_get(sdp); for (;;) { error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, &al->al_rgd_gh); switch (error) { case 0: if (try_rgrp_fit(rgd, al)) goto out; if (rgd->rd_flags & GFS2_RDF_CHECK) inode = try_rgrp_unlink(rgd, last_unlinked); gfs2_glock_dq_uninit(&al->al_rgd_gh); if (inode) return inode; break; case GLR_TRYFAILED: skipped++; break; default: return ERR_PTR(error); } rgd = gfs2_rgrpd_get_next(rgd); if (!rgd) rgd = gfs2_rgrpd_get_first(sdp); if (rgd == begin) { if (++loops >= 3) return ERR_PTR(-ENOSPC); if (!skipped) loops++; flags = 0; if (loops == 2) gfs2_log_flush(sdp, NULL); } }out: ip->i_last_rg_alloc = rgd->rd_addr; if (begin) { recent_rgrp_add(rgd); rgd = gfs2_rgrpd_get_next(rgd); if (!rgd) rgd = gfs2_rgrpd_get_first(sdp); forward_rgrp_set(sdp, rgd); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -