diff --git a/src/flashcache_conf.c b/src/flashcache_conf.c index 0ca05f7..5d9b555 100644 --- a/src/flashcache_conf.c +++ b/src/flashcache_conf.c @@ -1713,7 +1713,12 @@ static struct target_type flashcache_target = { .dtr = flashcache_dtr, .map = flashcache_map, .status = flashcache_status, +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) .ioctl = flashcache_ioctl, +#else + .prepare_ioctl = flashcache_prepare_ioctl, + .message = flashcache_message, +#endif .iterate_devices = flashcache_iterate_devices, }; diff --git a/src/flashcache_ioctl.c b/src/flashcache_ioctl.c index 52ac56f..4fd1dcc 100644 --- a/src/flashcache_ioctl.c +++ b/src/flashcache_ioctl.c @@ -503,6 +503,82 @@ skip_sequential_io(struct cache_c *dmc, struct bio *bio) * exit, for cases where the process dies after marking itself * non-cacheable. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) +int +flashcache_prepare_ioctl(struct dm_target *ti, + struct block_device **bdev, fmode_t *mode) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + + *bdev = dmc->disk_dev->bdev; + + return 0; +} + +int +flashcache_message(struct dm_target *ti, unsigned argc, char **argv) +{ + struct cache_c *dmc = (struct cache_c *) ti->private; + int list; + long long upid; + pid_t pid = 0; + + /* + * whitelist|blacklist add|del + * whitelist|blacklist delall + */ + if (argc < 2) + return -EINVAL; + + /* Decode the primary command. */ + if (strcmp(argv[0], "whitelist") == 0) { + list = FLASHCACHE_WHITELIST; + } else if (strcmp(argv[0], "blacklist") == 0) { + list = FLASHCACHE_BLACKLIST; + } else { + return -EINVAL; + } + + /* Decode the sub-command. */ + if (strcmp(argv[1], "add") == 0) { + int rr; + if (argc != 3) + return -EINVAL; + + /* Decode the pid. */ + if (kstrtoull(argv[2], 10, &upid)) + return -EINVAL; + pid = (pid_t)upid; + + flashcache_add_pid(dmc, pid, list); + return 0; + + } else if (strcmp(argv[1], "del") == 0) { + if (argc != 3) + return -EINVAL; + + /* Decode the pid. */ + if (kstrtoull(argv[2], 10, &upid)) + return -EINVAL; + pid = (pid_t)upid; + + flashcache_del_pid(dmc, pid, list); + return 0; + + } else if (strcmp(argv[1], "delall") == 0) { + if (argc != 2) + return -EINVAL; + + flashcache_del_all_pids(dmc, list, 0); + return 0; + + } else { + return -EINVAL; + } +} + +#else + int #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) flashcache_ioctl(struct dm_target *ti, struct inode *inode, @@ -561,3 +637,5 @@ flashcache_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) } } + +#endif diff --git a/src/flashcache_ioctl.h b/src/flashcache_ioctl.h index 105df6f..d3d7e25 100644 --- a/src/flashcache_ioctl.h +++ b/src/flashcache_ioctl.h @@ -51,6 +51,11 @@ enum { #define FLASHCACHEDELALLWHITELIST _IOW(FLASHCACHE_IOCTL, FLASHCACHEDELWHITELISTALL_CMD, pid_t) #ifdef __KERNEL__ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) +int flashcache_message(struct dm_target *ti, unsigned argc, char **argv); +int flashcache_prepare_ioctl(struct dm_target *ti, + struct block_device **bdev, fmode_t *mode); +#else #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) int flashcache_ioctl(struct dm_target *ti, struct inode *inode, struct file *filp, unsigned int cmd, @@ -59,6 +64,7 @@ int flashcache_ioctl(struct dm_target *ti, struct inode *inode, int flashcache_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg); #endif +#endif void flashcache_pid_expiry_all_locked(struct cache_c *dmc); int flashcache_uncacheable(struct cache_c *dmc, struct bio *bio); void seq_io_remove_from_lru(struct cache_c *dmc, struct sequential_io *seqio); diff --git a/src/utils/flashcache_setioctl.c b/src/utils/flashcache_setioctl.c index 44d5568..d2d7532 100644 --- a/src/utils/flashcache_setioctl.c +++ b/src/utils/flashcache_setioctl.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,55 @@ void usage(char *pname) exit(1); } +void dm_message(char *cachedev, char list, char action, pid_t pid) +{ + char pidstr[32]; + + char *argv[] = { + "/sbin/dmsetup", + "message", + cachedev, + "0", + /* command */ NULL, + /* sub-command */ NULL, + /* pid */ NULL, + NULL, + }; + + switch (list) { + case 'w': + argv[4] = "whitelist"; + break; + case 'b': + argv[4] = "blacklist"; + break; + default: + return; + } + + switch (action) { + case 'a': + argv[5] = "add"; + break; + case 'r': + argv[5] = "del"; + break; + case 'c': + argv[5] = "delall"; + break; + } + + switch (action) { + case 'a': + case 'r': + snprintf(pidstr, sizeof(pidstr), "%lld", (long long)pid); + argv[6] = pidstr; + break; + } + + execv(argv[0], argv); +} + int main(int argc, char **argv) { @@ -50,6 +100,7 @@ main(int argc, char **argv) intmax_t pidmax; char *tmp; pid_t pid; + int err; while ((c = getopt(argc, argv, "carb:w:")) != -1) { switch (c) { @@ -125,11 +176,18 @@ main(int argc, char **argv) break; } } + err = errno; close(cache_fd); + /* + * Failed with an error indicating the ioctl was not appropriate for the device + * switch to using DM messages. + */ + if (result < 0 && err == ENOTTY) { + dm_message(cachedev, list, action, pid); + } if (result < 0) { fprintf(stderr, "ioctl failed on %s\n", cachedev); exit(1); } return 0; } -