#ifndef _SPADFS_LINUX_COMPAT_H
#define _SPADFS_LINUX_COMPAT_H

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
static inline int blkdev_issue_flush(struct block_device *bdev,
				     sector_t *error_sector)
{
	return 0;
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
static inline void vprintk(const char *fmt, va_list args)
{
	char buffer[256];
	vsnprintf(buffer, sizeof buffer, fmt, args);
	printk("%s", buffer);
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
static inline void *kmalloc_node(size_t size, int flags, int node)
{
	return kmalloc(size, flags);
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
static inline void cancel_rearming_delayed_workqueue(
			struct workqueue_struct *wq, struct work_struct *work)
{
	while (!cancel_delayed_work(work))
		flush_workqueue(wq);
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
#define raw_smp_processor_id()	smp_processor_id()
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
#define rcu_barrier()	synchronize_kernel()
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
#define rcu_barrier()	synchronize_rcu()
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
static inline int rwsem_is_locked(struct rw_semaphore *s)
{
	if (down_write_trylock(s)) {
		up_write(s);
		return 0;
	}
	return 1;
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
#define mutex			semaphore
#define mutex_init		init_MUTEX
#define mutex_lock		down
#define mutex_lock_nested(s, n)	down(s)
#define mutex_unlock		up
#define mutex_trylock(s)	(!down_trylock(s))
#define mutex_is_locked(s)	(atomic_read(&(s)->count) < 1)
#define i_mutex			i_sem
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
#define SLAB_MEM_SPREAD	0
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) && !(defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && RHEL_MINOR >= 3)
static inline void clear_nlink(struct inode *inode)
{
	inode->i_nlink = 0;
}
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
#define NEW_WORKQUEUE
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
#define KMALLOC_MAX_SIZE	131072
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
#define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) && !(defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && RHEL_MINOR >= 3)
static inline int is_vmalloc_addr(const void *ptr)
{
#ifdef CONFIG_MMU
	if ((unsigned long)ptr >= VMALLOC_START &&
	    (unsigned long)ptr < VMALLOC_END)
		return 1;
#endif
	return 0;
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) && !(defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && RHEL_MINOR >= 4)
static inline size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
{
	size_t ret = src->to - src->from;

	if (size) {
		size_t len = ret >= size ? size - 1 : ret;
		memcpy(dest, src->from, len);
		dest[len] = '\0';
	}

	return ret;
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
#define get_current_uid()	(current->uid)
#define get_current_gid()	(current->gid)
#define get_current_fsuid()	(current->fsuid)
#define get_current_fsgid()	(current->fsgid)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
#define get_current_uid()	current_uid()
#define get_current_gid()	current_gid()
#define get_current_fsuid()	current_fsuid()
#define get_current_fsgid()	current_fsgid()
#else
#define get_current_uid()	from_kuid(&init_user_ns, current_uid())
#define get_current_gid()	from_kgid(&init_user_ns, current_gid())
#define get_current_fsuid()	from_kuid(&init_user_ns, current_fsuid())
#define get_current_fsgid()	from_kgid(&init_user_ns, current_fsgid())
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
#define nr_cpumask_bits		NR_CPUS
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
static inline unsigned queue_max_sectors(struct request_queue *q)
{
	return q->max_sectors;
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
static inline void set_nlink(struct inode *inode, unsigned nlink)
{
	inode->i_nlink = nlink;
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
#define i_uid_read(i)		((i)->i_uid)
#define i_gid_read(i)		((i)->i_gid)
#define i_uid_write(i, u)	((i)->i_uid = (u))
#define i_gid_write(i, u)	((i)->i_gid = (u))
#define uid_eq(a, b)		((a) == (b))
#define gid_eq(a, b)		((a) == (b))
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
#define file_inode(f)	(file_dentry(f)->d_inode)
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0) && !(LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,41) && LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)) && !(defined(RHEL_MAJOR) && ((RHEL_MAJOR == 6 && RHEL_MINOR >= 8) || (RHEL_MAJOR == 7 && RHEL_MINOR >= 1)))
static inline void kvfree(void *ptr)
{
	if (is_vmalloc_addr(ptr))
		vfree(ptr);
	else
		kfree(ptr);
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
#define file_dentry(f)	((f)->f_dentry)
#elif !(LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,2) || (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,8) && LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)))
#define file_dentry(f)	((f)->f_path.dentry)
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0)
#define __GFP_DIRECT_RECLAIM	__GFP_WAIT
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
#define huge_valid_dev(dev)	1
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,21)
/* warning: do not define inode_lock, it collides with another symbol on kernels <= 2.6.38 */
static inline void inode_unlock(struct inode *inode)
{
	mutex_unlock(&inode->i_mutex);
}
static inline int inode_trylock(struct inode *inode)
{
	return mutex_trylock(&inode->i_mutex);
}
static inline int inode_is_locked(struct inode *inode)
{
	return mutex_is_locked(&inode->i_mutex);
}
static inline void inode_lock_nested(struct inode *inode, unsigned subclass)
{
	mutex_lock_nested(&inode->i_mutex, subclass);
}
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
#define SLAB_ACCOUNT	0
#endif

#ifndef ACCESS_ONCE
#define ACCESS_ONCE(x)	(*(volatile typeof(x) *)&(x))
#endif

/* grsecurity hack */
#ifndef ACCESS_ONCE_RW
#define ACCESS_ONCE_RW	ACCESS_ONCE
#endif

#endif
