#!/bin/bash set -e # NOTE, we're using the argument array as part of this string here. As is # often the case in shell scripts (especially when used with Makefiles) the # quoting here is not correct in the sense that it can be broken for example # with arguments that contain spaces. But it is expected to work with our input # data. CFLAGS="-D__KERNEL__ $LINUXINCLUDE $* -DKBUILD_BASENAME=\"beegfs\" -DKBUILD_MODNAME=\"beegfs\"" _generate_includes() { for i in "$@"; do echo "#include <$i>" done } _marker_if_compiles() { local marker=$1 shift if $CC $CFLAGS -x c -o /dev/null -c - 2>/dev/null then echo -D$marker fi } _check_type_input() { local tp=$1 shift 1 _generate_includes "$@" cat <= 4.20 issues a warning (including stacktrace) if it _is_ set. # # We can't detect this from the headers, only by looking at the source. # BUT: The source is not guaranteed to be available when building. # # We have tried to check for this "feature" by looking at the Linux version # as reported by the LINUX_VERSION_CODE macro. # # BUT: Some non-vanilla < 4.20 kernels have backported the >= 4.20 # functionality to < 4.20 kernels. So relying on the version code doesn't # work either. # # What we're doing here now is our current best attempt to detect how the API # must be used. We're checking something that is not really related to the # actual function, but which seems to give the right results. check_function \ iov_iter_is_kvec 'bool(const struct iov_iter *)' \ KERNEL_HAS_IOV_ITER_KVEC_NO_TYPE_FLAG_IN_DIRECTION \ linux/uio.h # print_stack_trace() found on older Linux kernels < 5.2 check_function \ print_stack_trace 'void (struct stack_trace *trace, int spaces)' \ KERNEL_HAS_PRINT_STACK_TRACE \ linux/stacktrace.h # Starting from kernel 5.2, print_stack_trace() is demoted to tools/ directory # so not available to us. # Starting from kernel 5.16 print_stack_trace() is removed completely, but # stack_trace_print() can be used instead. # Notably, the identifier stack_trace_print() existed even in older Linux # versions, but with a different signature and different functionality. check_function \ stack_trace_print 'void (unsigned long *trace, unsigned int nr_entries, int spaces)' \ KERNEL_HAS_STACK_TRACE_PRINT \ linux/stacktrace.h \ check_type 'struct file_lock_core' KERNEL_HAS_FILE_LOCK_CORE linux/filelock.h check_type 'struct proc_ops' KERNEL_HAS_PROC_OPS linux/proc_fs.h check_type sockptr_t KERNEL_HAS_SOCKPTR_T linux/sockptr.h check_function \ sock_setsockopt 'int (struct socket *, int, int, sockptr_t, unsigned int)' \ KERNEL_HAS_SOCK_SETSOCKOPT_SOCKPTR_T_PARAM \ net/sock.h check_type time64_t KERNEL_HAS_TIME64 linux/ktime.h check_function ktime_get_ts64 'void (struct timespec64 *)' KERNEL_HAS_KTIME_GET_TS64 linux/ktime.h check_function ktime_get_real_ts64 'void (struct timespec64 *)' KERNEL_HAS_KTIME_GET_REAL_TS64 linux/ktime.h check_function ktime_get_coarse_real_ts64 'void (struct timespec64 *)' KERNEL_HAS_KTIME_GET_COARSE_REAL_TS64 linux/ktime.h # latest kernel from 6.3 changes moved to timekeeping.h check_function \ ktime_get_ts64 "void (struct timespec64 *ts)" \ KERNEL_HAS_KTIME_GET_TS64 \ linux/timekeeping.h check_function \ ktime_get_real_ts64 "void (struct timespec64 *tv)" \ KERNEL_HAS_KTIME_GET_REAL_TS64 \ linux/timekeeping.h check_function \ ktime_get_coarse_real_ts64 "void (struct timespec64 *ts)" \ KERNEL_HAS_KTIME_GET_COARSE_REAL_TS64 \ linux/timekeeping.h check_function \ generic_file_splice_read "ssize_t (struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int)" \ KERNEL_HAS_GENERIC_FILE_SPLICE_READ \ linux/fs.h check_function \ generic_permission "int (struct inode *, int)" \ KERNEL_HAS_GENERIC_PERMISSION_2 \ linux/fs.h check_function \ generic_permission "int (struct inode *, int, int (*check_acl)(struct inode *, int)" \ KERNEL_HAS_GENERIC_PERMISSION_4 \ linux/fs.h check_function \ setattr_prepare "int (struct mnt_idmap *, struct dentry *, struct iattr *)" \ KERNEL_HAS_SETATTR_PREPARE \ linux/fs.h check_function \ setattr_prepare "int (struct dentry *dentry, struct iattr *attr)" \ KERNEL_HAS_SETATTR_PREPARE \ linux/fs.h check_function \ setattr_prepare "int (struct user_namespace *, struct dentry *, struct iattr *)" \ KERNEL_HAS_SETATTR_PREPARE \ linux/fs.h check_struct_field \ inode_operations::get_acl \ KERNEL_HAS_GET_ACL \ linux/fs.h check_struct_field_type \ inode_operations::get_acl "struct posix_acl* (*)(struct mnt_idmap *, struct dentry *, int)" \ KERNEL_HAS_POSIX_GET_ACL_IDMAP \ linux/fs.h check_struct_field_type \ inode_operations::get_acl "struct posix_acl* (*)(struct user_namespace *, struct dentry *, int)" \ KERNEL_HAS_POSIX_GET_ACL_NS \ linux/fs.h check_symbol \ "extern const struct xattr_handler posix_acl_default_xattr_handler;" \ KERNEL_HAS_POSIX_ACL_DEFAULT_XATTR_HANDLER \ linux/posix_acl_xattr.h check_struct_field_type \ inode_operations::get_acl "struct posix_acl* (*)(struct inode *, int, bool)" \ KERNEL_POSIX_GET_ACL_HAS_RCU \ linux/fs.h check_struct_field_type \ inode_operations::get_inode_acl "struct posix_acl* (*)(struct inode *, int, bool)" \ KERNEL_HAS_GET_INODE_ACL \ linux/fs.h check_struct_field \ inode_operations::set_acl \ KERNEL_HAS_SET_ACL \ linux/fs.h check_struct_field_type \ inode_operations::set_acl "int (*)(struct user_namespace *, struct inode *, struct posix_acl *, int)" \ KERNEL_HAS_SET_ACL_NS_INODE \ linux/fs.h check_struct_field_type \ inode_operations::set_acl "int (*)(struct mnt_idmap *, struct dentry *, struct posix_acl *, int)" \ KERNEL_HAS_SET_ACL_DENTRY \ linux/fs.h check_struct_field_type \ inode_operations::set_acl "int (*)(struct user_namespace *, struct dentry *, struct posix_acl *, int)" \ KERNEL_HAS_SET_ACL_DENTRY \ linux/fs.h check_function \ vfs_create "int (struct user_namespace *, struct inode *, struct dentry *, umode_t, bool)" \ KERNEL_HAS_USER_NS_MOUNTS \ linux/fs.h check_function \ vfs_create "int (struct mnt_idmap *, struct inode *, struct dentry *, umode_t, bool)" \ KERNEL_HAS_IDMAPPED_MOUNTS \ linux/fs.h check_struct_field_type \ file_operations::iterate "int (*)(struct file *, struct dir_context *)" \ KERNEL_HAS_FOPS_ITERATE \ linux/fs.h check_struct_field_type \ xattr_handler::set "int (*)(const struct xattr_handler *, struct dentry *, struct inode *, const char *, const void *, size_t, int)" \ KERNEL_HAS_XATTR_HANDLERS_INODE_ARG \ linux/xattr.h check_struct_field_type \ xattr_handler::set "int (*)(const struct xattr_handler *, struct user_namespace *, struct dentry *, struct inode *, const char *, const void *, size_t, int)" \ KERNEL_HAS_XATTR_HANDLERS_INODE_ARG \ linux/xattr.h check_struct_field_type \ xattr_handler::set "int (*)(const struct xattr_handler *, struct mnt_idmap *, struct dentry *, struct inode *, const char *, const void *, size_t, int)" \ KERNEL_HAS_XATTR_HANDLERS_INODE_ARG \ linux/xattr.h check_struct_field \ thread_info::cpu \ KERNEL_HAS_CPU_IN_THREAD_INFO \ linux/thread_info.h check_function \ generic_fillattr "void (struct mnt_idmap *, u32, struct inode *, struct kstat *)" \ KERNEL_HAS_GENERIC_FILLATTR_REQUEST_MASK \ linux/fs.h # Kernel 6.5 introduced getters and setters for struct inode's ctime field check_function \ inode_get_ctime "struct timespec64 (const struct inode *inode)" \ KERNEL_HAS_INODE_GET_SET_CTIME \ linux/fs.h # Kernel 6.6 introduced more getters and setters, also for atime and mtime check_function \ inode_get_mtime "struct timespec64 (const struct inode *inode)" \ KERNEL_HAS_INODE_GET_SET_CTIME_MTIME_ATIME \ linux/fs.h # From Linux kernel 6.12 onward, unaligned.h has been moved from to include path check_header \ linux/unaligned.h \ KERNEL_HAS_LINUX_UNALIGNED_H # we have to communicate with the calling makefile somehow. since we can't really use the return # code of this script, we'll echo a special string at the end of our output for the caller to # detect and remove again. # this string has to be something that will, on its own, never be a valid compiler option. so let's # choose something really, really unlikely like echo "--~~success~~--"