aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2_leaf.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-08-12 06:49:36 -0400
committerBen Myers <bpm@sgi.com>2013-08-12 17:39:56 -0400
commit4a8af273de63d9656559ba5289e91f40aae0441f (patch)
treeac3d22e894df58c38326bada04073d283c90dee5 /fs/xfs/xfs_dir2_leaf.c
parent1fd7115eda5661e872463694fc4a12821c4f914a (diff)
xfs: move getdents code into it's own file
The directory readdir code is not used by userspace, but it is intermingled with files that are shared with userspace. This makes it difficult to compare the differences between the userspac eand kernel files are the userspace files don't have the getdents code in them. Move all the kernel getdents code to a separate file to bring the shared content between userspace and kernel files closer together. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_dir2_leaf.c')
-rw-r--r--fs/xfs/xfs_dir2_leaf.c390
1 files changed, 0 insertions, 390 deletions
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 2aed25cae04d..e1386aabb690 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -1083,396 +1083,6 @@ xfs_dir3_leaf_compact_x1(
1083 *highstalep = highstale; 1083 *highstalep = highstale;
1084} 1084}
1085 1085
1086struct xfs_dir2_leaf_map_info {
1087 xfs_extlen_t map_blocks; /* number of fsbs in map */
1088 xfs_dablk_t map_off; /* last mapped file offset */
1089 int map_size; /* total entries in *map */
1090 int map_valid; /* valid entries in *map */
1091 int nmap; /* mappings to ask xfs_bmapi */
1092 xfs_dir2_db_t curdb; /* db for current block */
1093 int ra_current; /* number of read-ahead blks */
1094 int ra_index; /* *map index for read-ahead */
1095 int ra_offset; /* map entry offset for ra */
1096 int ra_want; /* readahead count wanted */
1097 struct xfs_bmbt_irec map[]; /* map vector for blocks */
1098};
1099
1100STATIC int
1101xfs_dir2_leaf_readbuf(
1102 struct xfs_inode *dp,
1103 size_t bufsize,
1104 struct xfs_dir2_leaf_map_info *mip,
1105 xfs_dir2_off_t *curoff,
1106 struct xfs_buf **bpp)
1107{
1108 struct xfs_mount *mp = dp->i_mount;
1109 struct xfs_buf *bp = *bpp;
1110 struct xfs_bmbt_irec *map = mip->map;
1111 struct blk_plug plug;
1112 int error = 0;
1113 int length;
1114 int i;
1115 int j;
1116
1117 /*
1118 * If we have a buffer, we need to release it and
1119 * take it out of the mapping.
1120 */
1121
1122 if (bp) {
1123 xfs_trans_brelse(NULL, bp);
1124 bp = NULL;
1125 mip->map_blocks -= mp->m_dirblkfsbs;
1126 /*
1127 * Loop to get rid of the extents for the
1128 * directory block.
1129 */
1130 for (i = mp->m_dirblkfsbs; i > 0; ) {
1131 j = min_t(int, map->br_blockcount, i);
1132 map->br_blockcount -= j;
1133 map->br_startblock += j;
1134 map->br_startoff += j;
1135 /*
1136 * If mapping is done, pitch it from
1137 * the table.
1138 */
1139 if (!map->br_blockcount && --mip->map_valid)
1140 memmove(&map[0], &map[1],
1141 sizeof(map[0]) * mip->map_valid);
1142 i -= j;
1143 }
1144 }
1145
1146 /*
1147 * Recalculate the readahead blocks wanted.
1148 */
1149 mip->ra_want = howmany(bufsize + mp->m_dirblksize,
1150 mp->m_sb.sb_blocksize) - 1;
1151 ASSERT(mip->ra_want >= 0);
1152
1153 /*
1154 * If we don't have as many as we want, and we haven't
1155 * run out of data blocks, get some more mappings.
1156 */
1157 if (1 + mip->ra_want > mip->map_blocks &&
1158 mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
1159 /*
1160 * Get more bmaps, fill in after the ones
1161 * we already have in the table.
1162 */
1163 mip->nmap = mip->map_size - mip->map_valid;
1164 error = xfs_bmapi_read(dp, mip->map_off,
1165 xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
1166 mip->map_off,
1167 &map[mip->map_valid], &mip->nmap, 0);
1168
1169 /*
1170 * Don't know if we should ignore this or try to return an
1171 * error. The trouble with returning errors is that readdir
1172 * will just stop without actually passing the error through.
1173 */
1174 if (error)
1175 goto out; /* XXX */
1176
1177 /*
1178 * If we got all the mappings we asked for, set the final map
1179 * offset based on the last bmap value received. Otherwise,
1180 * we've reached the end.
1181 */
1182 if (mip->nmap == mip->map_size - mip->map_valid) {
1183 i = mip->map_valid + mip->nmap - 1;
1184 mip->map_off = map[i].br_startoff + map[i].br_blockcount;
1185 } else
1186 mip->map_off = xfs_dir2_byte_to_da(mp,
1187 XFS_DIR2_LEAF_OFFSET);
1188
1189 /*
1190 * Look for holes in the mapping, and eliminate them. Count up
1191 * the valid blocks.
1192 */
1193 for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) {
1194 if (map[i].br_startblock == HOLESTARTBLOCK) {
1195 mip->nmap--;
1196 length = mip->map_valid + mip->nmap - i;
1197 if (length)
1198 memmove(&map[i], &map[i + 1],
1199 sizeof(map[i]) * length);
1200 } else {
1201 mip->map_blocks += map[i].br_blockcount;
1202 i++;
1203 }
1204 }
1205 mip->map_valid += mip->nmap;
1206 }
1207
1208 /*
1209 * No valid mappings, so no more data blocks.
1210 */
1211 if (!mip->map_valid) {
1212 *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
1213 goto out;
1214 }
1215
1216 /*
1217 * Read the directory block starting at the first mapping.
1218 */
1219 mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
1220 error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
1221 map->br_blockcount >= mp->m_dirblkfsbs ?
1222 XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
1223
1224 /*
1225 * Should just skip over the data block instead of giving up.
1226 */
1227 if (error)
1228 goto out; /* XXX */
1229
1230 /*
1231 * Adjust the current amount of read-ahead: we just read a block that
1232 * was previously ra.
1233 */
1234 if (mip->ra_current)
1235 mip->ra_current -= mp->m_dirblkfsbs;
1236
1237 /*
1238 * Do we need more readahead?
1239 */
1240 blk_start_plug(&plug);
1241 for (mip->ra_index = mip->ra_offset = i = 0;
1242 mip->ra_want > mip->ra_current && i < mip->map_blocks;
1243 i += mp->m_dirblkfsbs) {
1244 ASSERT(mip->ra_index < mip->map_valid);
1245 /*
1246 * Read-ahead a contiguous directory block.
1247 */
1248 if (i > mip->ra_current &&
1249 map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
1250 xfs_dir3_data_readahead(NULL, dp,
1251 map[mip->ra_index].br_startoff + mip->ra_offset,
1252 XFS_FSB_TO_DADDR(mp,
1253 map[mip->ra_index].br_startblock +
1254 mip->ra_offset));
1255 mip->ra_current = i;
1256 }
1257
1258 /*
1259 * Read-ahead a non-contiguous directory block. This doesn't
1260 * use our mapping, but this is a very rare case.
1261 */
1262 else if (i > mip->ra_current) {
1263 xfs_dir3_data_readahead(NULL, dp,
1264 map[mip->ra_index].br_startoff +
1265 mip->ra_offset, -1);
1266 mip->ra_current = i;
1267 }
1268
1269 /*
1270 * Advance offset through the mapping table.
1271 */
1272 for (j = 0; j < mp->m_dirblkfsbs; j++) {
1273 /*
1274 * The rest of this extent but not more than a dir
1275 * block.
1276 */
1277 length = min_t(int, mp->m_dirblkfsbs,
1278 map[mip->ra_index].br_blockcount -
1279 mip->ra_offset);
1280 j += length;
1281 mip->ra_offset += length;
1282
1283 /*
1284 * Advance to the next mapping if this one is used up.
1285 */
1286 if (mip->ra_offset == map[mip->ra_index].br_blockcount) {
1287 mip->ra_offset = 0;
1288 mip->ra_index++;
1289 }
1290 }
1291 }
1292 blk_finish_plug(&plug);
1293
1294out:
1295 *bpp = bp;
1296 return error;
1297}
1298
1299/*
1300 * Getdents (readdir) for leaf and node directories.
1301 * This reads the data blocks only, so is the same for both forms.
1302 */
1303int /* error */
1304xfs_dir2_leaf_getdents(
1305 xfs_inode_t *dp, /* incore directory inode */
1306 struct dir_context *ctx,
1307 size_t bufsize)
1308{
1309 struct xfs_buf *bp = NULL; /* data block buffer */
1310 xfs_dir2_data_hdr_t *hdr; /* data block header */
1311 xfs_dir2_data_entry_t *dep; /* data entry */
1312 xfs_dir2_data_unused_t *dup; /* unused entry */
1313 int error = 0; /* error return value */
1314 int length; /* temporary length value */
1315 xfs_mount_t *mp; /* filesystem mount point */
1316 int byteoff; /* offset in current block */
1317 xfs_dir2_off_t curoff; /* current overall offset */
1318 xfs_dir2_off_t newoff; /* new curoff after new blk */
1319 char *ptr = NULL; /* pointer to current data */
1320 struct xfs_dir2_leaf_map_info *map_info;
1321
1322 /*
1323 * If the offset is at or past the largest allowed value,
1324 * give up right away.
1325 */
1326 if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
1327 return 0;
1328
1329 mp = dp->i_mount;
1330
1331 /*
1332 * Set up to bmap a number of blocks based on the caller's
1333 * buffer size, the directory block size, and the filesystem
1334 * block size.
1335 */
1336 length = howmany(bufsize + mp->m_dirblksize,
1337 mp->m_sb.sb_blocksize);
1338 map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
1339 (length * sizeof(struct xfs_bmbt_irec)),
1340 KM_SLEEP | KM_NOFS);
1341 map_info->map_size = length;
1342
1343 /*
1344 * Inside the loop we keep the main offset value as a byte offset
1345 * in the directory file.
1346 */
1347 curoff = xfs_dir2_dataptr_to_byte(mp, ctx->pos);
1348
1349 /*
1350 * Force this conversion through db so we truncate the offset
1351 * down to get the start of the data block.
1352 */
1353 map_info->map_off = xfs_dir2_db_to_da(mp,
1354 xfs_dir2_byte_to_db(mp, curoff));
1355
1356 /*
1357 * Loop over directory entries until we reach the end offset.
1358 * Get more blocks and readahead as necessary.
1359 */
1360 while (curoff < XFS_DIR2_LEAF_OFFSET) {
1361 /*
1362 * If we have no buffer, or we're off the end of the
1363 * current buffer, need to get another one.
1364 */
1365 if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
1366
1367 error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
1368 &curoff, &bp);
1369 if (error || !map_info->map_valid)
1370 break;
1371
1372 /*
1373 * Having done a read, we need to set a new offset.
1374 */
1375 newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
1376 /*
1377 * Start of the current block.
1378 */
1379 if (curoff < newoff)
1380 curoff = newoff;
1381 /*
1382 * Make sure we're in the right block.
1383 */
1384 else if (curoff > newoff)
1385 ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
1386 map_info->curdb);
1387 hdr = bp->b_addr;
1388 xfs_dir3_data_check(dp, bp);
1389 /*
1390 * Find our position in the block.
1391 */
1392 ptr = (char *)xfs_dir3_data_entry_p(hdr);
1393 byteoff = xfs_dir2_byte_to_off(mp, curoff);
1394 /*
1395 * Skip past the header.
1396 */
1397 if (byteoff == 0)
1398 curoff += xfs_dir3_data_entry_offset(hdr);
1399 /*
1400 * Skip past entries until we reach our offset.
1401 */
1402 else {
1403 while ((char *)ptr - (char *)hdr < byteoff) {
1404 dup = (xfs_dir2_data_unused_t *)ptr;
1405
1406 if (be16_to_cpu(dup->freetag)
1407 == XFS_DIR2_DATA_FREE_TAG) {
1408
1409 length = be16_to_cpu(dup->length);
1410 ptr += length;
1411 continue;
1412 }
1413 dep = (xfs_dir2_data_entry_t *)ptr;
1414 length =
1415 xfs_dir2_data_entsize(dep->namelen);
1416 ptr += length;
1417 }
1418 /*
1419 * Now set our real offset.
1420 */
1421 curoff =
1422 xfs_dir2_db_off_to_byte(mp,
1423 xfs_dir2_byte_to_db(mp, curoff),
1424 (char *)ptr - (char *)hdr);
1425 if (ptr >= (char *)hdr + mp->m_dirblksize) {
1426 continue;
1427 }
1428 }
1429 }
1430 /*
1431 * We have a pointer to an entry.
1432 * Is it a live one?
1433 */
1434 dup = (xfs_dir2_data_unused_t *)ptr;
1435 /*
1436 * No, it's unused, skip over it.
1437 */
1438 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
1439 length = be16_to_cpu(dup->length);
1440 ptr += length;
1441 curoff += length;
1442 continue;
1443 }
1444
1445 dep = (xfs_dir2_data_entry_t *)ptr;
1446 length = xfs_dir2_data_entsize(dep->namelen);
1447
1448 ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
1449 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
1450 be64_to_cpu(dep->inumber), DT_UNKNOWN))
1451 break;
1452
1453 /*
1454 * Advance to next entry in the block.
1455 */
1456 ptr += length;
1457 curoff += length;
1458 /* bufsize may have just been a guess; don't go negative */
1459 bufsize = bufsize > length ? bufsize - length : 0;
1460 }
1461
1462 /*
1463 * All done. Set output offset value to current offset.
1464 */
1465 if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
1466 ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
1467 else
1468 ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
1469 kmem_free(map_info);
1470 if (bp)
1471 xfs_trans_brelse(NULL, bp);
1472 return error;
1473}
1474
1475
1476/* 1086/*
1477 * Log the bests entries indicated from a leaf1 block. 1087 * Log the bests entries indicated from a leaf1 block.
1478 */ 1088 */