aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
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
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')
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/xfs_dir2.c31
-rw-r--r--fs/xfs/xfs_dir2_block.c97
-rw-r--r--fs/xfs/xfs_dir2_leaf.c390
-rw-r--r--fs/xfs/xfs_dir2_priv.h7
-rw-r--r--fs/xfs/xfs_dir2_readdir.c645
-rw-r--r--fs/xfs/xfs_dir2_sf.c94
7 files changed, 649 insertions, 616 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 7f2319d3554d..b6158afa94e7 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -30,6 +30,7 @@ xfs-y += xfs_aops.o \
30 xfs_bit.o \ 30 xfs_bit.o \
31 xfs_buf.o \ 31 xfs_buf.o \
32 xfs_dfrag.o \ 32 xfs_dfrag.o \
33 xfs_dir2_readdir.o \
33 xfs_discard.o \ 34 xfs_discard.o \
34 xfs_error.o \ 35 xfs_error.o \
35 xfs_export.o \ 36 xfs_export.o \
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 8f023dee404d..431be441347f 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -363,37 +363,6 @@ xfs_dir_removename(
363} 363}
364 364
365/* 365/*
366 * Read a directory.
367 */
368int
369xfs_readdir(
370 xfs_inode_t *dp,
371 struct dir_context *ctx,
372 size_t bufsize)
373{
374 int rval; /* return value */
375 int v; /* type-checking value */
376
377 trace_xfs_readdir(dp);
378
379 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
380 return XFS_ERROR(EIO);
381
382 ASSERT(S_ISDIR(dp->i_d.di_mode));
383 XFS_STATS_INC(xs_dir_getdents);
384
385 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
386 rval = xfs_dir2_sf_getdents(dp, ctx);
387 else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
388 ;
389 else if (v)
390 rval = xfs_dir2_block_getdents(dp, ctx);
391 else
392 rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize);
393 return rval;
394}
395
396/*
397 * Replace the inode number of a directory entry. 366 * Replace the inode number of a directory entry.
398 */ 367 */
399int 368int
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 5e7fbd72cf52..5e8400064fa9 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -126,7 +126,7 @@ const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
126 .verify_write = xfs_dir3_block_write_verify, 126 .verify_write = xfs_dir3_block_write_verify,
127}; 127};
128 128
129static int 129int
130xfs_dir3_block_read( 130xfs_dir3_block_read(
131 struct xfs_trans *tp, 131 struct xfs_trans *tp,
132 struct xfs_inode *dp, 132 struct xfs_inode *dp,
@@ -565,101 +565,6 @@ xfs_dir2_block_addname(
565} 565}
566 566
567/* 567/*
568 * Readdir for block directories.
569 */
570int /* error */
571xfs_dir2_block_getdents(
572 xfs_inode_t *dp, /* incore inode */
573 struct dir_context *ctx)
574{
575 xfs_dir2_data_hdr_t *hdr; /* block header */
576 struct xfs_buf *bp; /* buffer for block */
577 xfs_dir2_block_tail_t *btp; /* block tail */
578 xfs_dir2_data_entry_t *dep; /* block data entry */
579 xfs_dir2_data_unused_t *dup; /* block unused entry */
580 char *endptr; /* end of the data entries */
581 int error; /* error return value */
582 xfs_mount_t *mp; /* filesystem mount point */
583 char *ptr; /* current data entry */
584 int wantoff; /* starting block offset */
585 xfs_off_t cook;
586
587 mp = dp->i_mount;
588 /*
589 * If the block number in the offset is out of range, we're done.
590 */
591 if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
592 return 0;
593
594 error = xfs_dir3_block_read(NULL, dp, &bp);
595 if (error)
596 return error;
597
598 /*
599 * Extract the byte offset we start at from the seek pointer.
600 * We'll skip entries before this.
601 */
602 wantoff = xfs_dir2_dataptr_to_off(mp, ctx->pos);
603 hdr = bp->b_addr;
604 xfs_dir3_data_check(dp, bp);
605 /*
606 * Set up values for the loop.
607 */
608 btp = xfs_dir2_block_tail_p(mp, hdr);
609 ptr = (char *)xfs_dir3_data_entry_p(hdr);
610 endptr = (char *)xfs_dir2_block_leaf_p(btp);
611
612 /*
613 * Loop over the data portion of the block.
614 * Each object is a real entry (dep) or an unused one (dup).
615 */
616 while (ptr < endptr) {
617 dup = (xfs_dir2_data_unused_t *)ptr;
618 /*
619 * Unused, skip it.
620 */
621 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
622 ptr += be16_to_cpu(dup->length);
623 continue;
624 }
625
626 dep = (xfs_dir2_data_entry_t *)ptr;
627
628 /*
629 * Bump pointer for the next iteration.
630 */
631 ptr += xfs_dir2_data_entsize(dep->namelen);
632 /*
633 * The entry is before the desired starting point, skip it.
634 */
635 if ((char *)dep - (char *)hdr < wantoff)
636 continue;
637
638 cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
639 (char *)dep - (char *)hdr);
640
641 ctx->pos = cook & 0x7fffffff;
642 /*
643 * If it didn't fit, set the final offset to here & return.
644 */
645 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
646 be64_to_cpu(dep->inumber), DT_UNKNOWN)) {
647 xfs_trans_brelse(NULL, bp);
648 return 0;
649 }
650 }
651
652 /*
653 * Reached the end of the block.
654 * Set the offset to a non-existent block 1 and return.
655 */
656 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
657 0x7fffffff;
658 xfs_trans_brelse(NULL, bp);
659 return 0;
660}
661
662/*
663 * Log leaf entries from the block. 568 * Log leaf entries from the block.
664 */ 569 */
665static void 570static void
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 */
diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h
index 0511cda4a712..72ff8d74e8eb 100644
--- a/fs/xfs/xfs_dir2_priv.h
+++ b/fs/xfs/xfs_dir2_priv.h
@@ -32,9 +32,9 @@ extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
32/* xfs_dir2_block.c */ 32/* xfs_dir2_block.c */
33extern const struct xfs_buf_ops xfs_dir3_block_buf_ops; 33extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
34 34
35extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp,
36 struct xfs_buf **bpp);
35extern int xfs_dir2_block_addname(struct xfs_da_args *args); 37extern int xfs_dir2_block_addname(struct xfs_da_args *args);
36extern int xfs_dir2_block_getdents(struct xfs_inode *dp,
37 struct dir_context *ctx);
38extern int xfs_dir2_block_lookup(struct xfs_da_args *args); 38extern int xfs_dir2_block_lookup(struct xfs_da_args *args);
39extern int xfs_dir2_block_removename(struct xfs_da_args *args); 39extern int xfs_dir2_block_removename(struct xfs_da_args *args);
40extern int xfs_dir2_block_replace(struct xfs_da_args *args); 40extern int xfs_dir2_block_replace(struct xfs_da_args *args);
@@ -91,8 +91,6 @@ extern void xfs_dir3_leaf_compact(struct xfs_da_args *args,
91extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr, 91extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr,
92 struct xfs_dir2_leaf_entry *ents, int *indexp, 92 struct xfs_dir2_leaf_entry *ents, int *indexp,
93 int *lowstalep, int *highstalep, int *lowlogp, int *highlogp); 93 int *lowstalep, int *highstalep, int *lowlogp, int *highlogp);
94extern int xfs_dir2_leaf_getdents(struct xfs_inode *dp, struct dir_context *ctx,
95 size_t bufsize);
96extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno, 94extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno,
97 struct xfs_buf **bpp, __uint16_t magic); 95 struct xfs_buf **bpp, __uint16_t magic);
98extern void xfs_dir3_leaf_log_ents(struct xfs_trans *tp, struct xfs_buf *bp, 96extern void xfs_dir3_leaf_log_ents(struct xfs_trans *tp, struct xfs_buf *bp,
@@ -153,7 +151,6 @@ extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp,
153 int size, xfs_dir2_sf_hdr_t *sfhp); 151 int size, xfs_dir2_sf_hdr_t *sfhp);
154extern int xfs_dir2_sf_addname(struct xfs_da_args *args); 152extern int xfs_dir2_sf_addname(struct xfs_da_args *args);
155extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); 153extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino);
156extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, struct dir_context *ctx);
157extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); 154extern int xfs_dir2_sf_lookup(struct xfs_da_args *args);
158extern int xfs_dir2_sf_removename(struct xfs_da_args *args); 155extern int xfs_dir2_sf_removename(struct xfs_da_args *args);
159extern int xfs_dir2_sf_replace(struct xfs_da_args *args); 156extern int xfs_dir2_sf_replace(struct xfs_da_args *args);
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
new file mode 100644
index 000000000000..2bc4b324ff76
--- /dev/null
+++ b/fs/xfs/xfs_dir2_readdir.c
@@ -0,0 +1,645 @@
1/*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * Copyright (c) 2013 Red Hat, Inc.
4 * All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include "xfs.h"
20#include "xfs_fs.h"
21#include "xfs_types.h"
22#include "xfs_bit.h"
23#include "xfs_log.h"
24#include "xfs_trans.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
27#include "xfs_mount.h"
28#include "xfs_da_btree.h"
29#include "xfs_bmap_btree.h"
30#include "xfs_dinode.h"
31#include "xfs_inode.h"
32#include "xfs_dir2_format.h"
33#include "xfs_dir2_priv.h"
34#include "xfs_error.h"
35#include "xfs_trace.h"
36#include "xfs_bmap.h"
37
38STATIC int
39xfs_dir2_sf_getdents(
40 xfs_inode_t *dp, /* incore directory inode */
41 struct dir_context *ctx)
42{
43 int i; /* shortform entry number */
44 xfs_mount_t *mp; /* filesystem mount point */
45 xfs_dir2_dataptr_t off; /* current entry's offset */
46 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
47 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
48 xfs_dir2_dataptr_t dot_offset;
49 xfs_dir2_dataptr_t dotdot_offset;
50 xfs_ino_t ino;
51
52 mp = dp->i_mount;
53
54 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
55 /*
56 * Give up if the directory is way too short.
57 */
58 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
59 ASSERT(XFS_FORCED_SHUTDOWN(mp));
60 return XFS_ERROR(EIO);
61 }
62
63 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
64 ASSERT(dp->i_df.if_u1.if_data != NULL);
65
66 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
67
68 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
69
70 /*
71 * If the block number in the offset is out of range, we're done.
72 */
73 if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
74 return 0;
75
76 /*
77 * Precalculate offsets for . and .. as we will always need them.
78 *
79 * XXX(hch): the second argument is sometimes 0 and sometimes
80 * mp->m_dirdatablk.
81 */
82 dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
83 XFS_DIR3_DATA_DOT_OFFSET(mp));
84 dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
85 XFS_DIR3_DATA_DOTDOT_OFFSET(mp));
86
87 /*
88 * Put . entry unless we're starting past it.
89 */
90 if (ctx->pos <= dot_offset) {
91 ctx->pos = dot_offset & 0x7fffffff;
92 if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR))
93 return 0;
94 }
95
96 /*
97 * Put .. entry unless we're starting past it.
98 */
99 if (ctx->pos <= dotdot_offset) {
100 ino = xfs_dir2_sf_get_parent_ino(sfp);
101 ctx->pos = dotdot_offset & 0x7fffffff;
102 if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
103 return 0;
104 }
105
106 /*
107 * Loop while there are more entries and put'ing works.
108 */
109 sfep = xfs_dir2_sf_firstentry(sfp);
110 for (i = 0; i < sfp->count; i++) {
111 off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
112 xfs_dir2_sf_get_offset(sfep));
113
114 if (ctx->pos > off) {
115 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
116 continue;
117 }
118
119 ino = xfs_dir2_sfe_get_ino(sfp, sfep);
120 ctx->pos = off & 0x7fffffff;
121 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen,
122 ino, DT_UNKNOWN))
123 return 0;
124 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
125 }
126
127 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
128 0x7fffffff;
129 return 0;
130}
131
132/*
133 * Readdir for block directories.
134 */
135STATIC int
136xfs_dir2_block_getdents(
137 xfs_inode_t *dp, /* incore inode */
138 struct dir_context *ctx)
139{
140 xfs_dir2_data_hdr_t *hdr; /* block header */
141 struct xfs_buf *bp; /* buffer for block */
142 xfs_dir2_block_tail_t *btp; /* block tail */
143 xfs_dir2_data_entry_t *dep; /* block data entry */
144 xfs_dir2_data_unused_t *dup; /* block unused entry */
145 char *endptr; /* end of the data entries */
146 int error; /* error return value */
147 xfs_mount_t *mp; /* filesystem mount point */
148 char *ptr; /* current data entry */
149 int wantoff; /* starting block offset */
150 xfs_off_t cook;
151
152 mp = dp->i_mount;
153 /*
154 * If the block number in the offset is out of range, we're done.
155 */
156 if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
157 return 0;
158
159 error = xfs_dir3_block_read(NULL, dp, &bp);
160 if (error)
161 return error;
162
163 /*
164 * Extract the byte offset we start at from the seek pointer.
165 * We'll skip entries before this.
166 */
167 wantoff = xfs_dir2_dataptr_to_off(mp, ctx->pos);
168 hdr = bp->b_addr;
169 xfs_dir3_data_check(dp, bp);
170 /*
171 * Set up values for the loop.
172 */
173 btp = xfs_dir2_block_tail_p(mp, hdr);
174 ptr = (char *)xfs_dir3_data_entry_p(hdr);
175 endptr = (char *)xfs_dir2_block_leaf_p(btp);
176
177 /*
178 * Loop over the data portion of the block.
179 * Each object is a real entry (dep) or an unused one (dup).
180 */
181 while (ptr < endptr) {
182 dup = (xfs_dir2_data_unused_t *)ptr;
183 /*
184 * Unused, skip it.
185 */
186 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
187 ptr += be16_to_cpu(dup->length);
188 continue;
189 }
190
191 dep = (xfs_dir2_data_entry_t *)ptr;
192
193 /*
194 * Bump pointer for the next iteration.
195 */
196 ptr += xfs_dir2_data_entsize(dep->namelen);
197 /*
198 * The entry is before the desired starting point, skip it.
199 */
200 if ((char *)dep - (char *)hdr < wantoff)
201 continue;
202
203 cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
204 (char *)dep - (char *)hdr);
205
206 ctx->pos = cook & 0x7fffffff;
207 /*
208 * If it didn't fit, set the final offset to here & return.
209 */
210 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
211 be64_to_cpu(dep->inumber), DT_UNKNOWN)) {
212 xfs_trans_brelse(NULL, bp);
213 return 0;
214 }
215 }
216
217 /*
218 * Reached the end of the block.
219 * Set the offset to a non-existent block 1 and return.
220 */
221 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
222 0x7fffffff;
223 xfs_trans_brelse(NULL, bp);
224 return 0;
225}
226
227struct xfs_dir2_leaf_map_info {
228 xfs_extlen_t map_blocks; /* number of fsbs in map */
229 xfs_dablk_t map_off; /* last mapped file offset */
230 int map_size; /* total entries in *map */
231 int map_valid; /* valid entries in *map */
232 int nmap; /* mappings to ask xfs_bmapi */
233 xfs_dir2_db_t curdb; /* db for current block */
234 int ra_current; /* number of read-ahead blks */
235 int ra_index; /* *map index for read-ahead */
236 int ra_offset; /* map entry offset for ra */
237 int ra_want; /* readahead count wanted */
238 struct xfs_bmbt_irec map[]; /* map vector for blocks */
239};
240
241STATIC int
242xfs_dir2_leaf_readbuf(
243 struct xfs_inode *dp,
244 size_t bufsize,
245 struct xfs_dir2_leaf_map_info *mip,
246 xfs_dir2_off_t *curoff,
247 struct xfs_buf **bpp)
248{
249 struct xfs_mount *mp = dp->i_mount;
250 struct xfs_buf *bp = *bpp;
251 struct xfs_bmbt_irec *map = mip->map;
252 struct blk_plug plug;
253 int error = 0;
254 int length;
255 int i;
256 int j;
257
258 /*
259 * If we have a buffer, we need to release it and
260 * take it out of the mapping.
261 */
262
263 if (bp) {
264 xfs_trans_brelse(NULL, bp);
265 bp = NULL;
266 mip->map_blocks -= mp->m_dirblkfsbs;
267 /*
268 * Loop to get rid of the extents for the
269 * directory block.
270 */
271 for (i = mp->m_dirblkfsbs; i > 0; ) {
272 j = min_t(int, map->br_blockcount, i);
273 map->br_blockcount -= j;
274 map->br_startblock += j;
275 map->br_startoff += j;
276 /*
277 * If mapping is done, pitch it from
278 * the table.
279 */
280 if (!map->br_blockcount && --mip->map_valid)
281 memmove(&map[0], &map[1],
282 sizeof(map[0]) * mip->map_valid);
283 i -= j;
284 }
285 }
286
287 /*
288 * Recalculate the readahead blocks wanted.
289 */
290 mip->ra_want = howmany(bufsize + mp->m_dirblksize,
291 mp->m_sb.sb_blocksize) - 1;
292 ASSERT(mip->ra_want >= 0);
293
294 /*
295 * If we don't have as many as we want, and we haven't
296 * run out of data blocks, get some more mappings.
297 */
298 if (1 + mip->ra_want > mip->map_blocks &&
299 mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
300 /*
301 * Get more bmaps, fill in after the ones
302 * we already have in the table.
303 */
304 mip->nmap = mip->map_size - mip->map_valid;
305 error = xfs_bmapi_read(dp, mip->map_off,
306 xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
307 mip->map_off,
308 &map[mip->map_valid], &mip->nmap, 0);
309
310 /*
311 * Don't know if we should ignore this or try to return an
312 * error. The trouble with returning errors is that readdir
313 * will just stop without actually passing the error through.
314 */
315 if (error)
316 goto out; /* XXX */
317
318 /*
319 * If we got all the mappings we asked for, set the final map
320 * offset based on the last bmap value received. Otherwise,
321 * we've reached the end.
322 */
323 if (mip->nmap == mip->map_size - mip->map_valid) {
324 i = mip->map_valid + mip->nmap - 1;
325 mip->map_off = map[i].br_startoff + map[i].br_blockcount;
326 } else
327 mip->map_off = xfs_dir2_byte_to_da(mp,
328 XFS_DIR2_LEAF_OFFSET);
329
330 /*
331 * Look for holes in the mapping, and eliminate them. Count up
332 * the valid blocks.
333 */
334 for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) {
335 if (map[i].br_startblock == HOLESTARTBLOCK) {
336 mip->nmap--;
337 length = mip->map_valid + mip->nmap - i;
338 if (length)
339 memmove(&map[i], &map[i + 1],
340 sizeof(map[i]) * length);
341 } else {
342 mip->map_blocks += map[i].br_blockcount;
343 i++;
344 }
345 }
346 mip->map_valid += mip->nmap;
347 }
348
349 /*
350 * No valid mappings, so no more data blocks.
351 */
352 if (!mip->map_valid) {
353 *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
354 goto out;
355 }
356
357 /*
358 * Read the directory block starting at the first mapping.
359 */
360 mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
361 error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
362 map->br_blockcount >= mp->m_dirblkfsbs ?
363 XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
364
365 /*
366 * Should just skip over the data block instead of giving up.
367 */
368 if (error)
369 goto out; /* XXX */
370
371 /*
372 * Adjust the current amount of read-ahead: we just read a block that
373 * was previously ra.
374 */
375 if (mip->ra_current)
376 mip->ra_current -= mp->m_dirblkfsbs;
377
378 /*
379 * Do we need more readahead?
380 */
381 blk_start_plug(&plug);
382 for (mip->ra_index = mip->ra_offset = i = 0;
383 mip->ra_want > mip->ra_current && i < mip->map_blocks;
384 i += mp->m_dirblkfsbs) {
385 ASSERT(mip->ra_index < mip->map_valid);
386 /*
387 * Read-ahead a contiguous directory block.
388 */
389 if (i > mip->ra_current &&
390 map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
391 xfs_dir3_data_readahead(NULL, dp,
392 map[mip->ra_index].br_startoff + mip->ra_offset,
393 XFS_FSB_TO_DADDR(mp,
394 map[mip->ra_index].br_startblock +
395 mip->ra_offset));
396 mip->ra_current = i;
397 }
398
399 /*
400 * Read-ahead a non-contiguous directory block. This doesn't
401 * use our mapping, but this is a very rare case.
402 */
403 else if (i > mip->ra_current) {
404 xfs_dir3_data_readahead(NULL, dp,
405 map[mip->ra_index].br_startoff +
406 mip->ra_offset, -1);
407 mip->ra_current = i;
408 }
409
410 /*
411 * Advance offset through the mapping table.
412 */
413 for (j = 0; j < mp->m_dirblkfsbs; j++) {
414 /*
415 * The rest of this extent but not more than a dir
416 * block.
417 */
418 length = min_t(int, mp->m_dirblkfsbs,
419 map[mip->ra_index].br_blockcount -
420 mip->ra_offset);
421 j += length;
422 mip->ra_offset += length;
423
424 /*
425 * Advance to the next mapping if this one is used up.
426 */
427 if (mip->ra_offset == map[mip->ra_index].br_blockcount) {
428 mip->ra_offset = 0;
429 mip->ra_index++;
430 }
431 }
432 }
433 blk_finish_plug(&plug);
434
435out:
436 *bpp = bp;
437 return error;
438}
439
440/*
441 * Getdents (readdir) for leaf and node directories.
442 * This reads the data blocks only, so is the same for both forms.
443 */
444STATIC int
445xfs_dir2_leaf_getdents(
446 xfs_inode_t *dp, /* incore directory inode */
447 struct dir_context *ctx,
448 size_t bufsize)
449{
450 struct xfs_buf *bp = NULL; /* data block buffer */
451 xfs_dir2_data_hdr_t *hdr; /* data block header */
452 xfs_dir2_data_entry_t *dep; /* data entry */
453 xfs_dir2_data_unused_t *dup; /* unused entry */
454 int error = 0; /* error return value */
455 int length; /* temporary length value */
456 xfs_mount_t *mp; /* filesystem mount point */
457 int byteoff; /* offset in current block */
458 xfs_dir2_off_t curoff; /* current overall offset */
459 xfs_dir2_off_t newoff; /* new curoff after new blk */
460 char *ptr = NULL; /* pointer to current data */
461 struct xfs_dir2_leaf_map_info *map_info;
462
463 /*
464 * If the offset is at or past the largest allowed value,
465 * give up right away.
466 */
467 if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
468 return 0;
469
470 mp = dp->i_mount;
471
472 /*
473 * Set up to bmap a number of blocks based on the caller's
474 * buffer size, the directory block size, and the filesystem
475 * block size.
476 */
477 length = howmany(bufsize + mp->m_dirblksize,
478 mp->m_sb.sb_blocksize);
479 map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
480 (length * sizeof(struct xfs_bmbt_irec)),
481 KM_SLEEP | KM_NOFS);
482 map_info->map_size = length;
483
484 /*
485 * Inside the loop we keep the main offset value as a byte offset
486 * in the directory file.
487 */
488 curoff = xfs_dir2_dataptr_to_byte(mp, ctx->pos);
489
490 /*
491 * Force this conversion through db so we truncate the offset
492 * down to get the start of the data block.
493 */
494 map_info->map_off = xfs_dir2_db_to_da(mp,
495 xfs_dir2_byte_to_db(mp, curoff));
496
497 /*
498 * Loop over directory entries until we reach the end offset.
499 * Get more blocks and readahead as necessary.
500 */
501 while (curoff < XFS_DIR2_LEAF_OFFSET) {
502 /*
503 * If we have no buffer, or we're off the end of the
504 * current buffer, need to get another one.
505 */
506 if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
507
508 error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
509 &curoff, &bp);
510 if (error || !map_info->map_valid)
511 break;
512
513 /*
514 * Having done a read, we need to set a new offset.
515 */
516 newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
517 /*
518 * Start of the current block.
519 */
520 if (curoff < newoff)
521 curoff = newoff;
522 /*
523 * Make sure we're in the right block.
524 */
525 else if (curoff > newoff)
526 ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
527 map_info->curdb);
528 hdr = bp->b_addr;
529 xfs_dir3_data_check(dp, bp);
530 /*
531 * Find our position in the block.
532 */
533 ptr = (char *)xfs_dir3_data_entry_p(hdr);
534 byteoff = xfs_dir2_byte_to_off(mp, curoff);
535 /*
536 * Skip past the header.
537 */
538 if (byteoff == 0)
539 curoff += xfs_dir3_data_entry_offset(hdr);
540 /*
541 * Skip past entries until we reach our offset.
542 */
543 else {
544 while ((char *)ptr - (char *)hdr < byteoff) {
545 dup = (xfs_dir2_data_unused_t *)ptr;
546
547 if (be16_to_cpu(dup->freetag)
548 == XFS_DIR2_DATA_FREE_TAG) {
549
550 length = be16_to_cpu(dup->length);
551 ptr += length;
552 continue;
553 }
554 dep = (xfs_dir2_data_entry_t *)ptr;
555 length =
556 xfs_dir2_data_entsize(dep->namelen);
557 ptr += length;
558 }
559 /*
560 * Now set our real offset.
561 */
562 curoff =
563 xfs_dir2_db_off_to_byte(mp,
564 xfs_dir2_byte_to_db(mp, curoff),
565 (char *)ptr - (char *)hdr);
566 if (ptr >= (char *)hdr + mp->m_dirblksize) {
567 continue;
568 }
569 }
570 }
571 /*
572 * We have a pointer to an entry.
573 * Is it a live one?
574 */
575 dup = (xfs_dir2_data_unused_t *)ptr;
576 /*
577 * No, it's unused, skip over it.
578 */
579 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
580 length = be16_to_cpu(dup->length);
581 ptr += length;
582 curoff += length;
583 continue;
584 }
585
586 dep = (xfs_dir2_data_entry_t *)ptr;
587 length = xfs_dir2_data_entsize(dep->namelen);
588
589 ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
590 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
591 be64_to_cpu(dep->inumber), DT_UNKNOWN))
592 break;
593
594 /*
595 * Advance to next entry in the block.
596 */
597 ptr += length;
598 curoff += length;
599 /* bufsize may have just been a guess; don't go negative */
600 bufsize = bufsize > length ? bufsize - length : 0;
601 }
602
603 /*
604 * All done. Set output offset value to current offset.
605 */
606 if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
607 ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
608 else
609 ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
610 kmem_free(map_info);
611 if (bp)
612 xfs_trans_brelse(NULL, bp);
613 return error;
614}
615
616/*
617 * Read a directory.
618 */
619int
620xfs_readdir(
621 xfs_inode_t *dp,
622 struct dir_context *ctx,
623 size_t bufsize)
624{
625 int rval; /* return value */
626 int v; /* type-checking value */
627
628 trace_xfs_readdir(dp);
629
630 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
631 return XFS_ERROR(EIO);
632
633 ASSERT(S_ISDIR(dp->i_d.di_mode));
634 XFS_STATS_INC(xs_dir_getdents);
635
636 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
637 rval = xfs_dir2_sf_getdents(dp, ctx);
638 else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
639 ;
640 else if (v)
641 rval = xfs_dir2_block_getdents(dp, ctx);
642 else
643 rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize);
644 return rval;
645}
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 97676a347da1..f24ce9044e72 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -765,100 +765,6 @@ xfs_dir2_sf_create(
765 return 0; 765 return 0;
766} 766}
767 767
768int /* error */
769xfs_dir2_sf_getdents(
770 xfs_inode_t *dp, /* incore directory inode */
771 struct dir_context *ctx)
772{
773 int i; /* shortform entry number */
774 xfs_mount_t *mp; /* filesystem mount point */
775 xfs_dir2_dataptr_t off; /* current entry's offset */
776 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
777 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
778 xfs_dir2_dataptr_t dot_offset;
779 xfs_dir2_dataptr_t dotdot_offset;
780 xfs_ino_t ino;
781
782 mp = dp->i_mount;
783
784 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
785 /*
786 * Give up if the directory is way too short.
787 */
788 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
789 ASSERT(XFS_FORCED_SHUTDOWN(mp));
790 return XFS_ERROR(EIO);
791 }
792
793 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
794 ASSERT(dp->i_df.if_u1.if_data != NULL);
795
796 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
797
798 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
799
800 /*
801 * If the block number in the offset is out of range, we're done.
802 */
803 if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
804 return 0;
805
806 /*
807 * Precalculate offsets for . and .. as we will always need them.
808 *
809 * XXX(hch): the second argument is sometimes 0 and sometimes
810 * mp->m_dirdatablk.
811 */
812 dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
813 XFS_DIR3_DATA_DOT_OFFSET(mp));
814 dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
815 XFS_DIR3_DATA_DOTDOT_OFFSET(mp));
816
817 /*
818 * Put . entry unless we're starting past it.
819 */
820 if (ctx->pos <= dot_offset) {
821 ctx->pos = dot_offset & 0x7fffffff;
822 if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR))
823 return 0;
824 }
825
826 /*
827 * Put .. entry unless we're starting past it.
828 */
829 if (ctx->pos <= dotdot_offset) {
830 ino = xfs_dir2_sf_get_parent_ino(sfp);
831 ctx->pos = dotdot_offset & 0x7fffffff;
832 if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
833 return 0;
834 }
835
836 /*
837 * Loop while there are more entries and put'ing works.
838 */
839 sfep = xfs_dir2_sf_firstentry(sfp);
840 for (i = 0; i < sfp->count; i++) {
841 off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
842 xfs_dir2_sf_get_offset(sfep));
843
844 if (ctx->pos > off) {
845 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
846 continue;
847 }
848
849 ino = xfs_dir2_sfe_get_ino(sfp, sfep);
850 ctx->pos = off & 0x7fffffff;
851 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen,
852 ino, DT_UNKNOWN))
853 return 0;
854 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
855 }
856
857 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
858 0x7fffffff;
859 return 0;
860}
861
862/* 768/*
863 * Lookup an entry in a shortform directory. 769 * Lookup an entry in a shortform directory.
864 * Returns EEXIST if found, ENOENT if not found. 770 * Returns EEXIST if found, ENOENT if not found.