@@ -18,7 +18,7 @@ LIBS=-luuid
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
btrfs \
- btrfs-map-logical
+ btrfs-map-logical btrfs-reada
# make C=1 to enable sparse
ifdef C
@@ -62,6 +62,9 @@ btrfs-debug-tree: $(objects) debug-tree.o
btrfs-zero-log: $(objects) btrfs-zero-log.o
gcc $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS)
+btrfs-reada: $(objects) btrfs-reada.o
+ gcc $(CFLAGS) -o btrfs-reada $(objects) btrfs-reada.o $(LDFLAGS) $(LIBS)
+
btrfstune: $(objects) btrfstune.o
gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
new file mode 100644
@@ -0,0 +1,180 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <uuid/uuid.h>
+#include <ctype.h>
+
+
+#include "kerncompat.h"
+#include "btrfs_cmds.h"
+#include "version.h"
+#include "ioctl.h"
+#include "ctree.h"
+
+static int open_file_or_dir(const char *fname)
+{
+ int ret;
+ struct stat st;
+ DIR *dirstream;
+ int fd;
+
+ ret = stat(fname, &st);
+ if (ret < 0)
+ return -1;
+
+ if (S_ISDIR(st.st_mode)) {
+ dirstream = opendir(fname);
+ if (!dirstream)
+ return -2;
+ fd = dirfd(dirstream);
+ } else {
+ fd = open(fname, O_RDWR);
+ }
+ if (fd < 0)
+ return -3;
+
+ return fd;
+}
+
+void usage(void)
+{
+ printf("usage: btrfs-reada [-w] <mntpnt> [<tree> [<start> [<end>]]]\n");
+ printf(" <start|end>: max|<num>[:<num>[:<num>]]\n");
+ printf(" <tree>: csum|extent|<num>\n");
+ printf(" -w: wait\n");
+ printf(" -t: read tree the old fashioned way\n");
+ exit(1);
+}
+
+void parse_key(struct btrfs_key *key, char *p)
+{
+ char *n;
+
+ if (strcmp(p, "max") == 0) {
+ key->objectid = -1LL;
+ key->type = -1;
+ key->offset = -1LL;
+ return;
+ }
+ memset(key, 0, sizeof(*key));
+ n = strtok(p, ":");
+ if (n == NULL)
+ usage();
+ key->objectid = atoll(n);
+
+ n = strtok(p, ":");
+ if (n == NULL)
+ return;
+ key->type = atoi(n);
+
+ n = strtok(p, ":");
+ if (n == NULL)
+ return;
+ key->offset = atoll(n);
+}
+
+int main(int argc, char *argv[])
+{
+ char *mntpnt;
+ int fdmnt;
+ int res;
+ struct btrfs_ioctl_reada_args reada_args;
+ u64 tree = BTRFS_EXTENT_TREE_OBJECTID;
+ int wait = 0;
+ int trad = 0;
+ struct btrfs_key start = { 0, 0, 0};
+ struct btrfs_key end = { -1LL, -1, -1LL};
+
+ while (1) {
+ int c = getopt(argc, argv, "wth");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'w':
+ wait = 1;
+ break;
+ case 't':
+ trad = 1;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ if (optind < argc) {
+ mntpnt = argv[optind++];
+ } else {
+ usage();
+ exit(1);
+ }
+ if (optind < argc) {
+ char *p = argv[optind++];
+ if (strcmp(p, "extent") == 0) {
+ tree = BTRFS_EXTENT_TREE_OBJECTID;
+ } else if (strcmp(p, "csum") == 0) {
+ tree = BTRFS_CSUM_TREE_OBJECTID;
+ } else {
+ tree = atoll(p);
+ if (tree == 0) {
+ printf("inval tree\n");
+ usage();
+ }
+ }
+ }
+ if (optind < argc)
+ parse_key(&start, argv[optind++]);
+ if (optind < argc)
+ parse_key(&end, argv[optind++]);
+
+ fdmnt = open_file_or_dir(mntpnt);
+ if (fdmnt < 0) {
+ fprintf(stderr, "ERROR: can't access '%s'\n", mntpnt);
+ return 12;
+ }
+
+ memset(&reada_args, 0, sizeof(reada_args));
+ reada_args.flags = 0;
+ if (wait)
+ reada_args.flags |= BTRFS_READA_IOC_FLAGS_WAIT;
+ if (trad)
+ reada_args.flags |= BTRFS_READA_IOC_FLAGS_TRAD;
+ reada_args.tree = tree;
+ reada_args.start_objectid = start.objectid;
+ reada_args.start_type = start.type;
+ reada_args.start_offset = start.offset;
+ reada_args.end_objectid = end.objectid;
+ reada_args.end_type = end.type;
+ reada_args.end_offset = end.offset;
+ res = ioctl(fdmnt, BTRFS_IOC_READA_TEST, &reada_args);
+ if (res)
+ printf("ioctl return %d, %s\n", res, strerror(errno));
+
+ return 0;
+}
+
@@ -132,6 +132,20 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_space_info spaces[0];
};
+#define BTRFS_READA_IOC_FLAGS_WAIT 1
+#define BTRFS_READA_IOC_FLAGS_TRAD 2
+struct btrfs_ioctl_reada_args {
+ __u64 flags;
+ __u64 tree;
+ __u64 start_objectid;
+ __u8 start_type;
+ __u64 start_offset;
+ __u64 end_objectid;
+ __u8 end_type;
+ __u64 end_offset;
+ __u64 unused[100];
+};
+
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -169,4 +183,6 @@ struct btrfs_ioctl_space_args {
#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
struct btrfs_ioctl_space_args)
+#define BTRFS_IOC_READA_TEST _IOW(BTRFS_IOCTL_MAGIC, 99, \
+ struct btrfs_ioctl_reada_args)
#endif
This is a simple interface to test the new readahead-facility. You can trigger a readahead in the kernel for a given tree and key range. The default is to read the full extent tree. You can also specify to wait on it to finish (-w), or choose the traditional tree walk (-t) instead. Signed-off-by: Arne Jansen <sensille@gmx.net> --- Makefile | 5 +- btrfs-reada.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ioctl.h | 16 +++++ 3 files changed, 200 insertions(+), 1 deletions(-) create mode 100644 btrfs-reada.c