提交 5c8ed202 编写于 作者: D Dave Chinner 提交者: Alex Elder

xfs: introduce xfs_bmapi_read()

xfs_bmapi() currently handles both extent map reading and
allocation. As a result, the code is littered with "if (wr)"
branches to conditionally do allocation operations if required.
This makes the code much harder to follow and causes significant
indent issues with the code.

Given that read mapping is much simpler than allocation, we can
split out read mapping from xfs_bmapi() and reuse the logic that
we have already factored out do do all the hard work of handling the
extent map manipulations. The results in a much simpler function for
the common extent read operations, and will allow the allocation
code to be simplified in another commit.

Once xfs_bmapi_read() is implemented, convert all the callers of
xfs_bmapi() that are only reading extents to use the new function.
Signed-off-by: NDave Chinner <dchinner@redhat.com>
Signed-off-by: NChristoph Hellwig <hch@lst.de>
Signed-off-by: NAlex Elder <aelder@sgi.com>
上级 aef9a895
...@@ -315,8 +315,8 @@ xfs_map_blocks( ...@@ -315,8 +315,8 @@ xfs_map_blocks(
count = mp->m_maxioffset - offset; count = mp->m_maxioffset - offset;
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
offset_fsb = XFS_B_TO_FSBT(mp, offset); offset_fsb = XFS_B_TO_FSBT(mp, offset);
error = xfs_bmapi(NULL, ip, offset_fsb, end_fsb - offset_fsb, error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
bmapi_flags, NULL, 0, imap, &nimaps, NULL); imap, &nimaps, bmapi_flags);
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (error) if (error)
...@@ -1138,8 +1138,8 @@ __xfs_get_blocks( ...@@ -1138,8 +1138,8 @@ __xfs_get_blocks(
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size); end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
offset_fsb = XFS_B_TO_FSBT(mp, offset); offset_fsb = XFS_B_TO_FSBT(mp, offset);
error = xfs_bmapi(NULL, ip, offset_fsb, end_fsb - offset_fsb, error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
XFS_BMAPI_ENTIRE, NULL, 0, &imap, &nimaps, NULL); &imap, &nimaps, XFS_BMAPI_ENTIRE);
if (error) if (error)
goto out_unlock; goto out_unlock;
......
...@@ -1963,10 +1963,9 @@ xfs_attr_rmtval_get(xfs_da_args_t *args) ...@@ -1963,10 +1963,9 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
lblkno = args->rmtblkno; lblkno = args->rmtblkno;
while (valuelen > 0) { while (valuelen > 0) {
nmap = ATTR_RMTVALUE_MAPSIZE; nmap = ATTR_RMTVALUE_MAPSIZE;
error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
args->rmtblkcnt, args->rmtblkcnt, map, &nmap,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, XFS_BMAPI_ATTRFORK);
NULL, 0, map, &nmap, NULL);
if (error) if (error)
return(error); return(error);
ASSERT(nmap >= 1); ASSERT(nmap >= 1);
...@@ -2092,14 +2091,11 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) ...@@ -2092,14 +2091,11 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
*/ */
xfs_bmap_init(args->flist, args->firstblock); xfs_bmap_init(args->flist, args->firstblock);
nmap = 1; nmap = 1;
error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
args->rmtblkcnt, args->rmtblkcnt, &map, &nmap,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, XFS_BMAPI_ATTRFORK);
args->firstblock, 0, &map, &nmap, if (error)
NULL);
if (error) {
return(error); return(error);
}
ASSERT(nmap == 1); ASSERT(nmap == 1);
ASSERT((map.br_startblock != DELAYSTARTBLOCK) && ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
(map.br_startblock != HOLESTARTBLOCK)); (map.br_startblock != HOLESTARTBLOCK));
...@@ -2155,16 +2151,12 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) ...@@ -2155,16 +2151,12 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
/* /*
* Try to remember where we decided to put the value. * Try to remember where we decided to put the value.
*/ */
xfs_bmap_init(args->flist, args->firstblock);
nmap = 1; nmap = 1;
error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno, error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
args->rmtblkcnt, args->rmtblkcnt, &map, &nmap,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, XFS_BMAPI_ATTRFORK);
args->firstblock, 0, &map, &nmap, if (error)
args->flist);
if (error) {
return(error); return(error);
}
ASSERT(nmap == 1); ASSERT(nmap == 1);
ASSERT((map.br_startblock != DELAYSTARTBLOCK) && ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
(map.br_startblock != HOLESTARTBLOCK)); (map.br_startblock != HOLESTARTBLOCK));
......
...@@ -2926,9 +2926,8 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, ...@@ -2926,9 +2926,8 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
* Try to remember where we decided to put the value. * Try to remember where we decided to put the value.
*/ */
nmap = 1; nmap = 1;
error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt, error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt,
XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, &map, &nmap, XFS_BMAPI_ATTRFORK);
NULL, 0, &map, &nmap, NULL);
if (error) { if (error) {
return(error); return(error);
} }
......
...@@ -4349,6 +4349,98 @@ xfs_bmapi_update_map( ...@@ -4349,6 +4349,98 @@ xfs_bmapi_update_map(
*map = mval; *map = mval;
} }
/*
* Map file blocks to filesystem blocks without allocation.
*/
int
xfs_bmapi_read(
struct xfs_inode *ip,
xfs_fileoff_t bno,
xfs_filblks_t len,
struct xfs_bmbt_irec *mval,
int *nmap,
int flags)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_ifork *ifp;
struct xfs_bmbt_irec got;
struct xfs_bmbt_irec prev;
xfs_fileoff_t obno;
xfs_fileoff_t end;
xfs_extnum_t lastx;
int error;
int eof;
int n = 0;
int whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
ASSERT(*nmap >= 1);
ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE|
XFS_BMAPI_IGSTATE)));
if (unlikely(XFS_TEST_ERROR(
(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
return XFS_ERROR(EFSCORRUPTED);
}
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
XFS_STATS_INC(xs_blk_mapr);
ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT(ifp->if_ext_max ==
XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
if (!(ifp->if_flags & XFS_IFEXTENTS)) {
error = xfs_iread_extents(NULL, ip, whichfork);
if (error)
return error;
}
xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev);
end = bno + len;
obno = bno;
while (bno < end && n < *nmap) {
/* Reading past eof, act as though there's a hole up to end. */
if (eof)
got.br_startoff = end;
if (got.br_startoff > bno) {
/* Reading in a hole. */
mval->br_startoff = bno;
mval->br_startblock = HOLESTARTBLOCK;
mval->br_blockcount =
XFS_FILBLKS_MIN(len, got.br_startoff - bno);
mval->br_state = XFS_EXT_NORM;
bno += mval->br_blockcount;
len -= mval->br_blockcount;
mval++;
n++;
continue;
}
/* set up the extent map to return. */
xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags);
xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags);
/* If we're done, stop now. */
if (bno >= end || n >= *nmap)
break;
/* Else go on to the next record. */
if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t))
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got);
else
eof = 1;
}
*nmap = n;
return 0;
}
/* /*
* Map file blocks to filesystem blocks. * Map file blocks to filesystem blocks.
* File range is given by the bno/len pair. * File range is given by the bno/len pair.
...@@ -5490,10 +5582,9 @@ xfs_getbmap( ...@@ -5490,10 +5582,9 @@ xfs_getbmap(
do { do {
nmap = (nexleft > subnex) ? subnex : nexleft; nmap = (nexleft > subnex) ? subnex : nexleft;
error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
XFS_BB_TO_FSB(mp, bmv->bmv_length), XFS_BB_TO_FSB(mp, bmv->bmv_length),
bmapi_flags, NULL, 0, map, &nmap, map, &nmap, bmapi_flags);
NULL);
if (error) if (error)
goto out_free_map; goto out_free_map;
ASSERT(nmap <= subnex); ASSERT(nmap <= subnex);
...@@ -6084,9 +6175,8 @@ xfs_bmap_punch_delalloc_range( ...@@ -6084,9 +6175,8 @@ xfs_bmap_punch_delalloc_range(
* trying to remove a real extent (which requires a * trying to remove a real extent (which requires a
* transaction) or a hole, which is probably a bad idea... * transaction) or a hole, which is probably a bad idea...
*/ */
error = xfs_bmapi(NULL, ip, start_fsb, 1, error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
XFS_BMAPI_ENTIRE, NULL, 0, &imap, XFS_BMAPI_ENTIRE);
&nimaps, NULL);
if (error) { if (error) {
/* something screwed, just bail */ /* something screwed, just bail */
......
...@@ -294,6 +294,10 @@ xfs_bmapi( ...@@ -294,6 +294,10 @@ xfs_bmapi(
int *nmap, /* i/o: mval size/count */ int *nmap, /* i/o: mval size/count */
xfs_bmap_free_t *flist); /* i/o: list extents to free */ xfs_bmap_free_t *flist); /* i/o: list extents to free */
int xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno,
xfs_filblks_t len, struct xfs_bmbt_irec *mval,
int *nmap, int flags);
/* /*
* Map file blocks to filesystem blocks, simple version. * Map file blocks to filesystem blocks, simple version.
* One block only, read-only. * One block only, read-only.
......
...@@ -1995,11 +1995,10 @@ xfs_da_do_buf( ...@@ -1995,11 +1995,10 @@ xfs_da_do_buf(
} else { } else {
mapp = kmem_alloc(sizeof(*mapp) * nfsb, KM_SLEEP); mapp = kmem_alloc(sizeof(*mapp) * nfsb, KM_SLEEP);
nmap = nfsb; nmap = nfsb;
if ((error = xfs_bmapi(trans, dp, (xfs_fileoff_t)bno, error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb,
nfsb, mapp, &nmap,
XFS_BMAPI_METADATA | xfs_bmapi_aflag(whichfork));
xfs_bmapi_aflag(whichfork), if (error)
NULL, 0, mapp, &nmap, NULL)))
goto exit0; goto exit0;
} }
} else { } else {
......
...@@ -888,12 +888,10 @@ xfs_dir2_leaf_getdents( ...@@ -888,12 +888,10 @@ xfs_dir2_leaf_getdents(
* we already have in the table. * we already have in the table.
*/ */
nmap = map_size - map_valid; nmap = map_size - map_valid;
error = xfs_bmapi(NULL, dp, error = xfs_bmapi_read(dp, map_off,
map_off,
xfs_dir2_byte_to_da(mp, xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET) - map_off, XFS_DIR2_LEAF_OFFSET) - map_off,
XFS_BMAPI_METADATA, NULL, 0, &map[map_valid], &nmap, 0);
&map[map_valid], &nmap, NULL);
/* /*
* Don't know if we should ignore this or * Don't know if we should ignore this or
* try to return an error. * try to return an error.
......
...@@ -488,9 +488,8 @@ xfs_qm_dqtobp( ...@@ -488,9 +488,8 @@ xfs_qm_dqtobp(
/* /*
* Find the block map; no allocations yet * Find the block map; no allocations yet
*/ */
error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, error = xfs_bmapi_read(quotip, dqp->q_fileoffset,
XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA, XFS_DQUOT_CLUSTER_SIZE_FSB, &map, &nmaps, 0);
NULL, 0, &map, &nmaps, NULL);
xfs_iunlock(quotip, XFS_ILOCK_SHARED); xfs_iunlock(quotip, XFS_ILOCK_SHARED);
if (error) if (error)
......
...@@ -509,11 +509,9 @@ xfs_zero_last_block( ...@@ -509,11 +509,9 @@ xfs_zero_last_block(
last_fsb = XFS_B_TO_FSBT(mp, isize); last_fsb = XFS_B_TO_FSBT(mp, isize);
nimaps = 1; nimaps = 1;
error = xfs_bmapi(NULL, ip, last_fsb, 1, 0, NULL, 0, &imap, error = xfs_bmapi_read(ip, last_fsb, 1, &imap, &nimaps, 0);
&nimaps, NULL); if (error)
if (error) {
return error; return error;
}
ASSERT(nimaps > 0); ASSERT(nimaps > 0);
/* /*
* If the block underlying isize is just a hole, then there * If the block underlying isize is just a hole, then there
...@@ -604,8 +602,8 @@ xfs_zero_eof( ...@@ -604,8 +602,8 @@ xfs_zero_eof(
while (start_zero_fsb <= end_zero_fsb) { while (start_zero_fsb <= end_zero_fsb) {
nimaps = 1; nimaps = 1;
zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb, error = xfs_bmapi_read(ip, start_zero_fsb, zero_count_fsb,
0, NULL, 0, &imap, &nimaps, NULL); &imap, &nimaps, 0);
if (error) { if (error) {
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
return error; return error;
......
...@@ -1187,6 +1187,7 @@ xfs_isize_check( ...@@ -1187,6 +1187,7 @@ xfs_isize_check(
xfs_fileoff_t map_first; xfs_fileoff_t map_first;
int nimaps; int nimaps;
xfs_bmbt_irec_t imaps[2]; xfs_bmbt_irec_t imaps[2];
int error;
if (!S_ISREG(ip->i_d.di_mode)) if (!S_ISREG(ip->i_d.di_mode))
return; return;
...@@ -1203,13 +1204,12 @@ xfs_isize_check( ...@@ -1203,13 +1204,12 @@ xfs_isize_check(
* The filesystem could be shutting down, so bmapi may return * The filesystem could be shutting down, so bmapi may return
* an error. * an error.
*/ */
if (xfs_bmapi(NULL, ip, map_first, error = xfs_bmapi_read(ip, map_first,
(XFS_B_TO_FSB(mp, (XFS_B_TO_FSB(mp,
(xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first),
map_first), imaps, &nimaps, XFS_BMAPI_ENTIRE);
XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps, if (error)
NULL)) return;
return;
ASSERT(nimaps == 1); ASSERT(nimaps == 1);
ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
} }
......
...@@ -300,8 +300,8 @@ xfs_iomap_eof_want_preallocate( ...@@ -300,8 +300,8 @@ xfs_iomap_eof_want_preallocate(
while (count_fsb > 0) { while (count_fsb > 0) {
imaps = nimaps; imaps = nimaps;
firstblock = NULLFSBLOCK; firstblock = NULLFSBLOCK;
error = xfs_bmapi(NULL, ip, start_fsb, count_fsb, 0, error = xfs_bmapi_read(ip, start_fsb, count_fsb, imap, &imaps,
&firstblock, 0, imap, &imaps, NULL); 0);
if (error) if (error)
return error; return error;
for (n = 0; n < imaps; n++) { for (n = 0; n < imaps; n++) {
......
...@@ -1347,11 +1347,8 @@ xfs_qm_dqiterate( ...@@ -1347,11 +1347,8 @@ xfs_qm_dqiterate(
* the inode is never added to the transaction. * the inode is never added to the transaction.
*/ */
xfs_ilock(qip, XFS_ILOCK_SHARED); xfs_ilock(qip, XFS_ILOCK_SHARED);
error = xfs_bmapi(NULL, qip, lblkno, error = xfs_bmapi_read(qip, lblkno, maxlblkcnt - lblkno,
maxlblkcnt - lblkno, map, &nmaps, 0);
XFS_BMAPI_METADATA,
NULL,
0, map, &nmaps, NULL);
xfs_iunlock(qip, XFS_ILOCK_SHARED); xfs_iunlock(qip, XFS_ILOCK_SHARED);
if (error) if (error)
break; break;
......
...@@ -72,8 +72,8 @@ xfs_readlink_bmap( ...@@ -72,8 +72,8 @@ xfs_readlink_bmap(
xfs_buf_t *bp; xfs_buf_t *bp;
int error = 0; int error = 0;
error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0, error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, pathlen), mval, &nmaps,
mval, &nmaps, NULL); 0);
if (error) if (error)
goto out; goto out;
...@@ -178,8 +178,7 @@ xfs_free_eofblocks( ...@@ -178,8 +178,7 @@ xfs_free_eofblocks(
nimaps = 1; nimaps = 1;
xfs_ilock(ip, XFS_ILOCK_SHARED); xfs_ilock(ip, XFS_ILOCK_SHARED);
error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
NULL, 0, &imap, &nimaps, NULL);
xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iunlock(ip, XFS_ILOCK_SHARED);
if (!error && (nimaps != 0) && if (!error && (nimaps != 0) &&
...@@ -297,9 +296,9 @@ xfs_inactive_symlink_rmt( ...@@ -297,9 +296,9 @@ xfs_inactive_symlink_rmt(
done = 0; done = 0;
xfs_bmap_init(&free_list, &first_block); xfs_bmap_init(&free_list, &first_block);
nmaps = ARRAY_SIZE(mval); nmaps = ARRAY_SIZE(mval);
if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, size),
XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, mval, &nmaps, 0);
&free_list))) if (error)
goto error0; goto error0;
/* /*
* Invalidate the block(s). * Invalidate the block(s).
...@@ -1981,8 +1980,7 @@ xfs_zero_remaining_bytes( ...@@ -1981,8 +1980,7 @@ xfs_zero_remaining_bytes(
for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
offset_fsb = XFS_B_TO_FSBT(mp, offset); offset_fsb = XFS_B_TO_FSBT(mp, offset);
nimap = 1; nimap = 1;
error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, error = xfs_bmapi_read(ip, offset_fsb, 1, &imap, &nimap, 0);
NULL, 0, &imap, &nimap, NULL);
if (error || nimap < 1) if (error || nimap < 1)
break; break;
ASSERT(imap.br_blockcount >= 1); ASSERT(imap.br_blockcount >= 1);
...@@ -2101,8 +2099,8 @@ xfs_free_file_space( ...@@ -2101,8 +2099,8 @@ xfs_free_file_space(
*/ */
if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
nimap = 1; nimap = 1;
error = xfs_bmapi(NULL, ip, startoffset_fsb, error = xfs_bmapi_read(ip, startoffset_fsb, 1,
1, 0, NULL, 0, &imap, &nimap, NULL); &imap, &nimap, 0);
if (error) if (error)
goto out_unlock_iolock; goto out_unlock_iolock;
ASSERT(nimap == 0 || nimap == 1); ASSERT(nimap == 0 || nimap == 1);
...@@ -2116,8 +2114,8 @@ xfs_free_file_space( ...@@ -2116,8 +2114,8 @@ xfs_free_file_space(
startoffset_fsb += mp->m_sb.sb_rextsize - mod; startoffset_fsb += mp->m_sb.sb_rextsize - mod;
} }
nimap = 1; nimap = 1;
error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
1, 0, NULL, 0, &imap, &nimap, NULL); &imap, &nimap, 0);
if (error) if (error)
goto out_unlock_iolock; goto out_unlock_iolock;
ASSERT(nimap == 0 || nimap == 1); ASSERT(nimap == 0 || nimap == 1);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册