Merge branch 'xfs-misc-fixes-for-3.18-1' into for-next

This commit is contained in:
Dave Chinner 2014-09-09 13:25:31 +10:00
commit a4241aebe9
19 changed files with 295 additions and 330 deletions

View File

@ -2209,6 +2209,10 @@ xfs_agf_verify(
be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
return false;
if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
return false;
/*
* during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't

View File

@ -237,7 +237,8 @@ xfs_dir_init(
}
/*
Enter a name in a directory.
* Enter a name in a directory, or check for available space.
* If inum is 0, only the available space test is performed.
*/
int
xfs_dir_createname(
@ -254,10 +255,12 @@ xfs_dir_createname(
int v; /* type-checking value */
ASSERT(S_ISDIR(dp->i_d.di_mode));
rval = xfs_dir_ino_validate(tp->t_mountp, inum);
if (rval)
return rval;
XFS_STATS_INC(xs_dir_create);
if (inum) {
rval = xfs_dir_ino_validate(tp->t_mountp, inum);
if (rval)
return rval;
XFS_STATS_INC(xs_dir_create);
}
args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
if (!args)
@ -276,6 +279,8 @@ xfs_dir_createname(
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
if (!inum)
args->op_flags |= XFS_DA_OP_JUSTCHECK;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
rval = xfs_dir2_sf_addname(args);
@ -535,62 +540,14 @@ xfs_dir_replace(
/*
* See if this entry can be added to the directory without allocating space.
* First checks that the caller couldn't reserve enough space (resblks = 0).
*/
int
xfs_dir_canenter(
xfs_trans_t *tp,
xfs_inode_t *dp,
struct xfs_name *name, /* name of entry to add */
uint resblks)
struct xfs_name *name) /* name of entry to add */
{
struct xfs_da_args *args;
int rval;
int v; /* type-checking value */
if (resblks)
return 0;
ASSERT(S_ISDIR(dp->i_d.di_mode));
args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
if (!args)
return -ENOMEM;
args->geo = dp->i_mount->m_dir_geo;
args->name = name->name;
args->namelen = name->len;
args->filetype = name->type;
args->hashval = dp->i_mount->m_dirnameops->hashname(name);
args->dp = dp;
args->whichfork = XFS_DATA_FORK;
args->trans = tp;
args->op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
XFS_DA_OP_OKNOENT;
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
rval = xfs_dir2_sf_addname(args);
goto out_free;
}
rval = xfs_dir2_isblock(args, &v);
if (rval)
goto out_free;
if (v) {
rval = xfs_dir2_block_addname(args);
goto out_free;
}
rval = xfs_dir2_isleaf(args, &v);
if (rval)
goto out_free;
if (v)
rval = xfs_dir2_leaf_addname(args);
else
rval = xfs_dir2_node_addname(args);
out_free:
kmem_free(args);
return rval;
return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
}
/*

View File

@ -136,7 +136,7 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_fsblock_t *first,
struct xfs_bmap_free *flist, xfs_extlen_t tot);
extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, uint resblks);
struct xfs_name *name);
/*
* Direct call from the bmap code, bypassing the generic directory layer.

View File

@ -2051,6 +2051,8 @@ xfs_agi_verify(
if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
return false;
if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS)
return false;
/*
* during growfs operations, the perag is not fully initialised,
* so we can't use it for any useful checking. growfs ensures we can't

View File

@ -424,20 +424,24 @@ xfs_rtfind_forw(
}
/*
* Read and modify the summary information for a given extent size,
* Read and/or modify the summary information for a given extent size,
* bitmap block combination.
* Keeps track of a current summary block, so we don't keep reading
* it from the buffer cache.
*
* Summary information is returned in *sum if specified.
* If no delta is specified, returns summary only.
*/
int
xfs_rtmodify_summary(
xfs_mount_t *mp, /* file system mount point */
xfs_rtmodify_summary_int(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
int log, /* log2 of extent size */
xfs_rtblock_t bbno, /* bitmap block number */
int delta, /* change to make to summary info */
xfs_buf_t **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb) /* in/out: summary block number */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_suminfo_t *sum) /* out: summary info for this block */
{
xfs_buf_t *bp; /* buffer for the summary block */
int error; /* error value */
@ -456,7 +460,7 @@ xfs_rtmodify_summary(
/*
* If we have an old buffer, and the block number matches, use that.
*/
if (rbpp && *rbpp && *rsb == sb)
if (*rbpp && *rsb == sb)
bp = *rbpp;
/*
* Otherwise we have to get the buffer.
@ -465,7 +469,7 @@ xfs_rtmodify_summary(
/*
* If there was an old one, get rid of it first.
*/
if (rbpp && *rbpp)
if (*rbpp)
xfs_trans_brelse(tp, *rbpp);
error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
if (error) {
@ -474,21 +478,38 @@ xfs_rtmodify_summary(
/*
* Remember this buffer and block for the next call.
*/
if (rbpp) {
*rbpp = bp;
*rsb = sb;
}
*rbpp = bp;
*rsb = sb;
}
/*
* Point to the summary information, modify and log it.
* Point to the summary information, modify/log it, and/or copy it out.
*/
sp = XFS_SUMPTR(mp, bp, so);
*sp += delta;
xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr),
(uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1));
if (delta) {
uint first = (uint)((char *)sp - (char *)bp->b_addr);
*sp += delta;
xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
}
if (sum)
*sum = *sp;
return 0;
}
int
xfs_rtmodify_summary(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
int log, /* log2 of extent size */
xfs_rtblock_t bbno, /* bitmap block number */
int delta, /* change to make to summary info */
xfs_buf_t **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb) /* in/out: summary block number */
{
return xfs_rtmodify_summary_int(mp, tp, log, bbno,
delta, rbpp, rsb, NULL);
}
/*
* Set the given range of bitmap bits to the given value.
* Do whatever I/O and logging is required.

View File

@ -279,11 +279,13 @@ xfs_mount_validate_sb(
sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG ||
sbp->sb_blocksize != (1 << sbp->sb_blocklog) ||
sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG ||
sbp->sb_inodesize < XFS_DINODE_MIN_SIZE ||
sbp->sb_inodesize > XFS_DINODE_MAX_SIZE ||
sbp->sb_inodelog < XFS_DINODE_MIN_LOG ||
sbp->sb_inodelog > XFS_DINODE_MAX_LOG ||
sbp->sb_inodesize != (1 << sbp->sb_inodelog) ||
sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE ||
sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
(sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) ||
(sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||

View File

@ -1884,7 +1884,7 @@ xfs_buf_init(void)
goto out;
xfslogd_workqueue = alloc_workqueue("xfslogd",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
if (!xfslogd_workqueue)
goto out_free_buf_zone;

View File

@ -983,7 +983,7 @@ xfs_vm_page_mkwrite(
/*
* This type is designed to indicate the type of offset we would like
* to search from page cache for either xfs_seek_data() or xfs_seek_hole().
* to search from page cache for xfs_seek_hole_data().
*/
enum {
HOLE_OFF = 0,
@ -1040,7 +1040,7 @@ xfs_lookup_buffer_offset(
/*
* This routine is called to find out and return a data or hole offset
* from the page cache for unwritten extents according to the desired
* type for xfs_seek_data() or xfs_seek_hole().
* type for xfs_seek_hole_data().
*
* The argument offset is used to tell where we start to search from the
* page cache. Map is used to figure out the end points of the range to
@ -1200,110 +1200,10 @@ xfs_find_get_desired_pgoff(
}
STATIC loff_t
xfs_seek_data(
xfs_seek_hole_data(
struct file *file,
loff_t start)
{
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
loff_t uninitialized_var(offset);
xfs_fsize_t isize;
xfs_fileoff_t fsbno;
xfs_filblks_t end;
uint lock;
int error;
lock = xfs_ilock_data_map_shared(ip);
isize = i_size_read(inode);
if (start >= isize) {
error = -ENXIO;
goto out_unlock;
}
/*
* Try to read extents from the first block indicated
* by fsbno to the end block of the file.
*/
fsbno = XFS_B_TO_FSBT(mp, start);
end = XFS_B_TO_FSB(mp, isize);
for (;;) {
struct xfs_bmbt_irec map[2];
int nmap = 2;
unsigned int i;
error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
XFS_BMAPI_ENTIRE);
if (error)
goto out_unlock;
/* No extents at given offset, must be beyond EOF */
if (nmap == 0) {
error = -ENXIO;
goto out_unlock;
}
for (i = 0; i < nmap; i++) {
offset = max_t(loff_t, start,
XFS_FSB_TO_B(mp, map[i].br_startoff));
/* Landed in a data extent */
if (map[i].br_startblock == DELAYSTARTBLOCK ||
(map[i].br_state == XFS_EXT_NORM &&
!isnullstartblock(map[i].br_startblock)))
goto out;
/*
* Landed in an unwritten extent, try to search data
* from page cache.
*/
if (map[i].br_state == XFS_EXT_UNWRITTEN) {
if (xfs_find_get_desired_pgoff(inode, &map[i],
DATA_OFF, &offset))
goto out;
}
}
/*
* map[0] is hole or its an unwritten extent but
* without data in page cache. Probably means that
* we are reading after EOF if nothing in map[1].
*/
if (nmap == 1) {
error = -ENXIO;
goto out_unlock;
}
ASSERT(i > 1);
/*
* Nothing was found, proceed to the next round of search
* if reading offset not beyond or hit EOF.
*/
fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
start = XFS_FSB_TO_B(mp, fsbno);
if (start >= isize) {
error = -ENXIO;
goto out_unlock;
}
}
out:
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out_unlock:
xfs_iunlock(ip, lock);
if (error)
return error;
return offset;
}
STATIC loff_t
xfs_seek_hole(
struct file *file,
loff_t start)
loff_t start,
int whence)
{
struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
@ -1326,6 +1226,10 @@ xfs_seek_hole(
goto out_unlock;
}
/*
* Try to read extents from the first block indicated
* by fsbno to the end block of the file.
*/
fsbno = XFS_B_TO_FSBT(mp, start);
end = XFS_B_TO_FSB(mp, isize);
@ -1349,55 +1253,80 @@ xfs_seek_hole(
offset = max_t(loff_t, start,
XFS_FSB_TO_B(mp, map[i].br_startoff));
/* Landed in a hole */
if (map[i].br_startblock == HOLESTARTBLOCK)
/* Landed in the hole we wanted? */
if (whence == SEEK_HOLE &&
map[i].br_startblock == HOLESTARTBLOCK)
goto out;
/* Landed in the data extent we wanted? */
if (whence == SEEK_DATA &&
(map[i].br_startblock == DELAYSTARTBLOCK ||
(map[i].br_state == XFS_EXT_NORM &&
!isnullstartblock(map[i].br_startblock))))
goto out;
/*
* Landed in an unwritten extent, try to search hole
* from page cache.
* Landed in an unwritten extent, try to search
* for hole or data from page cache.
*/
if (map[i].br_state == XFS_EXT_UNWRITTEN) {
if (xfs_find_get_desired_pgoff(inode, &map[i],
HOLE_OFF, &offset))
whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF,
&offset))
goto out;
}
}
/*
* map[0] contains data or its unwritten but contains
* data in page cache, probably means that we are
* reading after EOF. We should fix offset to point
* to the end of the file(i.e., there is an implicit
* hole at the end of any file).
* We only received one extent out of the two requested. This
* means we've hit EOF and didn't find what we are looking for.
*/
if (nmap == 1) {
offset = isize;
break;
/*
* If we were looking for a hole, set offset to
* the end of the file (i.e., there is an implicit
* hole at the end of any file).
*/
if (whence == SEEK_HOLE) {
offset = isize;
break;
}
/*
* If we were looking for data, it's nowhere to be found
*/
ASSERT(whence == SEEK_DATA);
error = -ENXIO;
goto out_unlock;
}
ASSERT(i > 1);
/*
* Both mappings contains data, proceed to the next round of
* search if the current reading offset not beyond or hit EOF.
* Nothing was found, proceed to the next round of search
* if the next reading offset is not at or beyond EOF.
*/
fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
start = XFS_FSB_TO_B(mp, fsbno);
if (start >= isize) {
offset = isize;
break;
if (whence == SEEK_HOLE) {
offset = isize;
break;
}
ASSERT(whence == SEEK_DATA);
error = -ENXIO;
goto out_unlock;
}
}
out:
/*
* At this point, we must have found a hole. However, the returned
* If at this point we have found the hole we wanted, the returned
* offset may be bigger than the file size as it may be aligned to
* page boundary for unwritten extents, we need to deal with this
* page boundary for unwritten extents. We need to deal with this
* situation in particular.
*/
offset = min_t(loff_t, offset, isize);
if (whence == SEEK_HOLE)
offset = min_t(loff_t, offset, isize);
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out_unlock:
@ -1412,17 +1341,16 @@ STATIC loff_t
xfs_file_llseek(
struct file *file,
loff_t offset,
int origin)
int whence)
{
switch (origin) {
switch (whence) {
case SEEK_END:
case SEEK_CUR:
case SEEK_SET:
return generic_file_llseek(file, offset, origin);
case SEEK_DATA:
return xfs_seek_data(file, offset);
return generic_file_llseek(file, offset, whence);
case SEEK_HOLE:
return xfs_seek_hole(file, offset);
case SEEK_DATA:
return xfs_seek_hole_data(file, offset, whence);
default:
return -EINVAL;
}

View File

@ -43,3 +43,7 @@ xfs_param_t xfs_params = {
.fstrm_timer = { 1, 30*100, 3600*100},
.eofb_timer = { 1, 300, 3600*24},
};
struct xfs_globals xfs_globals = {
.log_recovery_delay = 0, /* no delay by default */
};

View File

@ -1153,9 +1153,11 @@ xfs_create(
if (error)
goto out_trans_cancel;
error = xfs_dir_canenter(tp, dp, name, resblks);
if (error)
goto out_trans_cancel;
if (!resblks) {
error = xfs_dir_canenter(tp, dp, name);
if (error)
goto out_trans_cancel;
}
/*
* A newly created regular or special file just has one directory
@ -1421,9 +1423,11 @@ xfs_link(
goto error_return;
}
error = xfs_dir_canenter(tp, tdp, target_name, resblks);
if (error)
goto error_return;
if (!resblks) {
error = xfs_dir_canenter(tp, tdp, target_name);
if (error)
goto error_return;
}
xfs_bmap_init(&free_list, &first_block);
@ -2759,9 +2763,11 @@ xfs_rename(
* If there's no space reservation, check the entry will
* fit before actually inserting it.
*/
error = xfs_dir_canenter(tp, target_dp, target_name, spaceres);
if (error)
goto error_return;
if (!spaceres) {
error = xfs_dir_canenter(tp, target_dp, target_name);
if (error)
goto error_return;
}
/*
* If target does not exist and the rename crosses
* directories, adjust the target directory link count

View File

@ -4132,41 +4132,13 @@ xlog_do_recovery_pass(
}
memset(rhash, 0, sizeof(rhash));
if (tail_blk <= head_blk) {
for (blk_no = tail_blk; blk_no < head_blk; ) {
error = xlog_bread(log, blk_no, hblks, hbp, &offset);
if (error)
goto bread_err2;
rhead = (xlog_rec_header_t *)offset;
error = xlog_valid_rec_header(log, rhead, blk_no);
if (error)
goto bread_err2;
/* blocks in data section */
bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
error = xlog_bread(log, blk_no + hblks, bblks, dbp,
&offset);
if (error)
goto bread_err2;
error = xlog_unpack_data(rhead, offset, log);
if (error)
goto bread_err2;
error = xlog_recover_process_data(log,
rhash, rhead, offset, pass);
if (error)
goto bread_err2;
blk_no += bblks + hblks;
}
} else {
blk_no = tail_blk;
if (tail_blk > head_blk) {
/*
* Perform recovery around the end of the physical log.
* When the head is not on the same cycle number as the tail,
* we can't do a sequential recovery as above.
* we can't do a sequential recovery.
*/
blk_no = tail_blk;
while (blk_no < log->l_logBBsize) {
/*
* Check for header wrapping around physical end-of-log
@ -4280,34 +4252,35 @@ xlog_do_recovery_pass(
ASSERT(blk_no >= log->l_logBBsize);
blk_no -= log->l_logBBsize;
}
/* read first part of physical log */
while (blk_no < head_blk) {
error = xlog_bread(log, blk_no, hblks, hbp, &offset);
if (error)
goto bread_err2;
/* read first part of physical log */
while (blk_no < head_blk) {
error = xlog_bread(log, blk_no, hblks, hbp, &offset);
if (error)
goto bread_err2;
rhead = (xlog_rec_header_t *)offset;
error = xlog_valid_rec_header(log, rhead, blk_no);
if (error)
goto bread_err2;
rhead = (xlog_rec_header_t *)offset;
error = xlog_valid_rec_header(log, rhead, blk_no);
if (error)
goto bread_err2;
bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
error = xlog_bread(log, blk_no+hblks, bblks, dbp,
&offset);
if (error)
goto bread_err2;
/* blocks in data section */
bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
error = xlog_bread(log, blk_no+hblks, bblks, dbp,
&offset);
if (error)
goto bread_err2;
error = xlog_unpack_data(rhead, offset, log);
if (error)
goto bread_err2;
error = xlog_unpack_data(rhead, offset, log);
if (error)
goto bread_err2;
error = xlog_recover_process_data(log, rhash,
rhead, offset, pass);
if (error)
goto bread_err2;
blk_no += bblks + hblks;
}
error = xlog_recover_process_data(log, rhash,
rhead, offset, pass);
if (error)
goto bread_err2;
blk_no += bblks + hblks;
}
bread_err2:
@ -4509,6 +4482,18 @@ xlog_recover(
return -EINVAL;
}
/*
* Delay log recovery if the debug hook is set. This is debug
* instrumention to coordinate simulation of I/O failures with
* log recovery.
*/
if (xfs_globals.log_recovery_delay) {
xfs_notice(log->l_mp,
"Delaying log recovery for %d seconds.",
xfs_globals.log_recovery_delay);
msleep(xfs_globals.log_recovery_delay * 1000);
}
xfs_notice(log->l_mp, "Starting recovery (logdev: %s)",
log->l_mp->m_logname ? log->l_mp->m_logname
: "internal");

View File

@ -304,7 +304,8 @@ _xfs_mru_cache_reap(
int
xfs_mru_cache_init(void)
{
xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);
xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache",
WQ_MEM_RECLAIM|WQ_FREEZABLE, 1);
if (!xfs_mru_reap_wq)
return -ENOMEM;
return 0;

View File

@ -46,7 +46,7 @@
* Keeps track of a current summary block, so we don't keep reading
* it from the buffer cache.
*/
STATIC int /* error */
int
xfs_rtget_summary(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
@ -56,60 +56,9 @@ xfs_rtget_summary(
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_suminfo_t *sum) /* out: summary info for this block */
{
xfs_buf_t *bp; /* buffer for summary block */
int error; /* error value */
xfs_fsblock_t sb; /* summary fsblock */
int so; /* index into the summary file */
xfs_suminfo_t *sp; /* pointer to returned data */
/*
* Compute entry number in the summary file.
*/
so = XFS_SUMOFFS(mp, log, bbno);
/*
* Compute the block number in the summary file.
*/
sb = XFS_SUMOFFSTOBLOCK(mp, so);
/*
* If we have an old buffer, and the block number matches, use that.
*/
if (rbpp && *rbpp && *rsb == sb)
bp = *rbpp;
/*
* Otherwise we have to get the buffer.
*/
else {
/*
* If there was an old one, get rid of it first.
*/
if (rbpp && *rbpp)
xfs_trans_brelse(tp, *rbpp);
error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
if (error) {
return error;
}
/*
* Remember this buffer and block for the next call.
*/
if (rbpp) {
*rbpp = bp;
*rsb = sb;
}
}
/*
* Point to the summary information & copy it out.
*/
sp = XFS_SUMPTR(mp, bp, so);
*sum = *sp;
/*
* Drop the buffer if we're not asked to remember it.
*/
if (!rbpp)
xfs_trans_brelse(tp, bp);
return 0;
return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
}
/*
* Return whether there are any free extents in the size range given
* by low and high, for the bitmap block bbno.

View File

@ -111,6 +111,10 @@ int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t *rtblock);
int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_extlen_t len, int val);
int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp,
int log, xfs_rtblock_t bbno, int delta,
xfs_buf_t **rbpp, xfs_fsblock_t *rsb,
xfs_suminfo_t *sum);
int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log,
xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp,
xfs_fsblock_t *rsb);

View File

@ -47,6 +47,7 @@
#include "xfs_dinode.h"
#include "xfs_filestream.h"
#include "xfs_quota.h"
#include "xfs_sysfs.h"
#include <linux/namei.h>
#include <linux/init.h>
@ -61,7 +62,11 @@
static const struct super_operations xfs_super_operations;
static kmem_zone_t *xfs_ioend_zone;
mempool_t *xfs_ioend_pool;
struct kset *xfs_kset;
struct kset *xfs_kset; /* top-level xfs sysfs dir */
#ifdef DEBUG
static struct xfs_kobj xfs_dbg_kobj; /* global debug sysfs attrs */
#endif
#define MNTOPT_LOGBUFS "logbufs" /* number of XFS log buffers */
#define MNTOPT_LOGBSIZE "logbsize" /* size of XFS log buffers */
@ -838,32 +843,32 @@ xfs_init_mount_workqueues(
struct xfs_mount *mp)
{
mp->m_data_workqueue = alloc_workqueue("xfs-data/%s",
WQ_MEM_RECLAIM, 0, mp->m_fsname);
WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_data_workqueue)
goto out;
mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
WQ_MEM_RECLAIM, 0, mp->m_fsname);
WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_unwritten_workqueue)
goto out_destroy_data_iodone_queue;
mp->m_cil_workqueue = alloc_workqueue("xfs-cil/%s",
WQ_MEM_RECLAIM, 0, mp->m_fsname);
WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_cil_workqueue)
goto out_destroy_unwritten;
mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
0, 0, mp->m_fsname);
WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_reclaim_workqueue)
goto out_destroy_cil;
mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
0, 0, mp->m_fsname);
WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_log_workqueue)
goto out_destroy_reclaim;
mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
0, 0, mp->m_fsname);
WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_eofblocks_workqueue)
goto out_destroy_log;
@ -1715,7 +1720,8 @@ xfs_init_workqueues(void)
* AGs in all the filesystems mounted. Hence use the default large
* max_active value for this workqueue.
*/
xfs_alloc_wq = alloc_workqueue("xfsalloc", WQ_MEM_RECLAIM, 0);
xfs_alloc_wq = alloc_workqueue("xfsalloc",
WQ_MEM_RECLAIM|WQ_FREEZABLE, 0);
if (!xfs_alloc_wq)
return -ENOMEM;
@ -1768,9 +1774,16 @@ init_xfs_fs(void)
goto out_sysctl_unregister;;
}
error = xfs_qm_init();
#ifdef DEBUG
xfs_dbg_kobj.kobject.kset = xfs_kset;
error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
if (error)
goto out_kset_unregister;
#endif
error = xfs_qm_init();
if (error)
goto out_remove_kobj;
error = register_filesystem(&xfs_fs_type);
if (error)
@ -1779,7 +1792,11 @@ init_xfs_fs(void)
out_qm_exit:
xfs_qm_exit();
out_remove_kobj:
#ifdef DEBUG
xfs_sysfs_del(&xfs_dbg_kobj);
out_kset_unregister:
#endif
kset_unregister(xfs_kset);
out_sysctl_unregister:
xfs_sysctl_unregister();
@ -1802,6 +1819,9 @@ exit_xfs_fs(void)
{
xfs_qm_exit();
unregister_filesystem(&xfs_fs_type);
#ifdef DEBUG
xfs_sysfs_del(&xfs_dbg_kobj);
#endif
kset_unregister(xfs_kset);
xfs_sysctl_unregister();
xfs_cleanup_procfs();

View File

@ -269,9 +269,11 @@ xfs_symlink(
/*
* Check for ability to enter directory entry, if no space reserved.
*/
error = xfs_dir_canenter(tp, dp, link_name, resblks);
if (error)
goto error_return;
if (!resblks) {
error = xfs_dir_canenter(tp, dp, link_name);
if (error)
goto error_return;
}
/*
* Initialize the bmap freelist prior to calling either
* bmapi or the directory create code.

View File

@ -92,6 +92,11 @@ enum {
extern xfs_param_t xfs_params;
struct xfs_globals {
int log_recovery_delay; /* log recovery delay (secs) */
};
extern struct xfs_globals xfs_globals;
#ifdef CONFIG_SYSCTL
extern int xfs_sysctl_register(void);
extern void xfs_sysctl_unregister(void);

View File

@ -51,6 +51,80 @@ struct kobj_type xfs_mp_ktype = {
.release = xfs_sysfs_release,
};
#ifdef DEBUG
/* debug */
STATIC ssize_t
log_recovery_delay_store(
const char *buf,
size_t count,
void *data)
{
int ret;
int val;
ret = kstrtoint(buf, 0, &val);
if (ret)
return ret;
if (val < 0 || val > 60)
return -EINVAL;
xfs_globals.log_recovery_delay = val;
return count;
}
STATIC ssize_t
log_recovery_delay_show(
char *buf,
void *data)
{
return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.log_recovery_delay);
}
XFS_SYSFS_ATTR_RW(log_recovery_delay);
static struct attribute *xfs_dbg_attrs[] = {
ATTR_LIST(log_recovery_delay),
NULL,
};
STATIC ssize_t
xfs_dbg_show(
struct kobject *kobject,
struct attribute *attr,
char *buf)
{
struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
return xfs_attr->show ? xfs_attr->show(buf, NULL) : 0;
}
STATIC ssize_t
xfs_dbg_store(
struct kobject *kobject,
struct attribute *attr,
const char *buf,
size_t count)
{
struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
return xfs_attr->store ? xfs_attr->store(buf, count, NULL) : 0;
}
static struct sysfs_ops xfs_dbg_ops = {
.show = xfs_dbg_show,
.store = xfs_dbg_store,
};
struct kobj_type xfs_dbg_ktype = {
.release = xfs_sysfs_release,
.sysfs_ops = &xfs_dbg_ops,
.default_attrs = xfs_dbg_attrs,
};
#endif /* DEBUG */
/* xlog */
STATIC ssize_t

View File

@ -20,6 +20,7 @@
#define __XFS_SYSFS_H__
extern struct kobj_type xfs_mp_ktype; /* xfs_mount */
extern struct kobj_type xfs_dbg_ktype; /* debug */
extern struct kobj_type xfs_log_ktype; /* xlog */
static inline struct xfs_kobj *