@@ -48,6 +48,7 @@ static void print_usage(void)
{
printf("usage: btrfsctl [ -d file|dir] [ -s snap_name subvol|tree ]\n");
printf(" [-r size] [-A device] [-a] [-c] [-D dir .]\n");
+ printf(" [-t file] [-T file] [-h filename [0-2]]\n");
printf("\t-d filename: defragments one file\n");
printf("\t-d directory: defragments the entire Btree\n");
printf("\t-s snap_name dir: creates a new snapshot of dir\n");
@@ -57,6 +58,14 @@ static void print_usage(void)
printf("\t-a: scans all devices for Btrfs filesystems\n");
printf("\t-c: forces a single FS sync\n");
printf("\t-D: delete snapshot\n");
+ printf("\t-t filename: dump indexed heat information for a file\n");
+ printf("\t-T filename: dump live heat informaton for a file\n");
+ printf("\t-h filename: query heat tracking/migration status\n");
+ printf("\t-h filename level: set heat tracking level:\n");
+ printf("\t\tlevel =\n");
+ printf("\t\t0: no tracking or relocation\n");
+ printf("\t\t1: access tracking only\n");
+ printf("\t\t2: tracking and automatic migration to SSD\n");
printf("\t-m [tree id] directory: set the default mounted subvolume"
" to the [tree id] or the directory\n");
printf("%s\n", BTRFS_BUILD_VERSION);
@@ -99,12 +108,14 @@ int main(int ac, char **av)
int fd;
int ret;
struct btrfs_ioctl_vol_args args;
+ struct btrfs_ioctl_heat_info hotinfo;
char *name = NULL;
int i;
unsigned long command = 0;
int len;
char *fullpath;
u64 objectid = 0;
+ int heatarg;
if (ac == 2 && strcmp(av[1], "-a") == 0) {
fprintf(stderr, "Scanning for Btrfs filesystems\n");
@@ -205,6 +216,38 @@ int main(int ac, char **av)
exit(1);
}
}
+ } else if (strcmp(av[i], "-t") == 0) {
+ if (i >= ac - 1) {
+ fprintf(stderr,
+ "-t requires a file argument\n");
+ print_usage();
+ }
+ hotinfo.live = 0;
+ command = BTRFS_IOC_GET_HEAT_INFO;
+ } else if (strcmp(av[i], "-T") == 0) {
+ if (i >= ac - 1) {
+ fprintf(stderr,
+ "-T requires a file argument\n");
+ print_usage();
+ }
+ hotinfo.live = 1;
+ command = BTRFS_IOC_GET_HEAT_INFO;
+ } else if (strcmp(av[i], "-h") == 0) {
+ if (i == ac - 2) {
+ command = BTRFS_IOC_GET_HEAT_OPTS;
+ } else if (i == ac - 3) {
+ command = BTRFS_IOC_SET_HEAT_OPTS;
+ heatarg = atoi(av[i + 2]);
+ } else {
+ fprintf(stderr, "-h invalid number of "
+ "arguments\n");
+ print_usage();
+ exit(1);
+ }
+
+ fprintf(stderr, "Btrfs hot data tracking: `%s'\n\n",
+ av[i + 1]);
+ av[i + 2] = av[i + 1];
}
}
if (command == 0) {
@@ -236,6 +279,70 @@ int main(int ac, char **av)
} else if (command == BTRFS_IOC_DEFAULT_SUBVOL) {
printf("objectid is %llu\n", objectid);
ret = ioctl(fd, command, &objectid);
+ } else if (command == BTRFS_IOC_GET_HEAT_INFO) {
+ strcpy(hotinfo.filename, fname);
+ ret = ioctl(fd, command, &hotinfo);
+ if (ret == 0) {
+ printf("Btrfs file hotness information\n");
+ printf("%s\n\n", hotinfo.filename);
+ printf("Last write: %llu\n",
+ (u64) hotinfo.last_write_time);
+ printf("Last read: %llu\n",
+ (u64) hotinfo.last_read_time);
+ printf("Average write delta: %llu\n",
+ (u64) hotinfo.avg_delta_writes);
+ printf("Average read delta: %llu\n",
+ (u64) hotinfo.avg_delta_reads);
+ printf("Number of writes: %u\n",
+ (u32) hotinfo.num_writes);
+ printf("Number of reads: %u\n\n",
+ (u32) hotinfo.num_reads);
+ if (hotinfo.live > 0)
+ printf("Temperature (live): %u\n\n",
+ hotinfo.temperature);
+ else
+ printf("Temperature (indexed): %u\n\n",
+ hotinfo.temperature);
+ }
+ } else if (command == BTRFS_IOC_SET_HEAT_OPTS) {
+ ret = ioctl(fd, command, &heatarg);
+ switch (heatarg) {
+ case 0:
+ printf("Turning OFF heat tracking and migration inode "
+ "flags.\n");
+ break;
+ case 1:
+ printf("Turning ON the heat tracking inode flag.\n");
+ printf("Turning OFF the migration inode flag.\n");
+ break;
+ case 2:
+ printf("Turning ON heat tracking and migration inode "
+ "flags.\n");
+ break;
+ default:
+ printf("Invalid heat tracking argument.\n");
+ }
+ printf("(Inode flags can be overridden by mount options)\n\n");
+ } else if (command == BTRFS_IOC_GET_HEAT_OPTS) {
+ ret = ioctl(fd, command, &heatarg);
+ switch (heatarg) {
+ case 0:
+ printf("Heat tracking and migration inode flags are "
+ "OFF.\n");
+ break;
+ case 1:
+ printf("Heat tracking inode flag is ON, migration "
+ "inode flag is OFF.\n");
+ break;
+ case 2:
+ printf("Heat tracking and migration inode flags are "
+ "both ON.\n");
+ break;
+ default:
+ printf("Wrong filesystem type, or invalid status "
+ "returned.\n");
+ }
+ printf("(Inode flags can be overridden by mount options)\n\n");
} else
ret = ioctl(fd, command, &args);
if (ret < 0) {
@@ -22,6 +22,9 @@ unsigned long ioctls[] = {
BTRFS_IOC_INO_LOOKUP,
BTRFS_IOC_DEFAULT_SUBVOL,
BTRFS_IOC_SPACE_INFO,
+ BTRFS_IOC_GET_HEAT_INFO,
+ BTRFS_IOC_SET_HEAT_OPTS,
+ BTRFS_IOC_GET_HEAT_OPTS,
0 };
int main(int ac, char **av)
@@ -132,6 +132,18 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_space_info spaces[0];
};
+struct btrfs_ioctl_heat_info {
+ __u64 avg_delta_reads;
+ __u64 avg_delta_writes;
+ __u64 last_read_time;
+ __u64 last_write_time;
+ __u32 num_reads;
+ __u32 num_writes;
+ char filename[BTRFS_PATH_NAME_MAX + 1];
+ int temperature;
+ __u8 live;
+};
+
#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 +181,16 @@ 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)
+
+/*
+ * Hot data tracking ioctls:
+ *
+ * GET_HEAT_INFO - retrieve frequency of access info on a file
+ * SET_HEAT_OPTS - set whether a file is tracked/migratable
+ * GET_HEAT_OPTS - check whether a file is tracked/migratable
+ */
+#define BTRFS_IOC_GET_HEAT_INFO _IOWR(BTRFS_IOCTL_MAGIC, 21, \
+ struct btrfs_ioctl_heat_info)
+#define BTRFS_IOC_SET_HEAT_OPTS _IOW(BTRFS_IOCTL_MAGIC, 22, int)
+#define BTRFS_IOC_GET_HEAT_OPTS _IOR(BTRFS_IOCTL_MAGIC, 23, int)
#endif