int gfs2_dinode_dealloc(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al; struct gfs2_rgrpd *rgd; int error; if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); return -EIO; } al = gfs2_alloc_get(ip); if (!al) return -ENOMEM; error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out; error = gfs2_rindex_hold(sdp, &al->al_ri_gh); if (error) goto out_qs; rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); if (!rgd) { gfs2_consist_inode(ip); error = -EIO; goto out_rindex_relse; } error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &al->al_rgd_gh); if (error) goto out_rindex_relse; error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); if (error) goto out_rg_gunlock; set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags); gfs2_free_di(rgd, ip); gfs2_trans_end(sdp); clear_bit(GLF_STICKY, &ip->i_gl->gl_flags); out_rg_gunlock: gfs2_glock_dq_uninit(&al->al_rgd_gh); out_rindex_relse: gfs2_glock_dq_uninit(&al->al_ri_gh); out_qs: gfs2_quota_unhold(ip); out: gfs2_alloc_put(ip); return error; }
static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder ghs[3]; struct gfs2_rgrpd *rgd; struct gfs2_holder ri_gh; int error; error = gfs2_rindex_hold(sdp, &ri_gh); if (error) return error; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); error = gfs2_glock_nq_m(3, ghs); if (error) goto out; error = gfs2_unlink_ok(dip, &dentry->d_name, ip); if (error) goto out_gunlock; if (ip->i_di.di_entries < 2) { if (gfs2_consist_inode(ip)) gfs2_dinode_print(ip); error = -EIO; goto out_gunlock; } if (ip->i_di.di_entries > 2) { error = -ENOTEMPTY; goto out_gunlock; } error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0); if (error) goto out_gunlock; error = gfs2_rmdiri(dip, &dentry->d_name, ip); gfs2_trans_end(sdp); out_gunlock: gfs2_glock_dq_m(3, ghs); out: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); gfs2_holder_uninit(ghs + 2); gfs2_glock_dq_uninit(&ri_gh); return error; }
static int gfs2_unlink(struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder ghs[3]; struct gfs2_rgrpd *rgd; struct gfs2_holder ri_gh; int error; error = gfs2_rindex_hold(sdp, &ri_gh); if (error) return error; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); error = gfs2_glock_nq(ghs); /* parent */ if (error) goto out_parent; error = gfs2_glock_nq(ghs + 1); /* child */ if (error) goto out_child; error = gfs2_glock_nq(ghs + 2); /* rgrp */ if (error) goto out_rgrp; error = gfs2_unlink_ok(dip, &dentry->d_name, ip); if (error) goto out_rgrp; error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); if (error) goto out_rgrp; error = gfs2_dir_del(dip, &dentry->d_name); if (error) goto out_end_trans; error = gfs2_change_nlink(ip, -1); out_end_trans: gfs2_trans_end(sdp); gfs2_glock_dq(ghs + 2); out_rgrp: gfs2_holder_uninit(ghs + 2); gfs2_glock_dq(ghs + 1); out_child: gfs2_holder_uninit(ghs + 1); gfs2_glock_dq(ghs); out_parent: gfs2_holder_uninit(ghs); gfs2_glock_dq_uninit(&ri_gh); return error; }
static struct dentry *gfs2_get_dentry(struct super_block *sb, struct gfs2_inum_host *inum) { struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj; struct gfs2_holder i_gh, ri_gh, rgd_gh; struct gfs2_rgrpd *rgd; struct inode *inode; struct dentry *dentry; int error; /* System files? */ inode = gfs2_ilookup(sb, inum); if (inode) { if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) { iput(inode); return ERR_PTR(-ESTALE); } goto out_inode; } error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return ERR_PTR(error); error = gfs2_rindex_hold(sdp, &ri_gh); if (error) goto fail; error = -EINVAL; rgd = gfs2_blk2rgrpd(sdp, inum->no_addr); if (!rgd) goto fail_rindex; error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); if (error) goto fail_rindex; error = -ESTALE; if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE) goto fail_rgd; gfs2_glock_dq_uninit(&rgd_gh); gfs2_glock_dq_uninit(&ri_gh); inode = gfs2_inode_lookup(sb, inum, fh_obj->imode); if (!inode) goto fail; if (IS_ERR(inode)) { error = PTR_ERR(inode); goto fail; } error = gfs2_inode_refresh(GFS2_I(inode)); if (error) { iput(inode); goto fail; } error = -EIO; if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) { iput(inode); goto fail; } gfs2_glock_dq_uninit(&i_gh); out_inode: dentry = d_alloc_anon(inode); if (!dentry) { iput(inode); return ERR_PTR(-ENOMEM); } dentry->d_op = &gfs2_dops; return dentry; fail_rgd: gfs2_glock_dq_uninit(&rgd_gh); fail_rindex: gfs2_glock_dq_uninit(&ri_gh); fail: gfs2_glock_dq_uninit(&i_gh); return ERR_PTR(error); }
static int gfs2_unlink(struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct inode *inode = dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; struct gfs2_holder ghs[3]; struct gfs2_rgrpd *rgd; struct gfs2_holder ri_gh; int error; error = gfs2_rindex_hold(sdp, &ri_gh); if (error) return error; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); error = gfs2_glock_nq(ghs); /* parent */ if (error) goto out_parent; error = gfs2_glock_nq(ghs + 1); /* child */ if (error) goto out_child; error = -ENOENT; if (inode->i_nlink == 0) goto out_rgrp; if (S_ISDIR(inode->i_mode)) { error = -ENOTEMPTY; if (ip->i_entries > 2 || inode->i_nlink > 2) goto out_rgrp; } error = gfs2_glock_nq(ghs + 2); /* rgrp */ if (error) goto out_rgrp; error = gfs2_unlink_ok(dip, &dentry->d_name, ip); if (error) goto out_gunlock; error = gfs2_trans_begin(sdp, 2*RES_DINODE + 3*RES_LEAF + RES_RG_BIT, 0); if (error) goto out_gunlock; error = gfs2_meta_inode_buffer(ip, &bh); if (error) goto out_end_trans; error = gfs2_unlink_inode(dip, dentry, bh); brelse(bh); out_end_trans: gfs2_trans_end(sdp); out_gunlock: gfs2_glock_dq(ghs + 2); out_rgrp: gfs2_holder_uninit(ghs + 2); gfs2_glock_dq(ghs + 1); out_child: gfs2_holder_uninit(ghs + 1); gfs2_glock_dq(ghs); out_parent: gfs2_holder_uninit(ghs); gfs2_glock_dq_uninit(&ri_gh); return error; }
static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc) { struct gfs2_holder ri_gh; struct gfs2_rgrpd *rgd_next; struct gfs2_holder *gha, *gh; unsigned int slots = 64; unsigned int x; int done; int error = 0, err; memset(sc, 0, sizeof(struct gfs2_statfs_change_host)); gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL); if (!gha) return -ENOMEM; error = gfs2_rindex_hold(sdp, &ri_gh); if (error) goto out; rgd_next = gfs2_rgrpd_get_first(sdp); for (;;) { done = 1; for (x = 0; x < slots; x++) { gh = gha + x; if (gh->gh_gl && gfs2_glock_poll(gh)) { err = gfs2_glock_wait(gh); if (err) { gfs2_holder_uninit(gh); error = err; } else { if (!error) error = statfs_slow_fill( gh->gh_gl->gl_object, sc); gfs2_glock_dq_uninit(gh); } } if (gh->gh_gl) done = 0; else if (rgd_next && !error) { error = gfs2_glock_nq_init(rgd_next->rd_gl, LM_ST_SHARED, GL_ASYNC, gh); rgd_next = gfs2_rgrpd_get_next(rgd_next); done = 0; } if (signal_pending(current)) error = -ERESTARTSYS; } if (done) break; yield(); } gfs2_glock_dq_uninit(&ri_gh); out: kfree(gha); return error; }