Skip to content

Instantly share code, notes, and snippets.

@yuhong-zhong
Created October 24, 2022 13:57
Show Gist options
  • Save yuhong-zhong/d7d9077659246891cfc52f0d28e63298 to your computer and use it in GitHub Desktop.
Save yuhong-zhong/d7d9077659246891cfc52f0d28e63298 to your computer and use it in GitHub Desktop.
diff --git a/Makefile b/Makefile
index 24a4c1b97bb0..a4c1d842c2e8 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 5
PATCHLEVEL = 8
SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION =-oliver
NAME = Kleptomaniac Octopus
# *DOCUMENTATION*
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 78847b32e137..b9fafce3d1cc 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -360,6 +360,9 @@
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2
+440 common imposter sys_imposter
+441 common init_imposter sys_init_imposter
+442 common get_imposter sys_get_imposter
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 4ee2330c603e..35c5dc6af7b0 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -21,6 +21,7 @@
#include <linux/nvme_ioctl.h>
#include <linux/pm_qos.h>
#include <asm/unaligned.h>
+#include <linux/hrtimer.h>
#include "nvme.h"
#include "fabrics.h"
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 09ffc3246f60..63b143e19ca5 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -490,6 +490,12 @@ static inline void nvme_end_request(struct request *req, __le16 status,
rq->result = result;
/* inject error when permitted by fault injection framework */
nvme_should_fail(req);
+
+ if (req->bio && req->bio->_imposter_level > 0 && _imposter_nvme_driver) {
+ long _index = atomic_long_fetch_inc(&_imposter_nvme_driver_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_nvme_driver[_index], ktime_sub(ktime_get(), req->bio->_imposter_nvme_driver_start));
+ }
+
blk_mq_complete_request(req);
}
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index d4b1ff747123..4bee8dd69997 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -24,6 +24,7 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/sed-opal.h>
#include <linux/pci-p2pdma.h>
+#include <linux/hrtimer.h>
#include "trace.h"
#include "nvme.h"
@@ -467,8 +468,11 @@ static inline void nvme_write_sq_db(struct nvme_queue *nvmeq)
* @write_sq: whether to write to the SQ doorbell
*/
static void nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd,
- bool write_sq)
+ bool write_sq, struct request *req)
{
+ if (req && req->bio && req->bio->_imposter_level > 0) {
+ req->bio->_imposter_device_start = ktime_get();
+ }
spin_lock(&nvmeq->sq_lock);
memcpy(nvmeq->sq_cmds + (nvmeq->sq_tail << nvmeq->sqes),
cmd, sizeof(*cmd));
@@ -863,6 +867,10 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
struct nvme_command cmnd;
blk_status_t ret;
+ if (req->bio && req->bio->_imposter_level > 0) {
+ req->bio->_imposter_nvme_driver_start = ktime_get();
+ }
+
iod->aborted = 0;
iod->npages = -1;
iod->nents = 0;
@@ -891,7 +899,7 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
}
blk_mq_start_request(req);
- nvme_submit_cmd(nvmeq, &cmnd, bd->last);
+ nvme_submit_cmd(nvmeq, &cmnd, bd->last, req);
return BLK_STS_OK;
out_unmap_data:
nvme_unmap_data(dev, req);
@@ -962,6 +970,12 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
}
req = blk_mq_tag_to_rq(nvme_queue_tagset(nvmeq), cqe->command_id);
+
+ if (req->bio && req->bio->_imposter_level > 0 && _imposter_device) {
+ long _index = atomic_long_fetch_inc(&_imposter_device_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_device[_index], ktime_sub(ktime_get(), req->bio->_imposter_device_start));
+ }
+
trace_nvme_sq(req, cqe->sq_head, nvmeq->sq_tail);
nvme_end_request(req, cqe->status, cqe->result);
}
@@ -1062,7 +1076,7 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl)
memset(&c, 0, sizeof(c));
c.common.opcode = nvme_admin_async_event;
c.common.command_id = NVME_AQ_BLK_MQ_DEPTH;
- nvme_submit_cmd(nvmeq, &c, true);
+ nvme_submit_cmd(nvmeq, &c, true, NULL);
}
static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 0ae656e022fd..14e5d0482c7e 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -193,6 +193,11 @@ static void blkdev_bio_end_io_simple(struct bio *bio)
{
struct task_struct *waiter = bio->bi_private;
+ if (bio && bio->_imposter_level > 0 && _imposter_bio) {
+ long _index = atomic_long_fetch_inc(&_imposter_bio_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_bio[_index], ktime_sub(ktime_get(), bio->_imposter_bio_start));
+ }
+
WRITE_ONCE(bio->bi_private, NULL);
blk_wake_io_task(waiter);
}
@@ -230,6 +235,8 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter,
bio.bi_private = current;
bio.bi_end_io = blkdev_bio_end_io_simple;
bio.bi_ioprio = iocb->ki_ioprio;
+ bio._imposter_level = file->_imposter_level;
+ bio._imposter_bio_start = ktime_get();
ret = bio_iov_iter_get_pages(&bio, iter);
if (unlikely(ret))
@@ -299,6 +306,11 @@ static void blkdev_bio_end_io(struct bio *bio)
struct blkdev_dio *dio = bio->bi_private;
bool should_dirty = dio->should_dirty;
+ if (bio && bio->_imposter_level > 0 && _imposter_bio) {
+ long _index = atomic_long_fetch_inc(&_imposter_bio_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_bio[_index], ktime_sub(ktime_get(), bio->_imposter_bio_start));
+ }
+
if (bio->bi_status && !dio->bio.bi_status)
dio->bio.bi_status = bio->bi_status;
@@ -381,6 +393,8 @@ __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)
bio->bi_private = dio;
bio->bi_end_io = blkdev_bio_end_io;
bio->bi_ioprio = iocb->ki_ioprio;
+ bio->_imposter_level = file->_imposter_level;
+ bio->_imposter_bio_start = ktime_get();
ret = bio_iov_iter_get_pages(bio, iter);
if (unlikely(ret)) {
diff --git a/fs/ioctl.c b/fs/ioctl.c
index d69786d1dd91..d3bbcb03d806 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -762,6 +762,148 @@ SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
return ksys_ioctl(fd, cmd, arg);
}
+long *_imposter_device;
+EXPORT_SYMBOL(_imposter_device);
+long *_imposter_nvme_driver;
+EXPORT_SYMBOL(_imposter_nvme_driver);
+long *_imposter_bio;
+EXPORT_SYMBOL(_imposter_bio);
+long *_imposter_fs;
+EXPORT_SYMBOL(_imposter_fs);
+long *_imposter_syscall;
+EXPORT_SYMBOL(_imposter_syscall);
+
+atomic_long_t _imposter_device_index;
+EXPORT_SYMBOL(_imposter_device_index);
+atomic_long_t _imposter_nvme_driver_index;
+EXPORT_SYMBOL(_imposter_nvme_driver_index);
+atomic_long_t _imposter_bio_index;
+EXPORT_SYMBOL(_imposter_bio_index);
+atomic_long_t _imposter_fs_index;
+EXPORT_SYMBOL(_imposter_fs_index);
+atomic_long_t _imposter_syscall_index;
+EXPORT_SYMBOL(_imposter_syscall_index);
+
+SYSCALL_DEFINE2(imposter, int, fd, int, level)
+{
+ struct fd f = fdget_pos(fd);
+ long ret = -EBADF;
+
+ if (f.file) {
+ f.file->_imposter_level = level;
+ fdput_pos(f);
+ ret = 0;
+ } else {
+ printk("imposter: bad file descriptor\n");
+ }
+
+ return ret;
+}
+
+SYSCALL_DEFINE0(init_imposter)
+{
+ long i;
+
+ _imposter_device = vmalloc(_IMPOSTER_ARR_SIZE * sizeof(long));
+ if (!_imposter_device) {
+ printk("cannot allocate buffer for _imposter_device\n");
+ return -ENOMEM;
+ }
+ _imposter_nvme_driver = vmalloc(_IMPOSTER_ARR_SIZE * sizeof(long));
+ if (!_imposter_nvme_driver) {
+ printk("cannot allocate buffer for _imposter_nvme_driver\n");
+ return -ENOMEM;
+ }
+ _imposter_bio = vmalloc(_IMPOSTER_ARR_SIZE * sizeof(long));
+ if (!_imposter_bio) {
+ printk("cannot allocate buffer for _imposter_bio\n");
+ return -ENOMEM;
+ }
+ _imposter_fs = vmalloc(_IMPOSTER_ARR_SIZE * sizeof(long));
+ if (!_imposter_fs) {
+ printk("cannot allocate buffer for _imposter_fs\n");
+ return -ENOMEM;
+ }
+ _imposter_syscall = vmalloc(_IMPOSTER_ARR_SIZE * sizeof(long));
+ if (!_imposter_syscall) {
+ printk("cannot allocate buffer for _imposter_syscall\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < _IMPOSTER_ARR_SIZE; ++i) {
+ _imposter_device[i] = -1;
+ _imposter_nvme_driver[i] = -1;
+ _imposter_bio[i] = -1;
+ _imposter_fs[i] = -1;
+ _imposter_syscall[i] = -1;
+ }
+
+ atomic_long_set(&_imposter_device_index, 0);
+ atomic_long_set(&_imposter_nvme_driver_index, 0);
+ atomic_long_set(&_imposter_bio_index, 0);
+ atomic_long_set(&_imposter_fs_index, 0);
+ atomic_long_set(&_imposter_syscall_index, 0);
+
+ return 0;
+}
+
+SYSCALL_DEFINE2(get_imposter, int, type, long, index)
+{
+ if (index < 0 || index >= _IMPOSTER_ARR_SIZE) {
+ printk("get_imposter: invalid index\n");
+ return -1;
+ }
+
+ if (type < 0 || type >= 5) {
+ printk("get_imposter: invalid type\n");
+ return -1;
+ }
+
+ long value;
+ switch (type) {
+ case 0:
+ if (!_imposter_device) {
+ value = -1;
+ } else {
+ value = READ_ONCE(_imposter_device[index]);
+ }
+ break;
+ case 1:
+ if (!_imposter_nvme_driver) {
+ value = -1;
+ } else {
+ value = READ_ONCE(_imposter_nvme_driver[index]);
+ }
+ break;
+ case 2:
+ if (!_imposter_bio) {
+ value = -1;
+ } else {
+ value = READ_ONCE(_imposter_bio[index]);
+ }
+ break;
+ case 3:
+ if (!_imposter_fs) {
+ value = -1;
+ } else {
+ value = READ_ONCE(_imposter_fs[index]);
+ }
+ break;
+ case 4:
+ if (!_imposter_syscall) {
+ value = -1;
+ } else {
+ value = READ_ONCE(_imposter_syscall[index]);
+ }
+ break;
+ default:
+ printk("get_imposter: unrecognized type\n");
+ value = -1;
+ }
+
+ return value;
+}
+
#ifdef CONFIG_COMPAT
/**
* compat_ptr_ioctl - generic implementation of .compat_ioctl file operation
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index ec7b78e6feca..c9b3f656024b 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -67,6 +67,11 @@ static void iomap_dio_submit_bio(struct iomap_dio *dio, struct iomap *iomap,
bio_set_polled(bio, dio->iocb);
dio->submit.last_queue = bdev_get_queue(iomap->bdev);
+
+ if (bio && bio->_imposter_level > 0) {
+ bio->_imposter_bio_start = ktime_get();
+ }
+
if (dio->dops && dio->dops->submit_io)
dio->submit.cookie = dio->dops->submit_io(
file_inode(dio->iocb->ki_filp),
@@ -153,6 +158,11 @@ static void iomap_dio_bio_end_io(struct bio *bio)
struct iomap_dio *dio = bio->bi_private;
bool should_dirty = (dio->flags & IOMAP_DIO_DIRTY);
+ if (bio && bio->_imposter_level > 0 && _imposter_bio) {
+ long _index = atomic_long_fetch_inc(&_imposter_bio_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_bio[_index], ktime_sub(ktime_get(), bio->_imposter_bio_start));
+ }
+
if (bio->bi_status)
iomap_dio_set_error(dio, blk_status_to_errno(bio->bi_status));
@@ -276,6 +286,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
bio->bi_ioprio = dio->iocb->ki_ioprio;
bio->bi_private = dio;
bio->bi_end_io = iomap_dio_bio_end_io;
+ bio->_imposter_level = dio->iocb->ki_filp->_imposter_level;
ret = bio_iov_iter_get_pages(bio, dio->submit.iter);
if (unlikely(ret)) {
diff --git a/fs/read_write.c b/fs/read_write.c
index 4fb797822567..1f86de544fde 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -21,6 +21,7 @@
#include <linux/mount.h>
#include <linux/fs.h>
#include "internal.h"
+#include <linux/hrtimer.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
@@ -614,7 +615,57 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
- return ksys_read(fd, buf, count);
+ struct fd f;
+ int _imposter_level;
+ loff_t pos, *ppos;
+
+ /* check imposter info */
+ f = fdget_pos(fd);
+ if (!f.file) {
+ return -EBADF;
+ }
+ _imposter_level = f.file->_imposter_level;
+ ppos = file_ppos(f.file);
+ if (ppos) {
+ pos = *ppos;
+ }
+ fdput_pos(f);
+
+ if (_imposter_level == 0) {
+ /* normal read */
+ return ksys_read(fd, buf, count);
+ } else {
+ /* imposter read */
+ ktime_t _imposter_syscall_start = ktime_get();
+
+ if (!ppos) {
+ printk("imposter read: invalid offset\n");
+ return -EBADF;
+ }
+ long index = pos >> 12;
+ int i;
+ for (i = 0; i < _imposter_level; ++i) {
+ if (i > 0) {
+ off_t lseek_ret = ksys_lseek(fd, index << 12, SEEK_SET);
+ if (lseek_ret != index << 12) {
+ printk("imposter read: ksys_lseek failed\n");
+ return -EBADF;
+ }
+ }
+ ssize_t read_ret = ksys_read(fd, buf, count);
+ if (read_ret != count) {
+ printk("imposter read: ksys_read failed\n");
+ return -EBADF;
+ }
+ index = (index * 1103515245 + 12345) % (1 << 23);
+ }
+
+ if (_imposter_syscall) {
+ long _index = atomic_long_fetch_inc(&_imposter_syscall_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_syscall[_index], ktime_sub(ktime_get(), _imposter_syscall_start));
+ }
+ return count;
+ }
}
ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index ccb895f911b1..d129cb2301aa 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -211,6 +211,11 @@ struct bio {
struct bio_set *bi_pool;
+ int _imposter_level;
+ ktime_t _imposter_device_start;
+ ktime_t _imposter_nvme_driver_start;
+ ktime_t _imposter_bio_start;
+
/*
* We can inline a number of vecs at the end of the bio, to avoid
* double allocations for a small number of bio_vecs. This member
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f5abba86107d..ee3f29d055a5 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -39,10 +39,25 @@
#include <linux/fs_types.h>
#include <linux/build_bug.h>
#include <linux/stddef.h>
+#include <linux/hrtimer.h>
#include <asm/byteorder.h>
#include <uapi/linux/fs.h>
+#ifndef _IMPOSTER_ARR_SIZE
+#define _IMPOSTER_ARR_SIZE 3750000
+#endif
+extern long *_imposter_device;
+extern long *_imposter_nvme_driver;
+extern long *_imposter_bio;
+extern long *_imposter_fs;
+extern long *_imposter_syscall;
+extern atomic_long_t _imposter_device_index;
+extern atomic_long_t _imposter_nvme_driver_index;
+extern atomic_long_t _imposter_bio_index;
+extern atomic_long_t _imposter_fs_index;
+extern atomic_long_t _imposter_syscall_index;
+
struct backing_dev_info;
struct bdi_writeback;
struct bio;
@@ -950,6 +965,8 @@ struct file {
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;
+ int _imposter_level;
+
/*
* Protects f_ep_links, f_flags.
* Must not be taken from IRQ context.
@@ -1899,7 +1916,17 @@ struct inode_operations {
static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio,
struct iov_iter *iter)
{
- return file->f_op->read_iter(kio, iter);
+ ktime_t _imposter_fs_start;
+ ssize_t ret;
+ if (file && file->_imposter_level > 0 && _imposter_fs) {
+ _imposter_fs_start = ktime_get();
+ }
+ ret = file->f_op->read_iter(kio, iter);
+ if (file && file->_imposter_level > 0 && _imposter_fs) {
+ long _index = atomic_long_fetch_inc(&_imposter_fs_index) % _IMPOSTER_ARR_SIZE;
+ WRITE_ONCE(_imposter_fs[_index], ktime_sub(ktime_get(), _imposter_fs_start));
+ }
+ return ret;
}
static inline ssize_t call_write_iter(struct file *file, struct kiocb *kio,
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 6d454886bcaf..96118ff7dc98 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -135,6 +135,20 @@
#include <linux/kasan.h>
+#ifndef _IMPOSTER_ARR_SIZE
+#define _IMPOSTER_ARR_SIZE 3750000
+#endif
+extern long *_imposter_device;
+extern long *_imposter_nvme_driver;
+extern long *_imposter_bio;
+extern long *_imposter_fs;
+extern long *_imposter_syscall;
+extern atomic_long_t _imposter_device_index;
+extern atomic_long_t _imposter_nvme_driver_index;
+extern atomic_long_t _imposter_bio_index;
+extern atomic_long_t _imposter_fs_index;
+extern atomic_long_t _imposter_syscall_index;
+
struct mem_cgroup;
/*
* struct kmem_cache related prototypes
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index b951a87da987..a4136cbb5aa0 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1424,4 +1424,8 @@ long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems,
unsigned int nsops,
const struct old_timespec32 __user *timeout);
+asmlinkage long sys_imposter(int fd, int level);
+asmlinkage long sys_init_imposter(void);
+asmlinkage long sys_get_imposter(int type, long index);
+
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment