aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-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.