+
+dnl #
+dnl # 2.6.x API change,
+dnl # kvasprintf() function added.
+dnl #
+AC_DEFUN([SPL_AC_KVASPRINTF],
+ [AC_MSG_CHECKING([whether kvasprintf() is available])
+ SPL_LINUX_TRY_COMPILE_SYMBOL([
+ #include <linux/kernel.h>
+ ], [
+ kvasprintf(0, NULL, *((va_list*)NULL));
+ ], [kvasprintf], [], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_KVASPRINTF, 1, [kvasprintf() is available])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.29 API change,
+dnl # vfs_fsync() funcation added, prior to this use file_fsync().
+dnl #
+AC_DEFUN([SPL_AC_VFS_FSYNC],
+ [AC_MSG_CHECKING([whether vfs_fsync() is available])
+ SPL_LINUX_TRY_COMPILE_SYMBOL([
+ #include <linux/fs.h>
+ ], [
+ (void) vfs_fsync;
+ ], [vfs_fsync], [fs/sync.c], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_VFS_FSYNC, 1, [vfs_fsync() is available])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.35 API change,
+dnl # Unused 'struct dentry *' removed from vfs_fsync() prototype.
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_VFS_FSYNC], [
+ AC_MSG_CHECKING([whether vfs_fsync() wants 2 args])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ vfs_fsync(NULL, 0);
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_2ARGS_VFS_FSYNC, 1, [vfs_fsync() wants 2 args])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 3.5 API change,
+dnl # inode_operations.truncate_range removed
+dnl #
+AC_DEFUN([SPL_AC_INODE_TRUNCATE_RANGE], [
+ AC_MSG_CHECKING([whether truncate_range() inode operation is available])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ struct inode_operations ops;
+ ops.truncate_range = NULL;
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INODE_TRUNCATE_RANGE, 1,
+ [truncate_range() inode operation is available])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_FILE_FALLOCATE], [
+ AC_MSG_CHECKING([whether fops->fallocate() exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+ struct file_operations fops __attribute__ ((unused)) = {
+ .fallocate = fallocate,
+ };
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # Linux 2.6.x - 2.6.37 API
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_INODE_FALLOCATE], [
+ AC_MSG_CHECKING([whether iops->fallocate() exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ long (*fallocate) (struct inode *, int, loff_t, loff_t) = NULL;
+ struct inode_operations fops __attribute__ ((unused)) = {
+ .fallocate = fallocate,
+ };
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INODE_FALLOCATE, 1, [fops->fallocate() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # PaX Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([SPL_AC_PAX_KERNEL_FILE_FALLOCATE], [
+ AC_MSG_CHECKING([whether fops->fallocate() exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+ struct file_operations_no_const fops __attribute__ ((unused)) = {
+ .fallocate = fallocate,
+ };
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # The fallocate callback was moved from the inode_operations
+dnl # structure to the file_operations structure.
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_FALLOCATE], [
+ SPL_AC_KERNEL_FILE_FALLOCATE
+ SPL_AC_KERNEL_INODE_FALLOCATE
+ SPL_AC_PAX_KERNEL_FILE_FALLOCATE
+])
+
+dnl #
+dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
+dnl # Earlier versions of rwsem_is_locked() were inline and had a race
+dnl # condition. The fixed version is exported as a symbol. The race
+dnl # condition is fixed by acquiring sem->wait_lock, so we must not
+dnl # call that version while holding sem->wait_lock.
+dnl #
+AC_DEFUN([SPL_AC_EXPORTED_RWSEM_IS_LOCKED],
+ [AC_MSG_CHECKING([whether rwsem_is_locked() acquires sem->wait_lock])
+ SPL_LINUX_TRY_COMPILE_SYMBOL([
+ #include <linux/rwsem.h>
+ int rwsem_is_locked(struct rw_semaphore *sem) { return 0; }
+ ], [], [rwsem_is_locked], [lib/rwsem-spinlock.c], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(RWSEM_IS_LOCKED_TAKES_WAIT_LOCK, 1,
+ [rwsem_is_locked() acquires sem->wait_lock])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.xx API compat,
+dnl # There currently exists no exposed API to partially shrink the dcache.
+dnl # The expected mechanism to shrink the cache is a registered shrinker
+dnl # which is called during memory pressure.
+dnl #
+AC_DEFUN([SPL_AC_SHRINK_DCACHE_MEMORY],
+ [AC_MSG_CHECKING([whether shrink_dcache_memory() is available])
+ SPL_LINUX_TRY_COMPILE_SYMBOL([
+ #include <linux/dcache.h>
+ ], [
+ shrink_dcache_memory(0, 0);
+ ], [shrink_dcache_memory], [fs/dcache.c], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SHRINK_DCACHE_MEMORY, 1,
+ [shrink_dcache_memory() is available])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.xx API compat,
+dnl # There currently exists no exposed API to partially shrink the icache.
+dnl # The expected mechanism to shrink the cache is a registered shrinker
+dnl # which is called during memory pressure.
+dnl #
+AC_DEFUN([SPL_AC_SHRINK_ICACHE_MEMORY],
+ [AC_MSG_CHECKING([whether shrink_icache_memory() is available])
+ SPL_LINUX_TRY_COMPILE_SYMBOL([
+ #include <linux/dcache.h>
+ ], [
+ shrink_icache_memory(0, 0);
+ ], [shrink_icache_memory], [fs/inode.c], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SHRINK_ICACHE_MEMORY, 1,
+ [shrink_icache_memory() is available])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.39 API compat,
+dnl # The path_lookup() function has been renamed to kern_path_parent()
+dnl # and the flags argument has been removed. The only behavior now
+dnl # offered is that of LOOKUP_PARENT. The spl already always passed
+dnl # this flag so dropping the flag does not impact us.
+dnl #
+AC_DEFUN([SPL_AC_KERN_PATH_PARENT_HEADER], [
+ SPL_CHECK_SYMBOL_HEADER(
+ [kern_path_parent],
+ [int kern_path_parent(const char \*, struct nameidata \*)],
+ [include/linux/namei.h],
+ [AC_DEFINE(HAVE_KERN_PATH_PARENT_HEADER, 1,
+ [kern_path_parent() is available])],
+ [])
+])
+
+dnl #
+dnl # 3.1 API compat,
+dnl # The kern_path_parent() symbol is no longer exported by the kernel.
+dnl # However, it remains the prefered interface and since we still have
+dnl # access to the prototype we dynamically lookup the required address.
+dnl #
+AC_DEFUN([SPL_AC_KERN_PATH_PARENT_SYMBOL],
+ [AC_MSG_CHECKING([whether kern_path_parent() is available])
+ SPL_LINUX_TRY_COMPILE_SYMBOL([
+ #include <linux/namei.h>
+ ], [
+ kern_path_parent(NULL, NULL);
+ ], [kern_path_parent], [fs/namei.c], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_KERN_PATH_PARENT_SYMBOL, 1,
+ [kern_path_parent() is available])
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 3.6 API compat,
+dnl # The kern_path_parent() function was replaced by the kern_path_locked()
+dnl # function to eliminate all struct nameidata usage outside fs/namei.c.
+dnl #
+AC_DEFUN([SPL_AC_KERN_PATH_LOCKED], [
+ SPL_CHECK_SYMBOL_HEADER(
+ [kern_path_locked],
+ [struct dentry \*kern_path_locked(const char \*, struct path \*)],
+ [include/linux/namei.h],
+ [AC_DEFINE(HAVE_KERN_PATH_LOCKED, 1,
+ [kern_path_locked() is available])],
+ [])
+])
+
+dnl #
+dnl # /proc/kallsyms support,
+dnl # Verify the kernel has CONFIG_KALLSYMS support enabled.
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_KALLSYMS], [
+ AC_MSG_CHECKING([whether CONFIG_KALLSYMS is defined])
+ SPL_LINUX_TRY_COMPILE([
+ #if !defined(CONFIG_KALLSYMS)
+ #error CONFIG_KALLSYMS not defined
+ #endif
+ ],[ ],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([
+ *** This kernel does not include the required kallsyms support.
+ *** Rebuild the kernel with CONFIG_KALLSYMS=y set.])
+ ])
+])
+
+dnl #
+dnl # zlib inflate compat,
+dnl # Verify the kernel has CONFIG_ZLIB_INFLATE support enabled.
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_ZLIB_INFLATE], [
+ AC_MSG_CHECKING([whether CONFIG_ZLIB_INFLATE is defined])
+ SPL_LINUX_TRY_COMPILE([
+ #if !defined(CONFIG_ZLIB_INFLATE) && \
+ !defined(CONFIG_ZLIB_INFLATE_MODULE)
+ #error CONFIG_ZLIB_INFLATE not defined
+ #endif
+ ],[ ],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([
+ *** This kernel does not include the required zlib inflate support.
+ *** Rebuild the kernel with CONFIG_ZLIB_INFLATE=y|m set.])
+ ])
+])
+
+dnl #
+dnl # zlib deflate compat,
+dnl # Verify the kernel has CONFIG_ZLIB_DEFLATE support enabled.
+dnl #
+AC_DEFUN([SPL_AC_CONFIG_ZLIB_DEFLATE], [
+ AC_MSG_CHECKING([whether CONFIG_ZLIB_DEFLATE is defined])
+ SPL_LINUX_TRY_COMPILE([
+ #if !defined(CONFIG_ZLIB_DEFLATE) && \
+ !defined(CONFIG_ZLIB_DEFLATE_MODULE)
+ #error CONFIG_ZLIB_DEFLATE not defined
+ #endif
+ ],[ ],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([
+ *** This kernel does not include the required zlib deflate support.
+ *** Rebuild the kernel with CONFIG_ZLIB_DEFLATE=y|m set.])
+ ])
+])
+
+dnl #
+dnl # 2.6.39 API compat,
+dnl # The function zlib_deflate_workspacesize() now take 2 arguments.
+dnl # This was done to avoid always having to allocate the maximum size
+dnl # workspace (268K). The caller can now specific the windowBits and
+dnl # memLevel compression parameters to get a smaller workspace.
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE],
+ [AC_MSG_CHECKING([whether zlib_deflate_workspacesize() wants 2 args])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/zlib.h>
+ ],[
+ return zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL);
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE, 1,
+ [zlib_deflate_workspacesize() wants 2 args])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.39 API change,
+dnl # Shrinker adjust to use common shrink_control structure.
+dnl #
+AC_DEFUN([SPL_AC_SHRINK_CONTROL_STRUCT], [
+ AC_MSG_CHECKING([whether struct shrink_control exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/mm.h>
+ ],[
+ struct shrink_control sc __attribute__ ((unused));
+
+ sc.nr_to_scan = 0;
+ sc.gfp_mask = GFP_KERNEL;
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SHRINK_CONTROL_STRUCT, 1,
+ [struct shrink_control exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 3.1 API Change
+dnl #
+dnl # The rw_semaphore.wait_lock member was changed from spinlock_t to
+dnl # raw_spinlock_t at commit ddb6c9b58a19edcfac93ac670b066c836ff729f1.
+dnl #
+AC_DEFUN([SPL_AC_RWSEM_SPINLOCK_IS_RAW], [
+ AC_MSG_CHECKING([whether struct rw_semaphore member wait_lock is raw])
+ tmp_flags="$EXTRA_KCFLAGS"
+ EXTRA_KCFLAGS="-Werror"
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/rwsem.h>
+ ],[
+ struct rw_semaphore dummy_semaphore __attribute__ ((unused));
+ raw_spinlock_t dummy_lock __attribute__ ((unused));
+ dummy_semaphore.wait_lock = dummy_lock;
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(RWSEM_SPINLOCK_IS_RAW, 1,
+ [struct rw_semaphore member wait_lock is raw_spinlock_t])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+ EXTRA_KCFLAGS="$tmp_flags"
+])
+
+dnl #
+dnl # 3.9 API change,
+dnl # Moved things from linux/sched.h to linux/sched/rt.h
+dnl #
+AC_DEFUN([SPL_AC_SCHED_RT_HEADER],
+ [AC_MSG_CHECKING([whether header linux/sched/rt.h exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/sched.h>
+ #include <linux/sched/rt.h>
+ ],[
+ return 0;
+ ],[
+ AC_DEFINE(HAVE_SCHED_RT_HEADER, 1, [linux/sched/rt.h exists])
+ AC_MSG_RESULT(yes)
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 3.9 API change,
+dnl # vfs_getattr() uses 2 args
+dnl # It takes struct path * instead of struct vfsmount * and struct dentry *
+dnl #
+AC_DEFUN([SPL_AC_2ARGS_VFS_GETATTR], [
+ AC_MSG_CHECKING([whether vfs_getattr() wants])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ vfs_getattr((struct path *) NULL,
+ (struct kstat *)NULL);
+ ],[
+ AC_MSG_RESULT(2 args)
+ AC_DEFINE(HAVE_2ARGS_VFS_GETATTR, 1,
+ [vfs_getattr wants 2 args])
+ ],[
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ vfs_getattr((struct vfsmount *)NULL,
+ (struct dentry *)NULL,
+ (struct kstat *)NULL);
+ ],[
+ AC_MSG_RESULT(3 args)
+ ],[
+ AC_MSG_ERROR(unknown)
+ ])
+ ])
+])
+
+dnl #
+dnl # 2.6.36 API compatibility.
+dnl # Added usleep_range timer.
+dnl # usleep_range is a finer precision implementation of msleep
+dnl # designed to be a drop-in replacement for udelay where a precise
+dnl # sleep / busy-wait is unnecessary.
+dnl #
+AC_DEFUN([SPL_AC_USLEEP_RANGE], [
+ AC_MSG_CHECKING([whether usleep_range() is available])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/delay.h>
+ ],[
+ usleep_range(0, 0);
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_USLEEP_RANGE, 1,
+ [usleep_range is available])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # 2.6.35 API change,
+dnl # The cachep->gfpflags member was renamed cachep->allocflags. These are
+dnl # private allocation flags which are applied when allocating a new slab
+dnl # in kmem_getpages(). Unfortunately there is no public API for setting
+dnl # non-default flags.
+dnl #
+AC_DEFUN([SPL_AC_KMEM_CACHE_ALLOCFLAGS], [
+ AC_MSG_CHECKING([whether struct kmem_cache has allocflags])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/slab.h>
+ ],[
+ struct kmem_cache cachep __attribute__ ((unused));
+ cachep.allocflags = GFP_KERNEL;
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_KMEM_CACHE_ALLOCFLAGS, 1,
+ [struct kmem_cache has allocflags])
+ ],[
+ AC_MSG_RESULT(no)
+
+ AC_MSG_CHECKING([whether struct kmem_cache has gfpflags])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/slab.h>
+ ],[
+ struct kmem_cache cachep __attribute__ ((unused));
+ cachep.gfpflags = GFP_KERNEL;
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_KMEM_CACHE_GFPFLAGS, 1,
+ [struct kmem_cache has gfpflags])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+ ])
+])