From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752865AbbCXNVz (ORCPT ); Tue, 24 Mar 2015 09:21:55 -0400 Received: from shonan.sfc.wide.ad.jp ([203.178.142.130]:60039 "EHLO mail.sfc.wide.ad.jp" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752764AbbCXNVI (ORCPT ); Tue, 24 Mar 2015 09:21:08 -0400 From: Hajime Tazaki To: linux-arch@vger.kernel.org Cc: Hajime Tazaki , Arnd Bergmann , Jonathan Corbet , Jhristoph Lameter , Jekka Enberg , Javid Rientjes , Joonsoo Kim , Jndrew Morton , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, netdev@vger.kernel.org, linux-mm@kvack.org, Jeff Dike , Richard Weinberger , Rusty Russell , Mathieu Lacage , Christoph Paasch Subject: [RFC PATCH 08/11] lib: other kernel glue layer code Date: Tue, 24 Mar 2015 22:10:39 +0900 Message-Id: <1427202642-1716-9-git-send-email-tazaki@sfc.wide.ad.jp> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1427202642-1716-1-git-send-email-tazaki@sfc.wide.ad.jp> References: <1427202642-1716-1-git-send-email-tazaki@sfc.wide.ad.jp> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org These files are used to provide the same function calls so that other network stack code keeps untouched. Signed-off-by: Hajime Tazaki Signed-off-by: Christoph Paasch --- arch/lib/cred.c | 16 +++ arch/lib/dcache.c | 93 +++++++++++++++ arch/lib/filemap.c | 27 +++++ arch/lib/fs.c | 287 ++++++++++++++++++++++++++++++++++++++++++++ arch/lib/glue.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++ arch/lib/inode.c | 146 +++++++++++++++++++++++ arch/lib/modules.c | 36 ++++++ arch/lib/pid.c | 29 +++++ arch/lib/print.c | 56 +++++++++ arch/lib/proc.c | 164 +++++++++++++++++++++++++ arch/lib/random.c | 53 +++++++++ arch/lib/security.c | 45 +++++++ arch/lib/seq.c | 122 +++++++++++++++++++ arch/lib/splice.c | 20 ++++ arch/lib/super.c | 210 ++++++++++++++++++++++++++++++++ arch/lib/sysfs.c | 83 +++++++++++++ arch/lib/vmscan.c | 26 ++++ 17 files changed, 1749 insertions(+) create mode 100644 arch/lib/cred.c create mode 100644 arch/lib/dcache.c create mode 100644 arch/lib/filemap.c create mode 100644 arch/lib/fs.c create mode 100644 arch/lib/glue.c create mode 100644 arch/lib/inode.c create mode 100644 arch/lib/modules.c create mode 100644 arch/lib/pid.c create mode 100644 arch/lib/print.c create mode 100644 arch/lib/proc.c create mode 100644 arch/lib/random.c create mode 100644 arch/lib/security.c create mode 100644 arch/lib/seq.c create mode 100644 arch/lib/splice.c create mode 100644 arch/lib/super.c create mode 100644 arch/lib/sysfs.c create mode 100644 arch/lib/vmscan.c diff --git a/arch/lib/cred.c b/arch/lib/cred.c new file mode 100644 index 0000000..50e37cc5 --- /dev/null +++ b/arch/lib/cred.c @@ -0,0 +1,16 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +void __put_cred(struct cred *cred) +{ +} +struct cred *prepare_creds(void) +{ + return 0; +} diff --git a/arch/lib/dcache.c b/arch/lib/dcache.c new file mode 100644 index 0000000..a007c20 --- /dev/null +++ b/arch/lib/dcache.c @@ -0,0 +1,93 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + * Frederic Urbani + */ + +#include +#include +#include +#include "sim-assert.h" + +static struct kmem_cache *dentry_cache __read_mostly; +struct kmem_cache *names_cachep __read_mostly; + +/** + * __d_alloc - allocate a dcache entry + * @sb: filesystem it will belong to + * @name: qstr of the name + * + * Allocates a dentry. It returns %NULL if there is insufficient memory + * available. On a success the dentry is returned. The name passed in is + * copied and the copy passed in may be reused after this call. + */ +struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) +{ + struct dentry *dentry; + unsigned char *dname; + + dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL); + if (!dentry) + return NULL; + + if (name->len > DNAME_INLINE_LEN - 1) { + dname = kmalloc(name->len + 1, GFP_KERNEL); + if (!dname) { + kmem_cache_free(dentry_cache, dentry); + return NULL; + } + } else + dname = dentry->d_iname; + dentry->d_name.name = dname; + + dentry->d_name.len = name->len; + dentry->d_name.hash = name->hash; + memcpy(dname, name->name, name->len); + dname[name->len] = 0; + + dentry->d_lockref.count = 1; + dentry->d_flags = 0; + spin_lock_init(&dentry->d_lock); + seqcount_init(&dentry->d_seq); + dentry->d_inode = NULL; + dentry->d_parent = dentry; + dentry->d_sb = sb; + dentry->d_op = NULL; + dentry->d_fsdata = NULL; + INIT_HLIST_BL_NODE(&dentry->d_hash); + INIT_LIST_HEAD(&dentry->d_lru); + INIT_LIST_HEAD(&dentry->d_subdirs); + INIT_HLIST_NODE(&dentry->d_u.d_alias); + INIT_LIST_HEAD(&dentry->d_child); + d_set_d_op(dentry, dentry->d_sb->s_d_op); + +/* this_cpu_inc(nr_dentry); */ + + return dentry; +} + +void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) +{ + WARN_ON_ONCE(dentry->d_op); + WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH | + DCACHE_OP_COMPARE | + DCACHE_OP_REVALIDATE | + DCACHE_OP_DELETE)); + dentry->d_op = op; + if (!op) + return; + if (op->d_hash) + dentry->d_flags |= DCACHE_OP_HASH; + if (op->d_compare) + dentry->d_flags |= DCACHE_OP_COMPARE; + if (op->d_revalidate) + dentry->d_flags |= DCACHE_OP_REVALIDATE; + if (op->d_delete) + dentry->d_flags |= DCACHE_OP_DELETE; + if (op->d_prune) + dentry->d_flags |= DCACHE_OP_PRUNE; + +} diff --git a/arch/lib/filemap.c b/arch/lib/filemap.c new file mode 100644 index 0000000..9a9837c --- /dev/null +++ b/arch/lib/filemap.c @@ -0,0 +1,27 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + * Frederic Urbani + */ + +#include "sim.h" +#include "sim-assert.h" +#include + + +ssize_t generic_file_aio_read(struct kiocb *a, const struct iovec *b, + unsigned long c, loff_t d) +{ + lib_assert(false); + + return 0; +} + +int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma) +{ + return -ENOSYS; +} + diff --git a/arch/lib/fs.c b/arch/lib/fs.c new file mode 100644 index 0000000..766a9a8 --- /dev/null +++ b/arch/lib/fs.c @@ -0,0 +1,287 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + * Frederic Urbani + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sim-assert.h" + +__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock); +struct super_block; + +struct user_namespace init_user_ns; + +int get_sb_pseudo(struct file_system_type *type, char *str, + const struct super_operations *ops, unsigned long z, + struct vfsmount *mnt) +{ + /* called from sockfs_get_sb by kern_mount_data */ + mnt->mnt_sb->s_root = 0; + mnt->mnt_sb->s_op = ops; + return 0; +} +struct inode *new_inode(struct super_block *sb) +{ + /* call sock_alloc_inode through s_op */ + struct inode *inode = sb->s_op->alloc_inode(sb); + + inode->i_ino = 0; + inode->i_sb = sb; + atomic_set(&inode->i_count, 1); + inode->i_state = 0; + return inode; +} +void iput(struct inode *inode) +{ + if (atomic_dec_and_test(&inode->i_count)) + /* call sock_destroy_inode */ + inode->i_sb->s_op->destroy_inode(inode); +} +void inode_init_once(struct inode *inode) +{ + memset(inode, 0, sizeof(*inode)); +} + +/* Implementation taken from vfs_kern_mount from linux/namespace.c */ +struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) +{ + static struct mount local_mnt; + struct mount *mnt = &local_mnt; + struct dentry *root = 0; + + memset(mnt, 0, sizeof(struct mount)); + if (!type) + return ERR_PTR(-ENODEV); + int flags = MS_KERNMOUNT; + char *name = (char *)type->name; + + if (flags & MS_KERNMOUNT) + mnt->mnt.mnt_flags = MNT_INTERNAL; + + root = type->mount(type, flags, name, data); + if (IS_ERR(root)) + return ERR_CAST(root); + + mnt->mnt.mnt_root = root; + mnt->mnt.mnt_sb = root->d_sb; + mnt->mnt_mountpoint = mnt->mnt.mnt_root; + mnt->mnt_parent = mnt; + /* DCE is monothreaded , so we do not care of lock here */ + list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); + + return &mnt->mnt; +} + +int register_filesystem(struct file_system_type *fs) +{ + /* We don't need to register anything because we never + really implement. any kind of filesystem. + return 0 to signal success. */ + return 0; +} + +int alloc_fd(unsigned start, unsigned flags) +{ + lib_assert(false); + return 0; +} +void fd_install(unsigned int fd, struct file *file) +{ + lib_assert(false); +} +void put_unused_fd(unsigned int fd) +{ + lib_assert(false); +} + +struct file *alloc_file(struct path *path, fmode_t mode, + const struct file_operations *fop) +{ + lib_assert(false); + return 0; +} + +struct file *fget(unsigned int fd) +{ + lib_assert(false); + return 0; +} +struct file *fget_light(unsigned int fd, int *fput_needed) +{ + lib_assert(false); + return 0; +} +void fput(struct file *file) +{ +} + +struct dentry *d_alloc(struct dentry *entry, const struct qstr *str) +{ + lib_assert(false); + return 0; +} +void d_instantiate(struct dentry *entry, struct inode *inode) +{ +} +char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, + const char *fmt, ...) +{ + lib_assert(false); + return 0; +} + +struct dentry_stat_t dentry_stat; +struct files_stat_struct files_stat; +struct inodes_stat_t inodes_stat; + +pid_t f_getown(struct file *filp) +{ + lib_assert(false); + return 0; +} + +void f_setown(struct file *filp, unsigned long arg, int force) +{ + lib_assert(false); +} + +void kill_fasync(struct fasync_struct **fs, int a, int b) +{ + lib_assert(false); +} +int fasync_helper(int a, struct file *file, int b, struct fasync_struct **c) +{ + lib_assert(false); + return 0; +} +long sys_close(unsigned int fd) +{ + lib_assert(false); + return 0; +} +ssize_t splice_to_pipe(struct pipe_inode_info *info, + struct splice_pipe_desc *desc) +{ + lib_assert(false); + return 0; +} +int splice_grow_spd(const struct pipe_inode_info *info, + struct splice_pipe_desc *desc) +{ + lib_assert(false); + return 0; +} +void splice_shrink_spd(struct splice_pipe_desc *desc) +{ + lib_assert(false); +} + +ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, + struct file *out, loff_t *poff, size_t len, + unsigned int flags) +{ + lib_assert(false); + return 0; +} +void *generic_pipe_buf_map(struct pipe_inode_info *pipe, + struct pipe_buffer *buf, int atomic) +{ + lib_assert(false); + return 0; +} + +void generic_pipe_buf_unmap(struct pipe_inode_info *pipe, + struct pipe_buffer *buf, void *address) +{ + lib_assert(false); +} + +int generic_pipe_buf_confirm(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) +{ + lib_assert(false); + return 0; +} + +void generic_pipe_buf_release(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) +{ + lib_assert(false); +} + +static int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) +{ + return 1; +} + +void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) +{ + lib_assert(false); +} +int proc_nr_inodes(struct ctl_table *table, int write, void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + lib_assert(false); + return 0; +} + +int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + lib_assert(false); + return 0; +} + +/* + * Handle writeback of dirty data for the device backed by this bdi. Also + * wakes up periodically and does kupdated style flushing. + */ +int bdi_writeback_thread(void *data) +{ + lib_assert(false); + + return 0; +} + +void get_filesystem(struct file_system_type *fs) +{ +} +/* #include */ +unsigned int nr_free_buffer_pages(void) +{ + return 1024; +} + +const struct pipe_buf_operations nosteal_pipe_buf_ops = { + .can_merge = 0, + .confirm = generic_pipe_buf_confirm, + .release = generic_pipe_buf_release, + .steal = generic_pipe_buf_nosteal, + .get = generic_pipe_buf_get, +}; + +ssize_t +generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) +{ + return 0; +} + +unsigned long get_max_files(void) +{ + return NR_FILE; +} diff --git a/arch/lib/glue.c b/arch/lib/glue.c new file mode 100644 index 0000000..9208739 --- /dev/null +++ b/arch/lib/glue.c @@ -0,0 +1,336 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + * Frederic Urbani + */ + +#include /* loff_t */ +#include /* ESPIPE */ +#include /* PAGE_CACHE_SIZE */ +#include /* NAME_MAX */ +#include /* struct kstatfs */ +#include /* HASHDIST_DEFAULT */ +#include +#include +#include +#include +#include +#include "sim-assert.h" +#include "sim.h" +#include "lib.h" + + +struct pipe_buffer; +struct file; +struct pipe_inode_info; +struct wait_queue_t; +struct kernel_param; +struct super_block; +struct tvec_base {}; + +/* defined in fs/exec.c */ +char core_pattern[CORENAME_MAX_SIZE] = "core"; +/* defined in sched.c, used in net/sched/em_meta.c */ +unsigned long avenrun[3]; +/* defined in mm/page_alloc.c, used in net/xfrm/xfrm_hash.c */ +int hashdist = HASHDIST_DEFAULT; +/* defined in mm/page_alloc.c */ +struct pglist_data __refdata contig_page_data; +/* defined in linux/mmzone.h mm/memory.c */ +struct page *mem_map = 0; +/* used during boot. */ +struct tvec_base boot_tvec_bases; +/* used by sysinfo in kernel/timer.c */ +int nr_threads = 0; +/* not very useful in mm/vmstat.c */ +atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS]; + +/* XXX: used in network stack ! */ +unsigned long num_physpages = 0; +unsigned long totalram_pages = 0; + +/* XXX figure out initial value */ +unsigned int interrupt_pending = 0; +static unsigned long g_irqflags = 0; +static unsigned long local_irqflags = 0; +int overflowgid = 0; +int overflowuid = 0; +int fs_overflowgid = 0; +int fs_overflowuid = 0; +unsigned long sysctl_overcommit_kbytes __read_mostly; +DEFINE_PER_CPU(struct task_struct *, ksoftirqd); + +/* from kobject_uevent.c */ +char uevent_helper[UEVENT_HELPER_PATH_LEN] = "dummy-uevent"; +/* from ksysfs.c */ +int rcu_expedited; +/* from rt.c */ +int sched_rr_timeslice = RR_TIMESLICE; +/* from main.c */ +bool initcall_debug; +bool static_key_initialized __read_mostly = false; +unsigned long __start_rodata, __end_rodata; + +unsigned long __raw_local_save_flags(void) +{ + return g_irqflags; +} +unsigned long arch_local_save_flags(void) +{ + return local_irqflags; +} +void arch_local_irq_restore(unsigned long flags) +{ + local_irqflags = flags; +} + +int in_egroup_p(kgid_t grp) +{ + /* called from sysctl code. */ + lib_assert(false); + return 0; +} + +void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) +{ +} + +unsigned long long nr_context_switches(void) +{ + /* we just need to return >0 to avoid the warning + in kernel/rcupdate.c */ + return 1; +} + + +long get_user_pages(struct task_struct *tsk, struct mm_struct *mm, + unsigned long start, unsigned long nr_pages, + int write, int force, struct page **pages, + struct vm_area_struct **vmas) +{ + /* in practice, this function is never called. It's linked in because */ + /* we link in get_user_pages_fast which is included only because it */ + /* is located in mm/util.c */ + lib_assert(false); + return 0; +} + + +unsigned long wrong_size_cmpxchg(volatile void *ptr) +{ + lib_assert(false); +} + +void dump_stack(void) +{ + /* we assert to make sure that we catch whoever calls dump_stack */ + lib_assert(false); +} + + +void lib_printf(const char *str, ...) +{ + va_list args; + + va_start(args, str); + lib_vprintf(str, args); + va_end(args); +} + +void atomic64_inc(atomic64_t *v) +{ + v->counter++; +} + +#include +#include + +static unsigned long __meminitdata nr_kernel_pages; +static unsigned long __meminitdata nr_all_pages; +/* + * allocate a large system hash table from bootmem + * - it is assumed that the hash table must contain an exact power-of-2 + * quantity of entries + * - limit is the number of hash buckets, not the total allocation size + */ +void *__init alloc_large_system_hash(const char *tablename, + unsigned long bucketsize, + unsigned long numentries, + int scale, + int flags, + unsigned int *_hash_shift, + unsigned int *_hash_mask, + unsigned long low_limit, + unsigned long high_limit) +{ + unsigned long long max = high_limit; + unsigned long log2qty, size; + void *table = NULL; + + /* allow the kernel cmdline to have a say */ + if (!numentries) { + /* round applicable memory size up to nearest megabyte */ + numentries = nr_kernel_pages; + numentries += (1UL << (20 - PAGE_SHIFT)) - 1; + numentries >>= 20 - PAGE_SHIFT; + numentries <<= 20 - PAGE_SHIFT; + + /* limit to 1 bucket per 2^scale bytes of low memory */ + if (scale > PAGE_SHIFT) + numentries >>= (scale - PAGE_SHIFT); + else + numentries <<= (PAGE_SHIFT - scale); + + /* Make sure we've got at least a 0-order allocation.. */ + if (unlikely(flags & HASH_SMALL)) { + /* Makes no sense without HASH_EARLY */ + WARN_ON(!(flags & HASH_EARLY)); + if (!(numentries >> *_hash_shift)) { + numentries = 1UL << *_hash_shift; + BUG_ON(!numentries); + } + } else if (unlikely((numentries * bucketsize) < PAGE_SIZE)) + numentries = PAGE_SIZE / bucketsize; + } + numentries = roundup_pow_of_two(numentries); + + /* limit allocation size to 1/16 total memory by default */ + if (max == 0) { + max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4; + do_div(max, bucketsize); + } + + if (numentries > max) + numentries = max; + + log2qty = ilog2(numentries); + + do { + size = bucketsize << log2qty; + if (flags & HASH_EARLY) + table = alloc_bootmem_nopanic(size); + else if (hashdist) + table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL); + else { + /* + * If bucketsize is not a power-of-two, we may free + * some pages at the end of hash table which + * alloc_pages_exact() automatically does + */ + if (get_order(size) < MAX_ORDER) { + table = alloc_pages_exact(size, GFP_ATOMIC); + kmemleak_alloc(table, size, 1, GFP_ATOMIC); + } + } + } while (!table && size > PAGE_SIZE && --log2qty); + + if (!table) + panic("Failed to allocate %s hash table\n", tablename); + + pr_info("%s hash table entries: %d (order: %d, %lu bytes)\n", + tablename, + (1U << log2qty), + ilog2(size) - PAGE_SHIFT, + size); + + if (_hash_shift) + *_hash_shift = log2qty; + if (_hash_mask) + *_hash_mask = (1 << log2qty) - 1; + + return table; +} + +int vm_insert_page(struct vm_area_struct *area, unsigned long addr, + struct page *page) +{ + /* this function is called from af_packet.c to support mmap on packet + sockets since we will never call mmap on them, this function + should never be called. */ + lib_assert(false); + return 0; /* quiet compiler */ +} + +void si_meminfo(struct sysinfo *val) +{ + /* This function is called from the ip layer to get information about + the amount of memory in the system and make some educated guesses + about some default buffer sizes. We pick a value which ensures + small buffers. */ + val->totalram = 0; +} +int slab_is_available(void) +{ + /* called from kernel/param.c. */ + return 1; +} + +/* used from kern_ptr_validate from mm/util.c which is never called */ +void *high_memory = 0; + + + +char *get_options(const char *str, int nints, int *ints) +{ + /* called from net/core/dev.c */ + /* we return 0 to indicate no options. */ + return 0; +} +void __xchg_called_with_bad_pointer(void) +{ + /* never called theoretically. */ + lib_assert(false); +} + +void async_synchronize_full(void) +{ + /* called from drivers/base/ *.c */ + /* there is nothing to do, really. */ +} +int send_sigurg(struct fown_struct *fown) +{ + lib_assert(false); + return 0; +} +int send_sig(int signal, struct task_struct *task, int x) +{ + struct SimTask *lib_task = container_of(task, struct SimTask, + kernel_task); + + lib_signal_raised((struct SimTask *)lib_task, signal); + /* lib_assert (false); */ + return 0; +} +unsigned long get_taint(void) +{ + /* never tainted. */ + return 0; +} +void add_taint(unsigned flag, enum lockdep_ok lockdep_ok) +{ +} +struct pid *cad_pid = 0; + +void add_device_randomness(const void *buf, unsigned int size) +{ +} + +int kobject_uevent(struct kobject *kobj, enum kobject_action action) +{ + return 0; +} + +int sched_rr_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + return 0; +} + +void on_each_cpu_mask(const struct cpumask *mask, + smp_call_func_t func, void *info, bool wait) +{ +} diff --git a/arch/lib/inode.c b/arch/lib/inode.c new file mode 100644 index 0000000..ab3d2ec --- /dev/null +++ b/arch/lib/inode.c @@ -0,0 +1,146 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + * Frederic Urbani + */ + +#include +#include +#include +#include +#include +#include + + +static struct kmem_cache *inode_cachep __read_mostly; +/* + * Empty aops. Can be used for the cases where the user does not + * define any of the address_space operations. + */ +const struct address_space_operations empty_aops = { +}; + +unsigned int get_next_ino(void) +{ + static unsigned int res = 0; + + return ++res; +} + +/** + * inode_init_always - perform inode structure intialisation + * @sb: superblock inode belongs to + * @inode: inode to initialise + * + * These are initializations that need to be done on every inode + * allocation as the fields are not initialised by slab allocation. + */ +int inode_init_always(struct super_block *sb, struct inode *inode) +{ + static const struct inode_operations empty_iops; + static const struct file_operations empty_fops; + struct address_space *const mapping = &inode->i_data; + + inode->i_sb = sb; + inode->i_blkbits = sb->s_blocksize_bits; + inode->i_flags = 0; + atomic_set(&inode->i_count, 1); + inode->i_op = &empty_iops; + inode->__i_nlink = 1; + inode->i_opflags = 0; + i_uid_write(inode, 0); + i_gid_write(inode, 0); + atomic_set(&inode->i_writecount, 0); + inode->i_size = 0; + inode->i_blocks = 0; + inode->i_bytes = 0; + inode->i_generation = 0; + inode->i_pipe = NULL; + inode->i_bdev = NULL; + inode->i_cdev = NULL; + inode->i_rdev = 0; + inode->dirtied_when = 0; + + if (security_inode_alloc(inode)) + goto out; + spin_lock_init(&inode->i_lock); + lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); + + mutex_init(&inode->i_mutex); + lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key); + + atomic_set(&inode->i_dio_count, 0); + + mapping->a_ops = &empty_aops; + mapping->host = inode; + mapping->flags = 0; + atomic_set(&mapping->i_mmap_writable, 0); + mapping_set_gfp_mask(mapping, GFP_HIGHUSER_MOVABLE); + mapping->private_data = NULL; + mapping->writeback_index = 0; + inode->i_private = NULL; + inode->i_mapping = mapping; + INIT_HLIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */ +#ifdef CONFIG_FS_POSIX_ACL + inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; +#endif + +#ifdef CONFIG_FSNOTIFY + inode->i_fsnotify_mask = 0; +#endif + /* this_cpu_inc(nr_inodes); */ + + return 0; +out: + return -ENOMEM; +} + + +static struct inode *alloc_inode(struct super_block *sb) +{ + struct inode *inode; + + if (sb->s_op->alloc_inode) + inode = sb->s_op->alloc_inode(sb); + else + inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); + + if (!inode) + return NULL; + + if (unlikely(inode_init_always(sb, inode))) { + if (inode->i_sb->s_op->destroy_inode) + inode->i_sb->s_op->destroy_inode(inode); + else + kmem_cache_free(inode_cachep, inode); + return NULL; + } + + return inode; +} + +/** + * new_inode_pseudo - obtain an inode + * @sb: superblock + * + * Allocates a new inode for given superblock. + * Inode wont be chained in superblock s_inodes list + * This means : + * - fs can't be unmount + * - quotas, fsnotify, writeback can't work + */ +struct inode *new_inode_pseudo(struct super_block *sb) +{ + struct inode *inode = alloc_inode(sb); + + if (inode) { + spin_lock(&inode->i_lock); + inode->i_state = 0; + spin_unlock(&inode->i_lock); + INIT_LIST_HEAD(&inode->i_sb_list); + } + return inode; +} diff --git a/arch/lib/modules.c b/arch/lib/modules.c new file mode 100644 index 0000000..ca43fdc --- /dev/null +++ b/arch/lib/modules.c @@ -0,0 +1,36 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + * Frederic Urbani + */ + +#include "sim-assert.h" +#include +#include +#include + +int modules_disabled = 0; +char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; + +static struct module_version_attribute g_empty_attr_buffer; +/* we make the array empty by default because, really, we don't need */ +/* to look at the builtin params */ +const struct kernel_param __start___param[] = {{0}} ; +const struct kernel_param __stop___param[] = {{0}} ; +const struct module_version_attribute *__start___modver[] = { + &g_empty_attr_buffer}; +const struct module_version_attribute *__stop___modver[] = { + &g_empty_attr_buffer}; + +struct module_attribute module_uevent; +struct ctl_table usermodehelper_table[] = {}; + +int __request_module(bool wait, const char *fmt, ...) +{ + /* we really should never be trying to load modules that way. */ + /* lib_assert (false); */ + return 0; +} diff --git a/arch/lib/pid.c b/arch/lib/pid.c new file mode 100644 index 0000000..00cf7b6 --- /dev/null +++ b/arch/lib/pid.c @@ -0,0 +1,29 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +#include "sim.h" +#include "sim-assert.h" + +void put_pid(struct pid *pid) +{ +} +pid_t pid_vnr(struct pid *pid) +{ + return pid_nr(pid); +} +struct task_struct *find_task_by_vpid(pid_t nr) +{ + lib_assert(false); + return 0; +} +struct pid *find_get_pid(int nr) +{ + lib_assert(false); + return 0; +} diff --git a/arch/lib/print.c b/arch/lib/print.c new file mode 100644 index 0000000..09b1bb5 --- /dev/null +++ b/arch/lib/print.c @@ -0,0 +1,56 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +#include +#include +#include "sim.h" +#include "sim-assert.h" + +int dmesg_restrict = 1; + +/* from lib/vsprintf.c */ +int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); + +int printk(const char *fmt, ...) +{ + va_list args; + static char buf[256]; + int value; + + va_start(args, fmt); + value = vsnprintf(buf, 256, printk_skip_level(fmt), args); + lib_printf("<%c>%s", printk_get_level(fmt), buf); + va_end(args); + return value; +} +void panic(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + lib_vprintf(fmt, args); + va_end(args); + lib_assert(false); +} + +void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...) +{ + va_list args; + + printk("%s:%d -- ", file, line); + va_start(args, fmt); + lib_vprintf(fmt, args); + va_end(args); +} + +void warn_slowpath_null(const char *file, int line) +{ + printk("%s:%d -- ", file, line); +} + diff --git a/arch/lib/proc.c b/arch/lib/proc.c new file mode 100644 index 0000000..0a65d7b --- /dev/null +++ b/arch/lib/proc.c @@ -0,0 +1,164 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2014 Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +#include +#include +#include +#include +#include +#include "sim-types.h" +#include "sim-assert.h" +#include "fs/proc/internal.h" /* XXX */ + +struct proc_dir_entry; +static char proc_root_data[sizeof(struct proc_dir_entry) + 4]; + +static struct proc_dir_entry *proc_root_sim = + (struct proc_dir_entry *)proc_root_data; + +void lib_proc_net_initialize(void) +{ + proc_root_sim->parent = proc_root_sim; + strcpy(proc_root_sim->name, "net"); + proc_root_sim->mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_root_sim->subdir = RB_ROOT; + init_net.proc_net = proc_root_sim; + init_net.proc_net_stat = proc_mkdir("stat", proc_root_sim); +} +struct proc_dir_entry * +proc_net_fops_create(struct net *net, + const char *name, + umode_t mode, const struct file_operations *fops) +{ + return proc_create_data(name, mode, net->proc_net, fops, 0); +} + +static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, + const char *name, + umode_t mode, + nlink_t nlink) +{ + struct proc_dir_entry *ent = NULL; + const char *fn = name; + struct qstr qstr; + + qstr.name = fn; + qstr.len = strlen(fn); + if (qstr.len == 0 || qstr.len >= 256) { + WARN(1, "name len %u\n", qstr.len); + return NULL; + } + + ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); + if (!ent) + goto out; + + memcpy(ent->name, fn, qstr.len + 1); + ent->namelen = qstr.len; + ent->mode = mode; + ent->nlink = nlink; + ent->subdir = RB_ROOT; + atomic_set(&ent->count, 1); + spin_lock_init(&ent->pde_unload_lock); + INIT_LIST_HEAD(&ent->pde_openers); +out: + return ent; +} +struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, + struct proc_dir_entry *parent, + const struct file_operations *proc_fops, + void *data) +{ + struct proc_dir_entry *de; + + de = __proc_create(&parent, name, S_IFDIR | mode, 2); + de->proc_fops = proc_fops; + de->data = data; + return de; +} +static int proc_match(unsigned int len, const char *name, + struct proc_dir_entry *de) +{ + if (len < de->namelen) + return -1; + if (len > de->namelen) + return 1; + + return memcmp(name, de->name, len); +} +static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir, + const char *name, + unsigned int len) +{ + struct rb_node *node = dir->subdir.rb_node; + + while (node) { + struct proc_dir_entry *de = container_of(node, + struct proc_dir_entry, + subdir_node); + int result = proc_match(len, name, de); + + if (result < 0) + node = node->rb_left; + else if (result > 0) + node = node->rb_right; + else + return de; + } + return NULL; +} + +void remove_proc_entry(const char *name, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *de, **prev; + + de = pde_subdir_find(parent, name, strlen(name)); + if (de) { + rb_erase(&de->subdir_node, &parent->subdir); + kfree(de->name); + kfree(de); + } +} +void proc_net_remove(struct net *net, const char *name) +{ + remove_proc_entry(name, net->proc_net); +} +void proc_remove(struct proc_dir_entry *de) +{ + /* XXX */ +} +int proc_nr_files(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return -ENOSYS; +} + +struct proc_dir_entry *proc_mkdir(const char *name, + struct proc_dir_entry *parent) +{ + return __proc_create(&parent, name, S_IFDIR | S_IRUGO, 2); +} + +struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, + struct proc_dir_entry *parent, + void *data) +{ + struct proc_dir_entry *de; + + de = __proc_create(&parent, name, + S_IFDIR | S_IRUGO | S_IXUGO | mode, 2); + de->data = data; + return de; +} + +int proc_alloc_inum(unsigned int *inum) +{ + *inum = 1; + return 0; +} diff --git a/arch/lib/random.c b/arch/lib/random.c new file mode 100644 index 0000000..9fbb8bf --- /dev/null +++ b/arch/lib/random.c @@ -0,0 +1,53 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include "sim.h" +#include + +u32 random32(void) +{ + return lib_random(); +} + +void get_random_bytes(void *buf, int nbytes) +{ + char *p = (char *)buf; + int i; + + for (i = 0; i < nbytes; i++) + p[i] = lib_random(); +} +void srandom32(u32 entropy) +{ +} + +u32 prandom_u32(void) +{ + return lib_random(); +} +void prandom_seed(u32 entropy) +{ +} + +void prandom_bytes(void *buf, size_t bytes) +{ + return get_random_bytes(buf, bytes); +} + +#include + +static int nothing; +struct ctl_table random_table[] = { + { + .procname = "nothing", + .data = ¬hing, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = proc_dointvec, + } +}; diff --git a/arch/lib/security.c b/arch/lib/security.c new file mode 100644 index 0000000..0367189 --- /dev/null +++ b/arch/lib/security.c @@ -0,0 +1,45 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include "linux/capability.h" + +struct sock; +struct sk_buff; + +bool capable(int cap) +{ + switch (cap) { + case CAP_NET_RAW: + case CAP_NET_BIND_SERVICE: + case CAP_NET_ADMIN: + return 1; + default: + break; + } + + return 0; +} + +int cap_netlink_recv(struct sk_buff *skb, int cap) +{ + return 0; +} + +int cap_netlink_send(struct sock *sk, struct sk_buff *skb) +{ + return 0; +} +bool ns_capable(struct user_namespace *ns, int cap) +{ + return true; +} +bool file_ns_capable(const struct file *file, struct user_namespace *ns, + int cap) +{ + return true; +} diff --git a/arch/lib/seq.c b/arch/lib/seq.c new file mode 100644 index 0000000..72c2f5d --- /dev/null +++ b/arch/lib/seq.c @@ -0,0 +1,122 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include + +struct hlist_node *seq_hlist_next_rcu(void *v, + struct hlist_head *head, + loff_t *ppos) +{ + return 0; +} +struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, + loff_t pos) +{ + return 0; +} +struct list_head *seq_list_start(struct list_head *head, + loff_t pos) +{ + return 0; +} +struct list_head *seq_list_start_head(struct list_head *head, + loff_t pos) +{ + return 0; +} + +struct list_head *seq_list_next(void *v, struct list_head *head, + loff_t *ppos) +{ + return 0; +} + +void *__seq_open_private(struct file *file, const struct seq_operations *ops, + int psize) +{ + return 0; +} + +int seq_open_private(struct file *file, const struct seq_operations *ops, + int psize) +{ + return 0; +} + +int seq_release_private(struct inode *inode, struct file *file) +{ + return 0; +} + +loff_t seq_lseek(struct file *file, loff_t offset, int origin) +{ + return 0; +} +int seq_release(struct inode *inode, struct file *file) +{ + return 0; +} +int seq_putc(struct seq_file *m, char c) +{ + return 0; +} +int seq_puts(struct seq_file *m, const char *s) +{ + return 0; +} +ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) +{ + return 0; +} +int seq_open(struct file *file, const struct seq_operations *ops) +{ + return 0; +} +int seq_printf(struct seq_file *seq, const char *fmt, ...) +{ + return 0; +} + +int seq_write(struct seq_file *seq, const void *data, size_t len) +{ + return 0; +} + +int seq_open_net(struct inode *inode, struct file *file, + const struct seq_operations *ops, int size) +{ + return 0; +} + +int seq_release_net(struct inode *inode, struct file *file) +{ + return 0; +} + + +int single_open(struct file *file, int (*cb)(struct seq_file *, + void *), void *data) +{ + return 0; +} + +int single_release(struct inode *inode, struct file *file) +{ + return 0; +} + +int single_open_net(struct inode *inode, struct file *file, + int (*show)(struct seq_file *, void *)) +{ + return 0; +} + +int single_release_net(struct inode *inode, struct file *file) +{ + return 0; +} diff --git a/arch/lib/splice.c b/arch/lib/splice.c new file mode 100644 index 0000000..9ecd9e5 --- /dev/null +++ b/arch/lib/splice.c @@ -0,0 +1,20 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include "sim.h" +#include "sim-assert.h" +#include + +ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, + struct pipe_inode_info *pipe, size_t len, + unsigned int flags) +{ + lib_assert(false); + + return 0; +} diff --git a/arch/lib/super.c b/arch/lib/super.c new file mode 100644 index 0000000..45a653f --- /dev/null +++ b/arch/lib/super.c @@ -0,0 +1,210 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +#include +#include +#include +#include +#include +#include /* for the emergency remount stuff */ +#include +#include +#include +#include +#include +#include +#include +#include + + +void put_super(struct super_block *sb) +{ +} + +int grab_super(struct super_block *s) +{ + return 0; +} +void destroy_super(struct super_block *s) +{ +} + +int set_anon_super(struct super_block *s, void *data) +{ + return 0; +} + +struct super_block; +LIST_HEAD(super_blocks); + +/** + * alloc_super - create new superblock + * @type: filesystem type superblock should belong to + * + * Allocates and initializes a new &struct super_block. alloc_super() + * returns a pointer new superblock or %NULL if allocation had failed. + */ +static struct super_block *alloc_super(struct file_system_type *type) +{ + struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); + static const struct super_operations default_op; + + if (s) { + if (security_sb_alloc(s)) { + kfree(s); + s = NULL; + goto fail; + } + INIT_HLIST_NODE(&s->s_instances); + INIT_HLIST_BL_HEAD(&s->s_anon); + INIT_LIST_HEAD(&s->s_inodes); + if (list_lru_init(&s->s_dentry_lru)) + goto fail; + if (list_lru_init(&s->s_inode_lru)) + goto fail; + INIT_LIST_HEAD(&s->s_mounts); + init_rwsem(&s->s_umount); + /* + * sget() can have s_umount recursion. + * + * When it cannot find a suitable sb, it allocates a new + * one (this one), and tries again to find a suitable old + * one. + * + * In case that succeeds, it will acquire the s_umount + * lock of the old one. Since these are clearly distrinct + * locks, and this object isn't exposed yet, there's no + * risk of deadlocks. + * + * Annotate this by putting this lock in a different + * subclass. + */ + down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING); + s->s_count = 1; + atomic_set(&s->s_active, 1); + mutex_init(&s->s_vfs_rename_mutex); + lockdep_set_class(&s->s_vfs_rename_mutex, + &type->s_vfs_rename_key); + mutex_init(&s->s_dquot.dqio_mutex); + mutex_init(&s->s_dquot.dqonoff_mutex); + s->s_maxbytes = MAX_NON_LFS; + s->s_op = &default_op; + s->s_time_gran = 1000000000; + s->cleancache_poolid = -1; + + s->s_shrink.seeks = DEFAULT_SEEKS; + s->s_shrink.batch = 1024; + return s; + } +fail: + destroy_super(s); + return NULL; +} + +/** + * deactivate_locked_super - drop an active reference to superblock + * @s: superblock to deactivate + * + * Drops an active reference to superblock, converting it into a temprory + * one if there is no other active references left. In that case we + * tell fs driver to shut it down and drop the temporary reference we + * had just acquired. + * + * Caller holds exclusive lock on superblock; that lock is released. + */ +void deactivate_locked_super(struct super_block *s) +{ + struct file_system_type *fs = s->s_type; + + if (atomic_dec_and_test(&s->s_active)) { + cleancache_invalidate_fs(s); + fs->kill_sb(s); + + /* caches are now gone, we can safely kill the shrinker now */ + unregister_shrinker(&s->s_shrink); + + /* + * We need to call rcu_barrier so all the delayed rcu free + * inodes are flushed before we release the fs module. + */ + rcu_barrier(); + put_filesystem(fs); + put_super(s); + } else + up_write(&s->s_umount); +} + +/* from fs/super.c */ +DEFINE_SPINLOCK(sb_lock); +/** + * sget - find or create a superblock + * @type: filesystem type superblock should belong to + * @test: comparison callback + * @set: setup callback + * @data: argument to each of them + */ +struct super_block *sget(struct file_system_type *type, + int (*test)(struct super_block *, void *), + int (*set)(struct super_block *, void *), + int flags, void *data) +{ + struct super_block *s = NULL; + struct super_block *old; + int err; + +retry: + spin_lock(&sb_lock); + if (test) { + hlist_for_each_entry(old, &type->fs_supers, s_instances) { + if (!test(old, data)) + continue; + if (!grab_super(old)) + goto retry; + if (s) { + up_write(&s->s_umount); + destroy_super(s); + s = NULL; + } + down_write(&old->s_umount); + if (unlikely(!(old->s_flags & MS_BORN))) { + deactivate_locked_super(old); + goto retry; + } + return old; + } + } + if (!s) { + spin_unlock(&sb_lock); + s = alloc_super(type); + if (!s) + return ERR_PTR(-ENOMEM); + goto retry; + } + + err = set(s, data); + if (err) { + spin_unlock(&sb_lock); + up_write(&s->s_umount); + destroy_super(s); + return ERR_PTR(err); + } + s->s_type = type; + strlcpy(s->s_id, type->name, sizeof(s->s_id)); + list_add_tail(&s->s_list, &super_blocks); + hlist_add_head(&s->s_instances, &type->fs_supers); + spin_unlock(&sb_lock); +/* get_filesystem(type); */ +/* register_shrinker(&s->s_shrink); */ + return s; +} + +void kill_anon_super(struct super_block *sb) +{ + +} diff --git a/arch/lib/sysfs.c b/arch/lib/sysfs.c new file mode 100644 index 0000000..2def2ca --- /dev/null +++ b/arch/lib/sysfs.c @@ -0,0 +1,83 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +#include +#include "sim.h" +#include "sim-assert.h" + +int sysfs_create_bin_file(struct kobject *kobj, + const struct bin_attribute *attr) +{ + return 0; +} +void sysfs_remove_bin_file(struct kobject *kobj, + const struct bin_attribute *attr) +{ +} +int sysfs_create_dir(struct kobject *kobj) +{ + return 0; +} +int sysfs_create_link(struct kobject *kobj, struct kobject *target, + const char *name) +{ + return 0; +} +int sysfs_move_dir(struct kobject *kobj, + struct kobject *new_parent_kobj) +{ + return 0; +} +void sysfs_remove_dir(struct kobject *kobj) +{ +} +void sysfs_remove_group(struct kobject *kobj, + const struct attribute_group *grp) +{ +} +int sysfs_rename_dir(struct kobject *kobj, const char *new_name) +{ + return 0; +} +int __must_check sysfs_create_group(struct kobject *kobj, + const struct attribute_group *grp) +{ + return 0; +} +int sysfs_create_groups(struct kobject *kobj, + const struct attribute_group **groups) +{ + return 0; +} +int sysfs_schedule_callback(struct kobject *kobj, + void (*func)( + void *), void *data, struct module *owner) +{ + return 0; +} +void sysfs_delete_link(struct kobject *dir, struct kobject *targ, + const char *name) +{ +} +void sysfs_exit_ns(enum kobj_ns_type type, const void *tag) +{ +} +void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) +{ +} +int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) +{ + kobj->sd = lib_malloc(sizeof(struct kernfs_node)); + return 0; +} +int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, + const void *ns) +{ + return 0; +} diff --git a/arch/lib/vmscan.c b/arch/lib/vmscan.c new file mode 100644 index 0000000..3132f66 --- /dev/null +++ b/arch/lib/vmscan.c @@ -0,0 +1,26 @@ +/* + * glue code for library version of Linux kernel + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage + * Hajime Tazaki + */ + +#include +#include + +/* + * Add a shrinker callback to be called from the vm + */ +int register_shrinker(struct shrinker *shrinker) +{ + return 0; +} + +/* + * Remove one + */ +void unregister_shrinker(struct shrinker *shrinker) +{ +} + -- 2.1.0