* always aligned to a 64 bit boundary.
*
* The size of the buffer is in bytes, but is it assumed that it is
- * always ok to to read a complete multiple of 64 bits at the end
+ * always ok to read a complete multiple of 64 bits at the end
* of the block in case the end is no aligned to a natural boundary.
*
* Return: the block number (bitmap buffer scope) that was found
u64 rgrp_count = ip->i_disksize;
int error;
- if (do_div(rgrp_count, sizeof(struct gfs2_rindex))) {
- gfs2_consist_inode(ip);
- return -EIO;
- }
-
+ do_div(rgrp_count, sizeof(struct gfs2_rindex));
clear_rgrpdi(sdp);
file_ra_state_init(&ra_state, inode->i_mapping);
goto start_new_extent;
if ((start + nr_sects) != blk) {
rv = blkdev_issue_discard(bdev, start,
- nr_sects, GFP_NOFS);
+ nr_sects, GFP_NOFS,
+ DISCARD_FL_BARRIER);
if (rv)
goto fail;
nr_sects = 0;
}
}
if (nr_sects) {
- rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS);
+ rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS,
+ DISCARD_FL_BARRIER);
if (rv)
goto fail;
}
struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
{
BUG_ON(ip->i_alloc != NULL);
- ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL);
+ ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_NOFS);
return ip->i_alloc;
}
* try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes
* @rgd: The rgrp
*
- * Returns: The inode, if one has been found
+ * Returns: 0 if no error
+ * The inode, if one has been found, in inode.
*/
-static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
- u64 skip)
+static u64 try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
+ u64 skip)
{
- struct inode *inode;
u32 goal = 0, block;
u64 no_addr;
struct gfs2_sbd *sdp = rgd->rd_sbd;
if (no_addr == skip)
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;
+ return no_addr;
}
rgd->rd_flags &= ~GFS2_RDF_CHECK;
- return NULL;
+ return 0;
}
/**
* Try to acquire rgrp in way which avoids contending with others.
*
* Returns: errno
+ * unlinked: the block address of an unlinked block to be reclaimed
*/
-static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
+static int get_local_rgrp(struct gfs2_inode *ip, u64 *unlinked,
+ 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 loops = 0;
int error, rg_locked;
+ *unlinked = 0;
rgd = gfs2_blk2rgrpd(sdp, ip->i_goal);
while (rgd) {
case 0:
if (try_rgrp_fit(rgd, al))
goto out;
- if (rgd->rd_flags & GFS2_RDF_CHECK)
- inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
+ /* If the rg came in already locked, there's no
+ way we can recover from a failed try_rgrp_unlink
+ because that would require an iput which can only
+ happen after the rgrp is unlocked. */
+ if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK)
+ *unlinked = try_rgrp_unlink(rgd, last_unlinked,
+ ip->i_no_addr);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
- if (inode)
- return inode;
+ if (*unlinked)
+ return -EAGAIN;
/* fall through */
case GLR_TRYFAILED:
rgd = recent_rgrp_next(rgd);
break;
default:
- return ERR_PTR(error);
+ return 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, ip->i_no_addr);
+ if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK)
+ *unlinked = try_rgrp_unlink(rgd, last_unlinked,
+ ip->i_no_addr);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
- if (inode)
- return inode;
+ if (*unlinked)
+ return -EAGAIN;
break;
case GLR_TRYFAILED:
break;
default:
- return ERR_PTR(error);
+ return error;
}
rgd = gfs2_rgrpd_get_next(rgd);
if (rgd == begin) {
if (++loops >= 3)
- return ERR_PTR(-ENOSPC);
+ return -ENOSPC;
if (!skipped)
loops++;
flags = 0;
forward_rgrp_set(sdp, rgd);
}
- return NULL;
+ return 0;
}
/**
struct gfs2_alloc *al = ip->i_alloc;
struct inode *inode;
int error = 0;
- u64 last_unlinked = NO_BLOCK;
+ u64 last_unlinked = NO_BLOCK, unlinked;
if (gfs2_assert_warn(sdp, al->al_requested))
return -EINVAL;
if (error)
return error;
- inode = get_local_rgrp(ip, &last_unlinked);
- if (inode) {
+ error = get_local_rgrp(ip, &unlinked, &last_unlinked);
+ if (error) {
if (ip != GFS2_I(sdp->sd_rindex))
gfs2_glock_dq_uninit(&al->al_ri_gh);
- if (IS_ERR(inode))
- return PTR_ERR(inode);
- iput(inode);
+ if (error != -EAGAIN)
+ return error;
+ error = gfs2_unlinked_inode_lookup(ip->i_inode.i_sb,
+ unlinked, &inode);
+ if (inode)
+ iput(inode);
gfs2_log_flush(sdp, NULL);
+ if (error == GLR_TRYFAILED)
+ error = 0;
goto try_again;
}
{
struct gfs2_rgrpd *rgd;
struct gfs2_holder ri_gh, rgd_gh;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
+ int ri_locked = 0;
int error;
- error = gfs2_rindex_hold(sdp, &ri_gh);
- if (error)
- goto fail;
+ if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
+ error = gfs2_rindex_hold(sdp, &ri_gh);
+ if (error)
+ goto fail;
+ ri_locked = 1;
+ }
error = -EINVAL;
rgd = gfs2_blk2rgrpd(sdp, no_addr);
gfs2_glock_dq_uninit(&rgd_gh);
fail_rindex:
- gfs2_glock_dq_uninit(&ri_gh);
+ if (ri_locked)
+ gfs2_glock_dq_uninit(&ri_gh);
fail:
return error;
}