Add -lrt to link line.
CFILES = xfs_copy.c
HFILES = xfs_copy.h
-LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBPTHREAD)
+LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBPTHREAD) $(LIBRT)
LTDEPENDENCIES = $(LIBXFS)
LLDFLAGS = -static
attrset.h
CFILES = $(HFILES:.h=.c)
LSRCFILES = xfs_admin.sh xfs_check.sh xfs_ncheck.sh
-LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID)
+LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT)
LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
LLDFLAGS += -static
CFILES = xfs_growfs.c
-LLDLIBS = $(LIBXFS) $(LIBXCMD) $(LIBUUID)
+LLDLIBS = $(LIBXFS) $(LIBXCMD) $(LIBUUID) $(LIBRT)
LTDEPENDENCIES = $(LIBXFS) $(LIBXCMD)
LLDFLAGS = -static
LSRCFILES = xfs_info.sh
#define XFS_IOC_GETPARENTS SGI_XFS_GETPARENTS
#define XFS_IOC_GETPARENTPATHS SGI_XFS_GETPARENTPATHS
+#define _AIOCB64_T_DEFINED 1
+
#endif /* __XFS_IRIX_H__ */
extern void libxfs_device_zero (dev_t, xfs_daddr_t, uint);
extern void libxfs_device_close (dev_t);
extern void libxfs_report(FILE *);
+extern char *libxfs_findrawpath(char *);
/* check or write log footer: specify device, log size in blocks & uuid */
typedef xfs_caddr_t (libxfs_get_block_t)(xfs_caddr_t, int, void *);
xfs_filblks_t, int, xfs_fsblock_t *,
xfs_extlen_t, xfs_bmbt_irec_t *, int *,
xfs_bmap_free_t *);
+extern int libxfs_bmapi_single(xfs_trans_t *, xfs_inode_t *, int,
+ xfs_fsblock_t *, xfs_fileoff_t);
extern int libxfs_bmap_finish (xfs_trans_t **, xfs_bmap_free_t *,
xfs_fsblock_t, int *);
extern int libxfs_bmap_next_offset (xfs_trans_t *, xfs_inode_t *,
extern void cmn_err(int, char *, ...);
enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC };
+/* lio interface */
+/* lio_listio(3) interface (POSIX linked asynchronous I/O) */
+extern int libxfs_lio_ino_count;
+extern int libxfs_lio_dir_count;
+extern int libxfs_lio_aio_count;
+
+extern int libxfs_lio_init(void);
+extern void libxfs_lio_allocate(void);
+extern void *libxfs_get_lio_buffer(int type);
+extern void libxfs_put_lio_buffer(void *buffer);
+extern int libxfs_readbuf_list(dev_t dev, int nent, void *voidp, int type);
+
+typedef struct libxfs_lio_req {
+ xfs_daddr_t blkno;
+ int len; /* bbs */
+} libxfs_lio_req_t;
+
+#define LIBXFS_LIO_TYPE_INO 0x1
+#define LIBXFS_LIO_TYPE_DIR 0x2
+#define LIBXFS_LIO_TYPE_RAW 0x3
+
+#define LIBXFS_BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT)
+
#include <xfs/xfs_ialloc.h>
#include <xfs/xfs_rtalloc.h>
#define _BOOLEAN_T_DEFINED 1
#endif
-#endif /* __XFS_IRIX_H__ */
+#ifdef __USE_GNU
+typedef struct aiocb64 aiocb64_t;
+#define _AIOCB64_T_DEFINED 1
+#endif
+
+#endif /* __XFS_LINUX_H__ */
LT_REVISION = 0
LT_AGE = 0
-HFILES = xfs.h init.h
-CFILES = bit.c cache.c init.c logitem.c rdwr.c trans.c util.c \
+HFILES = xfs.h init.h list.h
+CFILES = bit.c cache.c init.c lio.c logitem.c rdwr.c trans.c util.c \
xfs_alloc.c xfs_ialloc.c xfs_rtalloc.c \
xfs_inode.c xfs_btree.c xfs_alloc_btree.c xfs_ialloc_btree.c \
xfs_bmap_btree.c xfs_da_btree.c xfs_dir.c xfs_dir_leaf.c \
*sz = (long long)size;
*bsz = BBSIZE;
}
+
+/* ARGSUSED */
+int
+platform_aio_init(int aio_count)
+{
+ return (0); /* aio/lio_listio not available */
+}
+
+char *
+platform_findrawpath(char *path)
+{
+ return (path);
+}
*sz = (long long) (size / ssize);
*bsz = (int)ssize;
}
+
+/* ARGSUSED */
+int
+platform_aio_init(int aio_count)
+{
+ return (0); /* aio/lio_listio not available */
+}
+
+char *
+platform_findrawpath(char *path)
+{
+ return (path);
+}
void
libxfs_report(FILE *fp)
{
+ time_t t;
+ char *c;
+
cache_report(fp, "libxfs_icache", libxfs_icache);
cache_report(fp, "libxfs_bcache", libxfs_bcache);
+
+ t = time(NULL);
+ c = asctime(localtime(&t));
+ fprintf(fp, "%s", c);
+}
+
+char *
+libxfs_findrawpath(char *path)
+{
+ return platform_findrawpath(path);
}
extern void platform_findsizes (char *path, int fd, long long *sz, int *bsz);
extern void platform_set_blocksize (int fd, char *path, int blocksize);
extern void platform_flush_device (int fd, dev_t device);
-
+extern char *platform_findrawpath(char *path);
+extern int platform_aio_init(int aio_count);
#endif /* LIBXFS_INIT_H */
*/
#include <xfs/libxfs.h>
+#include <aio.h>
+#include <diskinfo.h>
extern char *progname;
extern __int64_t findsize(char *);
}
*bsz = BBSIZE;
}
+
+int
+platform_aio_init(int aio_count)
+{
+ struct aioinit aio_init;
+
+ memset(&aio_init, 0, sizeof(aio_init));
+ aio_init.aio_threads = aio_count;
+ aio_init.aio_numusers = aio_count;
+
+ aio_sgi_init64(&aio_init);
+ return (1); /* aio/lio_listio available */
+}
+
+char *
+platform_findrawpath(char *path)
+{
+ return findrawpath(path);
+}
#include <xfs/libxfs.h>
#include <mntent.h>
#include <sys/stat.h>
+#include <aio.h>
#undef ustat
#include <sys/ustat.h>
#include <sys/mount.h>
*bsz = BBSIZE;
}
}
+
+int
+platform_aio_init(int aio_count)
+{
+ struct aioinit lcl_aio_init;
+
+ memset(&lcl_aio_init, 0, sizeof(lcl_aio_init));
+ lcl_aio_init.aio_threads = aio_count;
+ lcl_aio_init.aio_numusers = aio_count;
+
+ aio_init(&lcl_aio_init);
+ return (1); /* aio/lio_listio available */
+}
+
+char *
+platform_findrawpath(char *path)
+{
+ return (path);
+}
--- /dev/null
+#include <xfs/libxfs.h>
+#include "init.h"
+#include "aio.h"
+
+#define DEF_PREFETCH_INOS 16
+#define DEF_PREFETCH_DIRS 16
+#define DEF_PREFETCH_AIO 32
+int libxfs_lio_ino_count = DEF_PREFETCH_INOS;
+int libxfs_lio_dir_count = DEF_PREFETCH_DIRS;
+int libxfs_lio_aio_count = DEF_PREFETCH_AIO;
+
+static pthread_key_t lio_ino_key;
+static pthread_key_t lio_dir_key;
+
+void
+libxfs_lio_allocate(void)
+{
+#ifdef _AIOCB64_T_DEFINED
+ size_t size;
+ void *voidp;
+
+ /*
+ * allocate a per-thread buffer which will be used in libxfs_readbuf_list
+ * in the following order:
+ * libxfs_lio_req_t array
+ * aiocb64_t array
+ * aiocb64_t * array
+ * xfs_buf_t * array
+ */
+ size = sizeof(libxfs_lio_req_t) + sizeof(aiocb64_t) + sizeof(aiocb64_t *) + sizeof(xfs_buf_t *);
+
+ voidp = malloc(libxfs_lio_ino_count*size);
+ if (voidp == NULL) {
+ fprintf(stderr, "lio_allocate: cannot allocate thread specific storage\n");
+ exit(1);
+ /* NO RETURN */
+ return;
+ }
+ pthread_setspecific(lio_ino_key, voidp);
+
+ voidp = malloc(libxfs_lio_dir_count*size);
+ if (voidp == NULL) {
+ fprintf(stderr, "lio_allocate: cannot allocate thread specific storage\n");
+ exit(1);
+ /* NO RETURN */
+ return;
+ }
+ pthread_setspecific(lio_dir_key, voidp);
+#endif /* _AIOCB64_T_DEFINED */
+}
+
+int
+libxfs_lio_init(void)
+{
+#ifdef _AIOCB64_T_DEFINED
+ if (platform_aio_init(libxfs_lio_aio_count)) {
+ pthread_key_create(&lio_ino_key, NULL);
+ pthread_key_create(&lio_dir_key, NULL);
+ return (1);
+ }
+#endif /* _AIOCB64_T_DEFINED */
+ return (0);
+}
+
+void *
+libxfs_get_lio_buffer(int type)
+{
+#ifdef _AIOCB64_T_DEFINED
+ if (type == LIBXFS_LIO_TYPE_INO)
+ return pthread_getspecific(lio_ino_key);
+ if (type == LIBXFS_LIO_TYPE_DIR)
+ return pthread_getspecific(lio_dir_key);
+ if (type == LIBXFS_LIO_TYPE_RAW) {
+ /* use the inode buffers since there is
+ * no overlap with the other requests.
+ */
+ return pthread_getspecific(lio_ino_key);
+ }
+ fprintf(stderr, "get_lio_buffer: invalid type 0x%x\n", type);
+ exit(1);
+#endif
+ return NULL;
+}
+
+/* ARGSUSED */
+void
+libxfs_put_lio_buffer(void *buffer)
+{
+ return; /* nothing to do */
+}
+
+static int
+lio_compare(const void *e1, const void *e2)
+{
+ libxfs_lio_req_t *r1 = (libxfs_lio_req_t *) e1;
+ libxfs_lio_req_t *r2 = (libxfs_lio_req_t *) e2;
+
+ return (int) (r1->blkno - r2->blkno);
+}
+
+int
+libxfs_readbuf_list(dev_t dev, int nent, void *voidp, int type)
+{
+#ifdef _AIOCB64_T_DEFINED
+ libxfs_lio_req_t *rblp;
+ xfs_buf_t *bp, **bplist;
+ aiocb64_t *aioclist, **aiocptr;
+ int i, nbp, err;
+ int fd;
+
+ if (nent <= 0)
+ return 0;
+ if ((type == LIBXFS_LIO_TYPE_INO) || (type == LIBXFS_LIO_TYPE_RAW)) {
+ if (libxfs_lio_ino_count == 0)
+ return (0);
+ if (nent > libxfs_lio_ino_count)
+ nent = libxfs_lio_ino_count;
+ }
+ else if (type == LIBXFS_LIO_TYPE_DIR) {
+ if (libxfs_lio_dir_count == 0)
+ return (0);
+ if (nent > libxfs_lio_dir_count)
+ nent = libxfs_lio_dir_count;
+ if (nent > 2)
+ qsort(voidp, nent, sizeof(libxfs_lio_req_t), lio_compare);
+ }
+ else {
+ fprintf(stderr, "Invalid type 0x%x in libxfs_readbuf_list\n", type);
+ abort();
+ /* NO RETURN */
+ return (0);
+ }
+
+ /* space for lio_listio processing, see libxfs_lio_allocate */
+ rblp = (libxfs_lio_req_t *) voidp;
+ aioclist = (aiocb64_t *) (rblp + nent);
+ aiocptr = (aiocb64_t **) (aioclist + nent);
+ bplist = (xfs_buf_t **) (aiocptr + nent);
+
+ bzero(aioclist, nent*sizeof(aiocb64_t));
+
+ /* look in buffer cache */
+ for (i = 0, nbp = 0; i < nent; i++) {
+ ASSERT(rblp[i].len);
+ bp = libxfs_getbuf(dev, rblp[i].blkno, rblp[i].len);
+ if (bp == NULL)
+ continue;
+ if (bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY)) {
+ /* already in cache */
+ libxfs_putbuf(bp);
+ continue;
+ }
+ bplist[nbp++] = bp;
+ }
+
+ if (nbp == 0)
+ return (0); /* Nothing to do */
+
+ if (nbp == 1) {
+ libxfs_putbuf(bplist[0]); /* single buffer, no point */
+ return (0);
+ }
+
+ fd = libxfs_device_to_fd(dev);
+
+ for (i = 0; i < nbp; i++) {
+ aioclist[i].aio_fildes = fd;
+ aioclist[i].aio_nbytes = XFS_BUF_COUNT(bplist[i]);
+ aioclist[i].aio_buf = XFS_BUF_PTR(bplist[i]);
+ aioclist[i].aio_offset = LIBXFS_BBTOOFF64(XFS_BUF_ADDR(bplist[i]));
+ aioclist[i].aio_lio_opcode = LIO_READ;
+ aiocptr[i] = &aioclist[i];
+ }
+
+ err = lio_listio64(LIO_WAIT, aiocptr, nbp, NULL);
+
+ if (err != 0) {
+ fprintf(stderr, "lio_listio (%d entries) failure err = %d\n", nbp, err);
+ }
+
+ for (i = 0; i < nbp; i++) {
+ /* buffer with data in cache available via future libxfs_readbuf */
+ if (err == 0)
+ bplist[i]->b_flags |= LIBXFS_B_UPTODATE;
+ libxfs_putbuf(bplist[i]);
+ }
+
+ return (err == 0? nbp : -1);
+#else /* _AIOCB64_T_DEFINED */
+ return -1;
+#endif /* _AIOCB64_T_DEFINED */
+}
#include <xfs/xfs_log.h>
#include <xfs/xfs_log_priv.h>
-#define BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT)
#define BDSTRAT_SIZE (256 * 1024)
#define min(x, y) ((x) < (y) ? (x) : (y))
memset(z, 0, zsize);
fd = libxfs_device_to_fd(dev);
- start_offset = BBTOOFF64(start);
+ start_offset = LIBXFS_BBTOOFF64(start);
if ((lseek64(fd, start_offset, SEEK_SET)) < 0) {
fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"),
exit(1);
}
- end_offset = BBTOOFF64(start + len) - start_offset;
+ end_offset = LIBXFS_BBTOOFF64(start + len) - start_offset;
for (offset = 0; offset < end_offset; ) {
bytes = min((ssize_t)(end_offset - offset), zsize);
if ((bytes = write(fd, z, bytes)) < 0) {
if (cache_node_get(libxfs_bcache, &key, (struct cache_node **)&bp)) {
#ifdef IO_DEBUG
fprintf(stderr, "%s: allocated buffer, key=%llu(%llu), %p\n",
- __FUNCTION__, BBTOB(len), BBTOOFF64(blkno), blkno, buf);
+ __FUNCTION__, BBTOB(len), LIBXFS_BBTOOFF64(blkno), blkno, buf);
#endif
bp->b_flags = 0;
bp->b_blkno = blkno;
ASSERT(BBTOB(len) <= bp->b_bcount);
- if (pread64(fd, bp->b_addr, bytes, BBTOOFF64(blkno)) < 0) {
+ if (pread64(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno)) < 0) {
fprintf(stderr, _("%s: read failed: %s\n"),
progname, strerror(errno));
if (flags & LIBXFS_EXIT_ON_FAILURE)
}
#ifdef IO_DEBUG
fprintf(stderr, "readbufr read %ubytes, blkno=%llu(%llu), %p\n",
- bytes, BBTOOFF64(blkno), blkno, bp);
+ bytes, LIBXFS_BBTOOFF64(blkno), blkno, bp);
#endif
if (bp->b_dev == dev &&
bp->b_blkno == blkno &&
int sts;
int fd = libxfs_device_to_fd(bp->b_dev);
- sts = pwrite64(fd, bp->b_addr, bp->b_bcount, BBTOOFF64(bp->b_blkno));
+ sts = pwrite64(fd, bp->b_addr, bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_blkno));
if (sts < 0) {
fprintf(stderr, _("%s: pwrite64 failed: %s\n"),
progname, strerror(errno));
}
#ifdef IO_DEBUG
fprintf(stderr, "writebufr wrote %ubytes, blkno=%llu(%llu), %p\n",
- bp->b_bcount, BBTOOFF64(bp->b_blkno), bp->b_blkno, bp);
+ bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_blkno), bp->b_blkno, bp);
#endif
bp->b_flags |= LIBXFS_B_UPTODATE;
bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT);
#define xfs_iformat libxfs_iformat
#define xfs_ichgtime libxfs_ichgtime
#define xfs_bmapi libxfs_bmapi
+#define xfs_bmapi_single libxfs_bmapi_single
#define xfs_bmap_finish libxfs_bmap_finish
#define xfs_bmap_del_free libxfs_bmap_del_free
#define xfs_bunmapi libxfs_bunmapi
log_copy.c log_dump.c log_misc.c \
log_print_all.c log_print_trans.c
-LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID)
+LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBRT)
LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
LLDFLAGS = -static
HFILES = xfs_mkfs.h
CFILES = maxtrres.c proto.c xfs_mkfs.c
-LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBDISK)
+LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBDISK) $(LIBRT)
LTDEPENDENCIES = $(LIBXFS) $(LIBDISK)
LLDFLAGS = -static
HFILES = agheader.h attr_repair.h avl.h avl64.h bmap.h dinode.h dir.h \
dir2.h dir_stack.h err_protos.h globals.h incore.h protos.h rt.h \
- scan.h versions.h
+ scan.h versions.h prefetch.h
CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c dino_chunks.c \
dinode.c dir.c dir2.c dir_stack.c globals.c incore.c \
incore_bmc.c init.c incore_ext.c incore_ino.c io.c phase1.c \
phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c rt.c sb.c \
- scan.c versions.c xfs_repair.c
+ prefetch.c scan.c versions.c xfs_repair.c
-LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBPTHREAD)
+LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID) $(LIBPTHREAD) $(LIBRT)
LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
LLDFLAGS = -static
#include "err_protos.h"
#include "dir.h"
#include "dinode.h"
+#include "prefetch.h"
#include "versions.h"
/*
{
int num_inos, bogus;
ino_tree_node_t *ino_rec, *first_ino_rec, *prev_ino_rec;
+ ino_tree_node_t *ino_ra;
+
+ ino_ra = do_prefetch ? prefetch_inode_chunks(mp, agno, NULL) : NULL;
first_ino_rec = ino_rec = findfirst_inode_rec(agno);
while (ino_rec != NULL) {
ASSERT(num_inos == XFS_IALLOC_INODES(mp));
+ if (do_prefetch && ino_ra && (first_ino_rec->ino_startnum >= ino_ra->ino_startnum))
+ ino_ra = prefetch_inode_chunks(mp, agno, ino_ra);
+
if (process_inode_chunk(mp, agno, num_inos, first_ino_rec,
ino_discovery, check_dups, extra_attr_check, &bogus)) {
/* XXX - i/o error, we've got a problem */
#include "dinode.h"
#include "dir.h"
#include "bmap.h"
+#include "prefetch.h"
#if XFS_DIR_LEAF_MAPSIZE >= XFS_ATTR_LEAF_MAPSIZE
#define XR_DA_LEAF_MAPSIZE XFS_DIR_LEAF_MAPSIZE
node = NULL;
da_cursor->active = 0;
+ if (do_prefetch && (whichfork == XFS_DATA_FORK))
+ prefetch_dir1(mp, bno, da_cursor);
+
do {
/*
* read in each block along the way and set up cursor
#include "dir.h"
#include "dir2.h"
#include "bmap.h"
+#include "prefetch.h"
/*
* Tag bad directory entries with this.
int t;
bmap_ext_t lbmp;
+ if (do_prefetch)
+ prefetch_dir2(mp, blkmap);
+
*repair = *dot = *dotdot = good = 0;
*parent = NULLFSINO;
ndbno = NULLDFILOFF;
#include "protos.h"
#include "err_protos.h"
#include "pthread.h"
+#include "prefetch.h"
#include <sys/resource.h>
static pthread_key_t dirbuf_key;
ts_init();
increase_rlimit();
+ if (do_prefetch) {
+ do_prefetch = libxfs_lio_init();
+ if (do_prefetch)
+ libxfs_lio_allocate();
+ }
}
#include "protos.h"
#include "err_protos.h"
#include "dinode.h"
+#include "prefetch.h"
#include "versions.h"
static struct cred zerocr;
int i;
int error;
char *ftype;
+ xfs_fsblock_t fblock2;
/*
* traverse down left-side of tree until we hit the
if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
return(fsbno);
+ if (do_prefetch) {
+ fblock2 = NULLFSBLOCK;
+ prefetch_p6_dir1(mp, ino, ip, 0, &fblock2);
+ }
+
do {
/*
* walk down left side of btree, release buffers as you
libxfs_dir2_isblock(NULL, ip, &isblock);
libxfs_dir2_isleaf(NULL, ip, &isleaf);
+ if (do_prefetch && !isblock)
+ prefetch_p6_dir2(mp, ip);
+
/* check directory data */
hashtab = dir_hash_init(ip->i_d.di_size);
for (da_bno = 0, next_da_bno = 0;
--- /dev/null
+#include <libxfs.h>
+#include "prefetch.h"
+#include "aio.h"
+#include "avl.h"
+#include "globals.h"
+#include "agheader.h"
+#include "incore.h"
+#include "dir.h"
+#include "dir2.h"
+#include "dir_stack.h"
+#include "protos.h"
+#include "err_protos.h"
+#include "dinode.h"
+#include "bmap.h"
+#include "versions.h"
+
+int do_prefetch = 1;
+
+ino_tree_node_t *
+prefetch_inode_chunks(xfs_mount_t *mp,
+ xfs_agnumber_t agno,
+ ino_tree_node_t *ino_ra)
+{
+ xfs_agblock_t agbno;
+ libxfs_lio_req_t *liop;
+ int i;
+
+ if (libxfs_lio_ino_count == 0)
+ return NULL;
+
+ liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_INO);
+ if (liop == NULL) {
+ do_prefetch = 0;
+ return NULL;
+ }
+
+ if (ino_ra == NULL)
+ ino_ra = findfirst_inode_rec(agno);
+
+ i = 0;
+ while (ino_ra) {
+ agbno = XFS_AGINO_TO_AGBNO(mp, ino_ra->ino_startnum);
+ liop[i].blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
+ liop[i].len = (int) XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp));
+ i++;
+ ino_ra = next_ino_rec(ino_ra);
+ if (i >= libxfs_lio_ino_count)
+ break;
+ }
+ if (i) {
+ if (libxfs_readbuf_list(mp->m_dev, i, (void *) liop, LIBXFS_LIO_TYPE_INO) == -1)
+ do_prefetch = 0;
+ }
+ libxfs_put_lio_buffer((void *) liop);
+ return (ino_ra);
+}
+
+static void
+prefetch_node(
+ xfs_mount_t *mp,
+ xfs_buf_t *bp,
+ da_bt_cursor_t *da_cursor)
+{
+ xfs_da_intnode_t *node;
+ libxfs_lio_req_t *liop;
+ int i;
+ xfs_dfsbno_t fsbno;
+
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
+ if (INT_GET(node->hdr.count, ARCH_CONVERT) <= 1)
+ return;
+
+ if ((liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_DIR)) == NULL) {
+ return;
+ }
+
+ for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); i++) {
+ if (i == libxfs_lio_dir_count)
+ break;
+
+ fsbno = blkmap_get(da_cursor->blkmap, INT_GET(node->btree[i].before, ARCH_CONVERT));
+ if (fsbno == NULLDFSBNO) {
+ libxfs_put_lio_buffer((void *) liop);
+ return;
+ }
+
+ liop[i].blkno = XFS_FSB_TO_DADDR(mp, fsbno);
+ liop[i].len = XFS_FSB_TO_BB(mp, 1);
+ }
+
+ if (i > 1) {
+ if (libxfs_readbuf_list(mp->m_dev, i, (void *) liop, LIBXFS_LIO_TYPE_DIR) == -1)
+ do_prefetch = 0;
+ }
+
+ libxfs_put_lio_buffer((void *) liop);
+ return;
+}
+
+void
+prefetch_dir1(
+ xfs_mount_t *mp,
+ xfs_dablk_t bno,
+ da_bt_cursor_t *da_cursor)
+{
+ xfs_da_intnode_t *node;
+ xfs_buf_t *bp;
+ xfs_dfsbno_t fsbno;
+ int i;
+
+ fsbno = blkmap_get(da_cursor->blkmap, bno);
+ if (fsbno == NULLDFSBNO)
+ return;
+
+ bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
+ XFS_FSB_TO_BB(mp, 1), 0);
+
+ if (bp == NULL)
+ return;
+
+
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
+ if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) {
+ libxfs_putbuf(bp);
+ return;
+ }
+
+ prefetch_node(mp, bp, da_cursor);
+
+ /* skip prefetching if next level is leaf level */
+ if (INT_GET(node->hdr.level, ARCH_CONVERT) > 1) {
+ for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); i++) {
+ prefetch_dir1(mp,
+ INT_GET(node->btree[i].before, ARCH_CONVERT),
+ da_cursor);
+ }
+ }
+
+ libxfs_putbuf(bp);
+ return;
+}
+
+void
+prefetch_dir2(
+ xfs_mount_t *mp,
+ blkmap_t *blkmap)
+{
+ xfs_dfiloff_t dbno;
+ xfs_dfiloff_t pdbno;
+ bmap_ext_t *bmp;
+ int nex;
+ int i, j, t;
+ libxfs_lio_req_t *liop;
+
+ liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_DIR);
+ if (liop == NULL)
+ return;
+
+ pdbno = NULLDFILOFF; /* previous dbno is NULLDFILOFF */
+ i = 0;
+ while ((dbno = blkmap_next_off(blkmap, pdbno, &t)) < mp->m_dirfreeblk) {
+ if (i == libxfs_lio_dir_count)
+ break;
+ if (dbno == NULLDFILOFF)
+ break;
+ if (mp->m_dirblkfsbs == 1) {
+ xfs_dfsbno_t blk;
+
+ /* avoid bmp realloc/free overhead, use blkmap_get */
+ blk = blkmap_get(blkmap, dbno);
+ if (blk == NULLDFSBNO)
+ break;
+ pdbno = dbno;
+ liop[i].blkno = XFS_FSB_TO_DADDR(mp, blk);
+ liop[i].len = (int) XFS_FSB_TO_BB(mp, 1);
+ i++;
+ }
+ else if (mp->m_dirblkfsbs > 1) {
+ nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp, NULL);
+ if (nex == 0)
+ break;
+ pdbno = dbno + mp->m_dirblkfsbs - 1;
+ for (j = 0; j < nex; j++) {
+ liop[i].blkno = XFS_FSB_TO_DADDR(mp, bmp[j].startblock);
+ liop[i].len = (int) XFS_FSB_TO_BB(mp, bmp[j].blockcount);
+ i++;
+ if (i == libxfs_lio_dir_count)
+ break; /* for loop */
+ }
+ free(bmp);
+ }
+ else {
+ do_error("invalid mp->m_dirblkfsbs %d\n", mp->m_dirblkfsbs);
+ }
+ }
+ if (i > 1) {
+ if (libxfs_readbuf_list(mp->m_dev, i, (void *) liop, LIBXFS_LIO_TYPE_DIR) == -1)
+ do_prefetch = 0;
+ }
+ libxfs_put_lio_buffer((void *) liop);
+}
+
+static void
+prefetch_p6_node(
+ xfs_mount_t *mp,
+ xfs_inode_t *ip,
+ xfs_buf_t *bp)
+{
+ xfs_da_intnode_t *node;
+ libxfs_lio_req_t *liop;
+ int i;
+ xfs_fsblock_t fblock;
+ xfs_dfsbno_t fsbno;
+ xfs_bmbt_irec_t map;
+ int nmap;
+ int error;
+
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
+ if (INT_GET(node->hdr.count, ARCH_CONVERT) <= 1)
+ return;
+
+ if ((liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_DIR)) == NULL) {
+ return;
+ }
+
+ fblock = NULLFSBLOCK;
+
+ for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); i++) {
+ if (i == libxfs_lio_dir_count)
+ break;
+
+ nmap = 1;
+ error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t)
+ INT_GET(node->btree[i].before, ARCH_CONVERT), 1,
+ XFS_BMAPI_METADATA, &fblock, 0,
+ &map, &nmap, NULL);
+
+ if (error || (nmap != 1)) {
+ libxfs_put_lio_buffer((void *) liop);
+ return;
+ }
+
+ if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) {
+ libxfs_put_lio_buffer((void *) liop);
+ return;
+ }
+ liop[i].blkno = XFS_FSB_TO_DADDR(mp, fsbno);
+ liop[i].len = XFS_FSB_TO_BB(mp, 1);
+ }
+
+ if (i > 1) {
+ if (libxfs_readbuf_list(mp->m_dev, i, (void *) liop, LIBXFS_LIO_TYPE_DIR) == -1)
+ do_prefetch = 0;
+ }
+
+ libxfs_put_lio_buffer((void *) liop);
+ return;
+}
+
+void
+prefetch_p6_dir1(
+ xfs_mount_t *mp,
+ xfs_ino_t ino,
+ xfs_inode_t *ip,
+ xfs_dablk_t da_bno,
+ xfs_fsblock_t *fblockp)
+{
+ xfs_da_intnode_t *node;
+ xfs_buf_t *bp;
+ xfs_dfsbno_t fsbno;
+ xfs_bmbt_irec_t map;
+ int nmap;
+ int i;
+ int error;
+
+ nmap = 1;
+ error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1,
+ XFS_BMAPI_METADATA, fblockp, 0,
+ &map, &nmap, NULL);
+ if (error || (nmap != 1)) {
+ return;
+ }
+
+ if ((fsbno = map.br_startblock) == HOLESTARTBLOCK)
+ return;
+
+ bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
+ XFS_FSB_TO_BB(mp, 1), 0);
+
+ if (bp == NULL)
+ return;
+
+
+ node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
+ if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) {
+ libxfs_putbuf(bp);
+ return;
+ }
+
+ prefetch_p6_node(mp, ip, bp);
+
+ /* skip prefetching if next level is leaf level */
+ if (INT_GET(node->hdr.level, ARCH_CONVERT) > 1) {
+ for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); i++) {
+ (void) prefetch_p6_dir1(mp, ino, ip,
+ INT_GET(node->btree[i].before, ARCH_CONVERT),
+ fblockp);
+ }
+ }
+
+ libxfs_putbuf(bp);
+ return;
+}
+
+#define NMAPP 4
+
+void
+prefetch_p6_dir2(
+ xfs_mount_t *mp,
+ xfs_inode_t *ip)
+{
+ xfs_fileoff_t da_bno;
+ xfs_fileoff_t next_da_bno;
+ int i, j;
+ libxfs_lio_req_t *liop;
+ xfs_fsblock_t fsb;
+ int nfsb;
+ int error;
+
+ if ((liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_DIR)) == NULL) {
+ return;
+ }
+ i = 0;
+ for (da_bno = 0, next_da_bno = 0; next_da_bno != NULLFILEOFF; da_bno = next_da_bno) {
+ if (i == libxfs_lio_dir_count)
+ break;
+ next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
+ if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
+ break;
+
+ if (mp->m_dirblkfsbs == 1) {
+ if ((error = libxfs_bmapi_single(NULL, ip, XFS_DATA_FORK, &fsb, da_bno)) != 0) {
+ libxfs_put_lio_buffer((void *) liop);
+ do_prefetch = 0;
+ do_warn("phase6 prefetch: cannot bmap single block err = %d\n", error);
+ return;
+ }
+ if (fsb == NULLFSBLOCK) {
+ libxfs_put_lio_buffer((void *) liop);
+ return;
+ }
+
+ liop[i].blkno = XFS_FSB_TO_DADDR(mp, fsb);
+ liop[i].len = XFS_FSB_TO_BB(mp, 1);
+ i++;
+ }
+ else if ((nfsb = mp->m_dirblkfsbs) > 1) {
+ xfs_fsblock_t firstblock;
+ xfs_bmbt_irec_t map[NMAPP];
+ xfs_bmbt_irec_t *mapp;
+ int nmap;
+
+ if (nfsb > NMAPP) {
+ mapp = malloc(sizeof(*mapp) * nfsb);
+ if (mapp == NULL) {
+ libxfs_put_lio_buffer((void *) liop);
+ do_prefetch = 0;
+ do_warn("phase6 prefetch: cannot allocate mem for map\n");
+ return;
+ }
+ }
+ else {
+ mapp = map;
+ }
+ firstblock = NULLFSBLOCK;
+ nmap = nfsb;
+ if ((error = libxfs_bmapi(NULL, ip, da_bno,
+ nfsb,
+ XFS_BMAPI_METADATA | XFS_BMAPI_AFLAG(XFS_DATA_FORK),
+ &firstblock, 0, mapp, &nmap, NULL))) {
+ libxfs_put_lio_buffer((void *) liop);
+ do_prefetch = 0;
+ do_warn("phase6 prefetch: cannot bmap err = %d\n", error);
+ return;
+ }
+ for (j = 0; j < nmap; j++) {
+ liop[i].blkno = XFS_FSB_TO_DADDR(mp, mapp[j].br_startblock);
+ liop[i].len = (int)XFS_FSB_TO_BB(mp, mapp[j].br_blockcount);
+ i++;
+ if (i == libxfs_lio_dir_count)
+ break; /* for loop */
+ }
+ if (mapp != map)
+ free(mapp);
+
+ }
+ else {
+ do_error("phase6: invalid mp->m_dirblkfsbs %d\n", mp->m_dirblkfsbs);
+ }
+ }
+ if (i > 1) {
+ if (libxfs_readbuf_list(mp->m_dev, i, (void *) liop, LIBXFS_LIO_TYPE_DIR) == -1)
+ do_prefetch = 0;
+ }
+ libxfs_put_lio_buffer((void *) liop);
+}
+
+void
+prefetch_sb(xfs_mount_t *mp, xfs_agnumber_t agno)
+{
+ libxfs_lio_req_t *liop;
+
+ if ((liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_RAW)) == NULL) {
+ do_prefetch = 0;
+ return;
+ }
+
+ liop[0].blkno = XFS_AG_DADDR(mp, agno, XFS_SB_DADDR);
+ liop[1].blkno = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp));
+ liop[2].blkno = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp));
+ liop[0].len = XFS_FSS_TO_BB(mp, 1);
+ liop[1].len = XFS_FSS_TO_BB(mp, 1);
+ liop[2].len = XFS_FSS_TO_BB(mp, 1);
+ if (libxfs_readbuf_list(mp->m_dev, 3, (void *) liop, LIBXFS_LIO_TYPE_RAW) == -1)
+ do_prefetch = 0;
+
+ libxfs_put_lio_buffer((void *) liop);
+}
+
+void
+prefetch_roots(xfs_mount_t *mp, xfs_agnumber_t agno,
+ xfs_agf_t *agf, xfs_agi_t *agi)
+{
+ int i;
+ libxfs_lio_req_t *liop;
+
+ if ((liop = (libxfs_lio_req_t *) libxfs_get_lio_buffer(LIBXFS_LIO_TYPE_RAW)) == NULL) {
+ do_prefetch = 0;
+ return;
+ }
+
+ i = 0;
+ if (agf->agf_roots[XFS_BTNUM_BNO] != 0 &&
+ verify_agbno(mp, agno, agf->agf_roots[XFS_BTNUM_BNO])) {
+ liop[i].blkno = XFS_AGB_TO_DADDR(mp, agno, agf->agf_roots[XFS_BTNUM_BNO]);
+ liop[i].len = XFS_FSB_TO_BB(mp, 1);
+ i++;
+ }
+ if (agf->agf_roots[XFS_BTNUM_CNT] != 0 &&
+ verify_agbno(mp, agno, agf->agf_roots[XFS_BTNUM_CNT])) {
+ liop[i].blkno = XFS_AGB_TO_DADDR(mp, agno, agf->agf_roots[XFS_BTNUM_CNT]);
+ liop[i].len = XFS_FSB_TO_BB(mp, 1);
+ i++;
+ }
+ if (agi->agi_root != 0 && verify_agbno(mp, agno, agi->agi_root)) {
+ liop[i].blkno = XFS_AGB_TO_DADDR(mp, agno, agi->agi_root);
+ liop[i].len = XFS_FSB_TO_BB(mp, 1);
+ i++;
+ }
+ if (i > 1) {
+ if (libxfs_readbuf_list(mp->m_dev, i, (void *) liop, LIBXFS_LIO_TYPE_RAW) == -1)
+ do_prefetch = 0;
+ }
+
+ libxfs_put_lio_buffer((void *) liop);
+}
--- /dev/null
+#ifndef _XFS_REPAIR_PREFETCH_H
+#define _XFS_REPAIR_PREFETCH_H
+
+struct blkmap;
+struct da_bt_cursor;
+struct xfs_mount;
+
+extern int do_prefetch;
+
+struct ino_tree_node *prefetch_inode_chunks(
+ struct xfs_mount *,
+ xfs_agnumber_t,
+ struct ino_tree_node *);
+
+extern void prefetch_dir1(
+ struct xfs_mount *mp,
+ xfs_dablk_t bno,
+ struct da_bt_cursor *da_cursor);
+
+extern void prefetch_dir2(
+ struct xfs_mount *mp,
+ struct blkmap *blkmap);
+
+extern void prefetch_p6_dir1(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ struct xfs_inode *ip,
+ xfs_dablk_t da_bno,
+ xfs_fsblock_t *fblockp);
+
+extern void prefetch_p6_dir2(
+ struct xfs_mount *mp,
+ struct xfs_inode *ip);
+
+extern void prefetch_sb(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno);
+
+extern void prefetch_roots(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agf_t *agf,
+ xfs_agi_t *agi);
+
+#endif /* _XFS_REPAIR_PREFETCH_H */
#include "scan.h"
#include "versions.h"
#include "bmap.h"
+#include "prefetch.h"
extern int verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb,
xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i);
agi_dirty = agf_dirty = sb_dirty = 0;
+ if (do_prefetch)
+ prefetch_sb(mp, agno);
+
sbbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
XFS_FSS_TO_BB(mp, 1), 0);
if (!sbbuf) {
scan_freelist(agf);
+ if (do_prefetch)
+ prefetch_roots(mp, agno, agf, agi);
+
if (INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT) != 0 &&
verify_agbno(mp, agno,
INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT)))
#include "protos.h"
#include "incore.h"
#include "err_protos.h"
+#include "prefetch.h"
#define rounddown(x, y) (((x)/(y))*(y))
"ihash",
#define BHASH_SIZE 3
"bhash",
+#define PREFETCH_INO_CNT 4
+ "pfino",
+#define PREFETCH_DIR_CNT 5
+ "pfdir",
+#define PREFETCH_AIO_CNT 6
+ "pfaio",
NULL
};
* XXX have to add suboption processing here
* attributes, quotas, nlinks, aligned_inos, sb_fbits
*/
- while ((c = getopt(argc, argv, "o:fl:r:LnDvVd")) != EOF) {
+ while ((c = getopt(argc, argv, "o:fl:r:LnDvVdP")) != EOF) {
switch (c) {
case 'D':
dumpcore = 1;
case BHASH_SIZE:
libxfs_bhash_size = (int) strtol(val, 0, 0);
break;
+ case PREFETCH_INO_CNT:
+ libxfs_lio_ino_count = (int) strtol(val, 0, 0);
+ break;
+ case PREFETCH_DIR_CNT:
+ libxfs_lio_dir_count = (int) strtol(val, 0, 0);
+ break;
+ case PREFETCH_AIO_CNT:
+ libxfs_lio_aio_count = (int) strtol(val, 0, 0);
+ break;
default:
unknown('o', val);
break;
case 'V':
printf(_("%s version %s\n"), progname, VERSION);
exit(0);
+ case 'P':
+ do_prefetch ^= 1;
+ break;
case '?':
usage();
}
if ((fs_name = argv[optind]) == NULL)
usage();
+
+ if (!isa_file) {
+ if ((fs_name = libxfs_findrawpath(fs_name)) == NULL)
+ do_error("couldn't find raw device for %s\n", fs_name);
+ }
}
void