Merge branch 'xfs-misc-fixes-for-3.18-1' into for-next
This commit is contained in:
commit
a4241aebe9
|
@ -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
|
||||
|
|
|
@ -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 @@ out_free:
|
|||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 @@ out:
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Reference in New Issue