zfs: merge openzfs/zfs@d2ccc2155
Notable upstream pull request merges: #16431244ea5c48Add missing kstats to dataset kstats Obtained from: OpenZFS OpenZFS commit:d2ccc21552
This commit is contained in:
@@ -25,6 +25,8 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_PLUG], [
|
||||
dnl #
|
||||
dnl # 2.6.32 - 4.11: statically allocated bdi in request_queue
|
||||
dnl # 4.12: dynamically allocated bdi in request_queue
|
||||
dnl # 6.11: bdi no longer available through request_queue, so get it from
|
||||
dnl # the gendisk attached to the queue
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_BDI], [
|
||||
ZFS_LINUX_TEST_SRC([blk_queue_bdi], [
|
||||
@@ -47,6 +49,30 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_BDI], [
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISK_BDI], [
|
||||
ZFS_LINUX_TEST_SRC([blk_queue_disk_bdi], [
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/backing-dev.h>
|
||||
], [
|
||||
struct request_queue q;
|
||||
struct gendisk disk;
|
||||
struct backing_dev_info bdi __attribute__ ((unused));
|
||||
q.disk = &disk;
|
||||
q.disk->bdi = &bdi;
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_DISK_BDI], [
|
||||
AC_MSG_CHECKING([whether backing_dev_info is available through queue gendisk])
|
||||
ZFS_LINUX_TEST_RESULT([blk_queue_disk_bdi], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_BLK_QUEUE_DISK_BDI, 1,
|
||||
[backing_dev_info is available through queue gendisk])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # 5.9: added blk_queue_update_readahead(),
|
||||
dnl # 5.15: renamed to disk_update_readahead()
|
||||
@@ -407,6 +433,7 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_MQ], [
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE], [
|
||||
ZFS_AC_KERNEL_SRC_BLK_QUEUE_PLUG
|
||||
ZFS_AC_KERNEL_SRC_BLK_QUEUE_BDI
|
||||
ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISK_BDI
|
||||
ZFS_AC_KERNEL_SRC_BLK_QUEUE_UPDATE_READAHEAD
|
||||
ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISCARD
|
||||
ZFS_AC_KERNEL_SRC_BLK_QUEUE_SECURE_ERASE
|
||||
@@ -421,6 +448,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE], [
|
||||
AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE], [
|
||||
ZFS_AC_KERNEL_BLK_QUEUE_PLUG
|
||||
ZFS_AC_KERNEL_BLK_QUEUE_BDI
|
||||
ZFS_AC_KERNEL_BLK_QUEUE_DISK_BDI
|
||||
ZFS_AC_KERNEL_BLK_QUEUE_UPDATE_READAHEAD
|
||||
ZFS_AC_KERNEL_BLK_QUEUE_DISCARD
|
||||
ZFS_AC_KERNEL_BLK_QUEUE_SECURE_ERASE
|
||||
|
||||
@@ -58,6 +58,13 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MAKE_REQUEST_FN], [
|
||||
disk = blk_alloc_disk(lim, NUMA_NO_NODE);
|
||||
])
|
||||
|
||||
ZFS_LINUX_TEST_SRC([blkdev_queue_limits_features], [
|
||||
#include <linux/blkdev.h>
|
||||
],[
|
||||
struct queue_limits *lim = NULL;
|
||||
lim->features = 0;
|
||||
])
|
||||
|
||||
ZFS_LINUX_TEST_SRC([blk_cleanup_disk], [
|
||||
#include <linux/blkdev.h>
|
||||
],[
|
||||
@@ -114,6 +121,20 @@ AC_DEFUN([ZFS_AC_KERNEL_MAKE_REQUEST_FN], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_BLK_ALLOC_DISK_2ARG], 1, [blk_alloc_disk() exists and takes 2 args])
|
||||
|
||||
dnl #
|
||||
dnl # Linux 6.11 API change:
|
||||
dnl # struct queue_limits gains a 'features' field,
|
||||
dnl # used to set flushing options
|
||||
dnl #
|
||||
AC_MSG_CHECKING([whether struct queue_limits has a features field])
|
||||
ZFS_LINUX_TEST_RESULT([blkdev_queue_limits_features], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_BLKDEV_QUEUE_LIMITS_FEATURES], 1,
|
||||
[struct queue_limits has a features field])
|
||||
], [
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # 5.20 API change,
|
||||
dnl # Removed blk_cleanup_disk(), put_disk() should be used.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_SIZE], [
|
||||
ZFS_LINUX_TEST_SRC([page_size], [
|
||||
#include <linux/mm.h>
|
||||
],[
|
||||
unsigned long s;
|
||||
s = page_size(NULL);
|
||||
])
|
||||
])
|
||||
AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_SIZE], [
|
||||
AC_MSG_CHECKING([whether page_size() is available])
|
||||
ZFS_LINUX_TEST_RESULT([page_size], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_MM_PAGE_SIZE, 1, [page_size() is available])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,36 @@
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_SIZE], [
|
||||
ZFS_LINUX_TEST_SRC([page_size], [
|
||||
#include <linux/mm.h>
|
||||
],[
|
||||
unsigned long s;
|
||||
s = page_size(NULL);
|
||||
])
|
||||
])
|
||||
AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_SIZE], [
|
||||
AC_MSG_CHECKING([whether page_size() is available])
|
||||
ZFS_LINUX_TEST_RESULT([page_size], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_MM_PAGE_SIZE, 1, [page_size() is available])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_MAPPING], [
|
||||
ZFS_LINUX_TEST_SRC([page_mapping], [
|
||||
#include <linux/pagemap.h>
|
||||
],[
|
||||
struct page *p = NULL;
|
||||
struct address_space *m = page_mapping(NULL);
|
||||
])
|
||||
])
|
||||
AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_MAPPING], [
|
||||
AC_MSG_CHECKING([whether page_mapping() is available])
|
||||
ZFS_LINUX_TEST_RESULT([page_mapping], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_MM_PAGE_MAPPING, 1, [page_mapping() is available])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
||||
@@ -25,3 +25,62 @@ AC_DEFUN([ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE], [
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # Linux 6.11 register_sysctl() enforces that sysctl tables no longer
|
||||
dnl # supply a sentinel end-of-table element. 6.6 introduces
|
||||
dnl # register_sysctl_sz() to enable callers to choose, so we use it if
|
||||
dnl # available for backward compatibility.
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ], [
|
||||
ZFS_LINUX_TEST_SRC([has_register_sysctl_sz], [
|
||||
#include <linux/sysctl.h>
|
||||
],[
|
||||
struct ctl_table test_table[] __attribute__((unused)) = {0};
|
||||
register_sysctl_sz("", test_table, 0);
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ], [
|
||||
AC_MSG_CHECKING([whether register_sysctl_sz exists])
|
||||
ZFS_LINUX_TEST_RESULT([has_register_sysctl_sz], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_REGISTER_SYSCTL_SZ, 1,
|
||||
[register_sysctl_sz exists])
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
||||
|
||||
dnl #
|
||||
dnl # Linux 6.11 makes const the ctl_table arg of proc_handler
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_PROC_HANDLER_CTL_TABLE_CONST], [
|
||||
ZFS_LINUX_TEST_SRC([has_proc_handler_ctl_table_const], [
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
static int test_handler(
|
||||
const struct ctl_table *ctl __attribute((unused)),
|
||||
int write __attribute((unused)),
|
||||
void *buffer __attribute((unused)),
|
||||
size_t *lenp __attribute((unused)),
|
||||
loff_t *ppos __attribute((unused)))
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
], [
|
||||
proc_handler *ph __attribute((unused)) =
|
||||
&test_handler;
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_PROC_HANDLER_CTL_TABLE_CONST], [
|
||||
AC_MSG_CHECKING([whether proc_handler ctl_table arg is const])
|
||||
ZFS_LINUX_TEST_RESULT([has_proc_handler_ctl_table_const], [
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(HAVE_PROC_HANDLER_CTL_TABLE_CONST, 1,
|
||||
[proc_handler ctl_table arg is const])
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -167,9 +167,12 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
||||
ZFS_AC_KERNEL_SRC_WRITEPAGE_T
|
||||
ZFS_AC_KERNEL_SRC_RECLAIMED
|
||||
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
|
||||
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ
|
||||
ZFS_AC_KERNEL_SRC_PROC_HANDLER_CTL_TABLE_CONST
|
||||
ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ
|
||||
ZFS_AC_KERNEL_SRC_SYNC_BDEV
|
||||
ZFS_AC_KERNEL_SRC_MM_PAGE_SIZE
|
||||
ZFS_AC_KERNEL_SRC_MM_PAGE_MAPPING
|
||||
case "$host_cpu" in
|
||||
powerpc*)
|
||||
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
|
||||
@@ -319,9 +322,12 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
||||
ZFS_AC_KERNEL_WRITEPAGE_T
|
||||
ZFS_AC_KERNEL_RECLAIMED
|
||||
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
|
||||
ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ
|
||||
ZFS_AC_KERNEL_PROC_HANDLER_CTL_TABLE_CONST
|
||||
ZFS_AC_KERNEL_COPY_SPLICE_READ
|
||||
ZFS_AC_KERNEL_SYNC_BDEV
|
||||
ZFS_AC_KERNEL_MM_PAGE_SIZE
|
||||
ZFS_AC_KERNEL_MM_PAGE_MAPPING
|
||||
case "$host_cpu" in
|
||||
powerpc*)
|
||||
ZFS_AC_KERNEL_CPU_HAS_FEATURE
|
||||
|
||||
@@ -57,6 +57,11 @@ blk_queue_flag_clear(unsigned int flag, struct request_queue *q)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 6.11 API
|
||||
* Setting the flush flags directly is no longer possible; flush flags are set
|
||||
* on the queue_limits structure and passed to blk_disk_alloc(). In this case
|
||||
* we remove this function entirely.
|
||||
*
|
||||
* 4.7 API,
|
||||
* The blk_queue_write_cache() interface has replaced blk_queue_flush()
|
||||
* interface. However, the new interface is GPL-only thus we implement
|
||||
@@ -68,31 +73,33 @@ blk_queue_flag_clear(unsigned int flag, struct request_queue *q)
|
||||
* new one is GPL-only. Thus if the GPL-only version is detected we
|
||||
* implement our own trivial helper.
|
||||
*/
|
||||
#if !defined(HAVE_BLK_ALLOC_DISK_2ARG) || \
|
||||
!defined(HAVE_BLKDEV_QUEUE_LIMITS_FEATURES)
|
||||
static inline void
|
||||
blk_queue_set_write_cache(struct request_queue *q, bool wc, bool fua)
|
||||
blk_queue_set_write_cache(struct request_queue *q, bool on)
|
||||
{
|
||||
#if defined(HAVE_BLK_QUEUE_WRITE_CACHE_GPL_ONLY)
|
||||
if (wc)
|
||||
if (on) {
|
||||
blk_queue_flag_set(QUEUE_FLAG_WC, q);
|
||||
else
|
||||
blk_queue_flag_clear(QUEUE_FLAG_WC, q);
|
||||
if (fua)
|
||||
blk_queue_flag_set(QUEUE_FLAG_FUA, q);
|
||||
else
|
||||
} else {
|
||||
blk_queue_flag_clear(QUEUE_FLAG_WC, q);
|
||||
blk_queue_flag_clear(QUEUE_FLAG_FUA, q);
|
||||
}
|
||||
#elif defined(HAVE_BLK_QUEUE_WRITE_CACHE)
|
||||
blk_queue_write_cache(q, wc, fua);
|
||||
blk_queue_write_cache(q, on, on);
|
||||
#elif defined(HAVE_BLK_QUEUE_FLUSH_GPL_ONLY)
|
||||
if (wc)
|
||||
q->flush_flags |= REQ_FLUSH;
|
||||
if (fua)
|
||||
q->flush_flags |= REQ_FUA;
|
||||
if (on)
|
||||
q->flush_flags |= REQ_FLUSH | REQ_FUA;
|
||||
else
|
||||
q->flush_flags &= ~(REQ_FLUSH | REQ_FUA);
|
||||
#elif defined(HAVE_BLK_QUEUE_FLUSH)
|
||||
blk_queue_flush(q, (wc ? REQ_FLUSH : 0) | (fua ? REQ_FUA : 0));
|
||||
blk_queue_flush(q, on ? (REQ_FLUSH | REQ_FUA) : 0);
|
||||
#else
|
||||
#error "Unsupported kernel"
|
||||
#endif
|
||||
}
|
||||
#endif /* !HAVE_BLK_ALLOC_DISK_2ARG || !HAVE_BLKDEV_QUEUE_LIMITS_FEATURES */
|
||||
|
||||
/*
|
||||
* Detect if a device has a write cache. Used to set the intial value for the
|
||||
@@ -126,8 +133,10 @@ blk_queue_set_read_ahead(struct request_queue *q, unsigned long ra_pages)
|
||||
{
|
||||
#if !defined(HAVE_BLK_QUEUE_UPDATE_READAHEAD) && \
|
||||
!defined(HAVE_DISK_UPDATE_READAHEAD)
|
||||
#ifdef HAVE_BLK_QUEUE_BDI_DYNAMIC
|
||||
#if defined(HAVE_BLK_QUEUE_BDI_DYNAMIC)
|
||||
q->backing_dev_info->ra_pages = ra_pages;
|
||||
#elif defined(HAVE_BLK_QUEUE_DISK_BDI)
|
||||
q->disk->bdi->ra_pages = ra_pages;
|
||||
#else
|
||||
q->backing_dev_info.ra_pages = ra_pages;
|
||||
#endif
|
||||
|
||||
@@ -21,16 +21,23 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Klara Inc.
|
||||
* Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||
*/
|
||||
|
||||
#ifndef _ZFS_MM_COMPAT_H
|
||||
#define _ZFS_MM_COMPAT_H
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
/* 5.4 introduced page_size(). Older kernels can use a trivial macro instead */
|
||||
#ifndef HAVE_MM_PAGE_SIZE
|
||||
#define page_size(p) ((unsigned long)(PAGE_SIZE << compound_order(p)))
|
||||
#endif
|
||||
|
||||
/* 6.11 removed page_mapping(). A simple wrapper around folio_mapping() works */
|
||||
#ifndef HAVE_MM_PAGE_MAPPING
|
||||
#define page_mapping(p) folio_mapping(page_folio(p))
|
||||
#endif
|
||||
|
||||
#endif /* _ZFS_MM_COMPAT_H */
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
*
|
||||
* Solaris Porting Layer (SPL) Proc Implementation.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||
*/
|
||||
|
||||
#include <sys/systeminfo.h>
|
||||
#include <sys/kstat.h>
|
||||
@@ -43,6 +46,12 @@ typedef struct ctl_table __no_const spl_ctl_table;
|
||||
typedef struct ctl_table spl_ctl_table;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PROC_HANDLER_CTL_TABLE_CONST
|
||||
#define CONST_CTL_TABLE const struct ctl_table
|
||||
#else
|
||||
#define CONST_CTL_TABLE struct ctl_table
|
||||
#endif
|
||||
|
||||
static unsigned long table_min = 0;
|
||||
static unsigned long table_max = ~0;
|
||||
|
||||
@@ -60,7 +69,7 @@ struct proc_dir_entry *proc_spl_kstat = NULL;
|
||||
|
||||
#ifdef DEBUG_KMEM
|
||||
static int
|
||||
proc_domemused(struct ctl_table *table, int write,
|
||||
proc_domemused(CONST_CTL_TABLE *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -88,7 +97,7 @@ proc_domemused(struct ctl_table *table, int write,
|
||||
#endif /* DEBUG_KMEM */
|
||||
|
||||
static int
|
||||
proc_doslab(struct ctl_table *table, int write,
|
||||
proc_doslab(CONST_CTL_TABLE *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -135,7 +144,7 @@ proc_doslab(struct ctl_table *table, int write,
|
||||
}
|
||||
|
||||
static int
|
||||
proc_dohostid(struct ctl_table *table, int write,
|
||||
proc_dohostid(CONST_CTL_TABLE *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
char *end, str[32];
|
||||
@@ -688,6 +697,37 @@ static void spl_proc_cleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_REGISTER_SYSCTL_TABLE
|
||||
|
||||
/*
|
||||
* Traditionally, struct ctl_table arrays have been terminated by an "empty"
|
||||
* sentinel element (specifically, one with .procname == NULL).
|
||||
*
|
||||
* Linux 6.6 began migrating away from this, adding register_sysctl_sz() so
|
||||
* that callers could provide the size directly, and redefining
|
||||
* register_sysctl() to just call register_sysctl_sz() with the array size. It
|
||||
* retained support for the terminating element so that existing callers would
|
||||
* continue to work.
|
||||
*
|
||||
* Linux 6.11 removed support for the terminating element, instead interpreting
|
||||
* it as a real malformed element, and rejecting it.
|
||||
*
|
||||
* In order to continue support older kernels, we retain the terminating
|
||||
* sentinel element for our sysctl tables, but instead detect availability of
|
||||
* register_sysctl_sz(). If it exists, we pass it the array size -1, stopping
|
||||
* the kernel from trying to process the terminator. For pre-6.6 kernels that
|
||||
* don't have register_sysctl_sz(), we just use register_sysctl(), which can
|
||||
* handle the terminating element as it always has.
|
||||
*/
|
||||
#ifdef HAVE_REGISTER_SYSCTL_SZ
|
||||
#define spl_proc_register_sysctl(p, t) \
|
||||
register_sysctl_sz(p, t, ARRAY_SIZE(t)-1)
|
||||
#else
|
||||
#define spl_proc_register_sysctl(p, t) \
|
||||
register_sysctl(p, t)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int
|
||||
spl_proc_init(void)
|
||||
{
|
||||
@@ -698,16 +738,17 @@ spl_proc_init(void)
|
||||
if (spl_header == NULL)
|
||||
return (-EUNATCH);
|
||||
#else
|
||||
spl_header = register_sysctl("kernel/spl", spl_table);
|
||||
spl_header = spl_proc_register_sysctl("kernel/spl", spl_table);
|
||||
if (spl_header == NULL)
|
||||
return (-EUNATCH);
|
||||
|
||||
spl_kmem = register_sysctl("kernel/spl/kmem", spl_kmem_table);
|
||||
spl_kmem = spl_proc_register_sysctl("kernel/spl/kmem", spl_kmem_table);
|
||||
if (spl_kmem == NULL) {
|
||||
rc = -EUNATCH;
|
||||
goto out;
|
||||
}
|
||||
spl_kstat = register_sysctl("kernel/spl/kstat", spl_kstat_table);
|
||||
spl_kstat = spl_proc_register_sysctl("kernel/spl/kstat",
|
||||
spl_kstat_table);
|
||||
if (spl_kstat == NULL) {
|
||||
rc = -EUNATCH;
|
||||
goto out;
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#include <sys/zpl.h>
|
||||
#include <sys/zil.h>
|
||||
#include <sys/sa_impl.h>
|
||||
#include <linux/mm_compat.h>
|
||||
|
||||
/*
|
||||
* Programming rules.
|
||||
@@ -1788,24 +1789,36 @@ zfs_setattr_dir(znode_t *dzp)
|
||||
&gid, sizeof (gid));
|
||||
}
|
||||
|
||||
if (zp->z_projid != dzp->z_projid) {
|
||||
|
||||
uint64_t projid = dzp->z_projid;
|
||||
if (zp->z_projid != projid) {
|
||||
if (!(zp->z_pflags & ZFS_PROJID)) {
|
||||
zp->z_pflags |= ZFS_PROJID;
|
||||
SA_ADD_BULK_ATTR(bulk, count,
|
||||
SA_ZPL_FLAGS(zfsvfs), NULL, &zp->z_pflags,
|
||||
sizeof (zp->z_pflags));
|
||||
err = sa_add_projid(zp->z_sa_hdl, tx, projid);
|
||||
if (unlikely(err == EEXIST)) {
|
||||
err = 0;
|
||||
} else if (err != 0) {
|
||||
goto sa_add_projid_err;
|
||||
} else {
|
||||
projid = ZFS_INVALID_PROJID;
|
||||
}
|
||||
}
|
||||
|
||||
zp->z_projid = dzp->z_projid;
|
||||
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PROJID(zfsvfs),
|
||||
NULL, &zp->z_projid, sizeof (zp->z_projid));
|
||||
if (projid != ZFS_INVALID_PROJID) {
|
||||
zp->z_projid = projid;
|
||||
SA_ADD_BULK_ATTR(bulk, count,
|
||||
SA_ZPL_PROJID(zfsvfs), NULL, &zp->z_projid,
|
||||
sizeof (zp->z_projid));
|
||||
}
|
||||
}
|
||||
|
||||
sa_add_projid_err:
|
||||
mutex_exit(&dzp->z_lock);
|
||||
|
||||
if (likely(count > 0)) {
|
||||
err = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
|
||||
dmu_tx_commit(tx);
|
||||
} else if (projid == ZFS_INVALID_PROJID) {
|
||||
dmu_tx_commit(tx);
|
||||
} else {
|
||||
dmu_tx_abort(tx);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||
* Copyright (c) 2024, Klara, Inc.
|
||||
*/
|
||||
|
||||
@@ -1089,11 +1090,42 @@ static const struct block_device_operations zvol_ops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Since 6.9, Linux has been removing queue limit setters in favour of an
|
||||
* initial queue_limits struct applied when the device is open. Since 6.11,
|
||||
* queue_limits is being extended to allow more things to be applied when the
|
||||
* device is open. Setters are also being removed for this.
|
||||
*
|
||||
* For OpenZFS, this means that depending on kernel version, some options may
|
||||
* be set up before the device is open, and some applied to an open device
|
||||
* (queue) after the fact.
|
||||
*
|
||||
* We manage this complexity by having our own limits struct,
|
||||
* zvol_queue_limits_t, in which we carry any queue config that we're
|
||||
* interested in setting. This structure is the same on all kernels.
|
||||
*
|
||||
* These limits are then applied to the queue at device open time by the most
|
||||
* appropriate method for the kernel.
|
||||
*
|
||||
* zvol_queue_limits_convert() is used on 6.9+ (where the two-arg form of
|
||||
* blk_alloc_disk() exists). This converts our limits struct to a proper Linux
|
||||
* struct queue_limits, and passes it in. Any fields added in later kernels are
|
||||
* (obviously) not set up here.
|
||||
*
|
||||
* zvol_queue_limits_apply() is called on all kernel versions after the queue
|
||||
* is created, and applies any remaining config. Before 6.9 that will be
|
||||
* everything, via setter methods. After 6.9 that will be whatever couldn't be
|
||||
* put into struct queue_limits. (This implies that zvol_queue_limits_apply()
|
||||
* will always be a no-op on the latest kernel we support).
|
||||
*/
|
||||
typedef struct zvol_queue_limits {
|
||||
unsigned int zql_max_hw_sectors;
|
||||
unsigned short zql_max_segments;
|
||||
unsigned int zql_max_segment_size;
|
||||
unsigned int zql_io_opt;
|
||||
unsigned int zql_physical_block_size;
|
||||
unsigned int zql_max_discard_sectors;
|
||||
unsigned int zql_discard_granularity;
|
||||
} zvol_queue_limits_t;
|
||||
|
||||
static void
|
||||
@@ -1162,6 +1194,11 @@ zvol_queue_limits_init(zvol_queue_limits_t *limits, zvol_state_t *zv,
|
||||
}
|
||||
|
||||
limits->zql_io_opt = zv->zv_volblocksize;
|
||||
|
||||
limits->zql_physical_block_size = zv->zv_volblocksize;
|
||||
limits->zql_max_discard_sectors =
|
||||
(zvol_max_discard_blocks * zv->zv_volblocksize) >> 9;
|
||||
limits->zql_discard_granularity = zv->zv_volblocksize;
|
||||
}
|
||||
|
||||
#ifdef HAVE_BLK_ALLOC_DISK_2ARG
|
||||
@@ -1174,18 +1211,34 @@ zvol_queue_limits_convert(zvol_queue_limits_t *limits,
|
||||
qlimits->max_segments = limits->zql_max_segments;
|
||||
qlimits->max_segment_size = limits->zql_max_segment_size;
|
||||
qlimits->io_opt = limits->zql_io_opt;
|
||||
qlimits->physical_block_size = limits->zql_physical_block_size;
|
||||
qlimits->max_discard_sectors = limits->zql_max_discard_sectors;
|
||||
qlimits->discard_granularity = limits->zql_discard_granularity;
|
||||
#ifdef HAVE_BLKDEV_QUEUE_LIMITS_FEATURES
|
||||
qlimits->features =
|
||||
BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA | BLK_FEAT_IO_STAT;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
static void
|
||||
zvol_queue_limits_apply(zvol_queue_limits_t *limits,
|
||||
struct request_queue *queue)
|
||||
{
|
||||
#ifndef HAVE_BLK_ALLOC_DISK_2ARG
|
||||
blk_queue_max_hw_sectors(queue, limits->zql_max_hw_sectors);
|
||||
blk_queue_max_segments(queue, limits->zql_max_segments);
|
||||
blk_queue_max_segment_size(queue, limits->zql_max_segment_size);
|
||||
blk_queue_io_opt(queue, limits->zql_io_opt);
|
||||
}
|
||||
blk_queue_physical_block_size(queue, limits->zql_physical_block_size);
|
||||
blk_queue_max_discard_sectors(queue, limits->zql_max_discard_sectors);
|
||||
blk_queue_discard_granularity(queue, limits->zql_discard_granularity);
|
||||
#endif
|
||||
#ifndef HAVE_BLKDEV_QUEUE_LIMITS_FEATURES
|
||||
blk_queue_set_write_cache(queue, B_TRUE);
|
||||
blk_queue_flag_set(QUEUE_FLAG_IO_STAT, queue);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
zvol_alloc_non_blk_mq(struct zvol_state_os *zso, zvol_queue_limits_t *limits)
|
||||
@@ -1208,6 +1261,10 @@ zvol_alloc_non_blk_mq(struct zvol_state_os *zso, zvol_queue_limits_t *limits)
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifndef HAVE_BLKDEV_QUEUE_LIMITS_FEATURES
|
||||
blk_queue_set_write_cache(zso->zvo_queue, B_TRUE);
|
||||
#endif
|
||||
|
||||
zso->zvo_disk = disk;
|
||||
zso->zvo_disk->minors = ZVOL_MINORS;
|
||||
zso->zvo_queue = zso->zvo_disk->queue;
|
||||
@@ -1223,7 +1280,6 @@ zvol_alloc_non_blk_mq(struct zvol_state_os *zso, zvol_queue_limits_t *limits)
|
||||
}
|
||||
|
||||
zso->zvo_disk->queue = zso->zvo_queue;
|
||||
zvol_queue_limits_apply(limits, zso->zvo_queue);
|
||||
#endif /* HAVE_BLK_ALLOC_DISK */
|
||||
#else
|
||||
zso->zvo_queue = blk_generic_alloc_queue(zvol_request, NUMA_NO_NODE);
|
||||
@@ -1237,8 +1293,10 @@ zvol_alloc_non_blk_mq(struct zvol_state_os *zso, zvol_queue_limits_t *limits)
|
||||
}
|
||||
|
||||
zso->zvo_disk->queue = zso->zvo_queue;
|
||||
zvol_queue_limits_apply(limits, zso->zvo_queue);
|
||||
#endif /* HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS */
|
||||
|
||||
zvol_queue_limits_apply(limits, zso->zvo_queue);
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
@@ -1260,7 +1318,6 @@ zvol_alloc_blk_mq(zvol_state_t *zv, zvol_queue_limits_t *limits)
|
||||
return (1);
|
||||
}
|
||||
zso->zvo_queue = zso->zvo_disk->queue;
|
||||
zvol_queue_limits_apply(limits, zso->zvo_queue);
|
||||
zso->zvo_disk->minors = ZVOL_MINORS;
|
||||
#elif defined(HAVE_BLK_ALLOC_DISK_2ARG)
|
||||
struct queue_limits qlimits;
|
||||
@@ -1291,10 +1348,11 @@ zvol_alloc_blk_mq(zvol_state_t *zv, zvol_queue_limits_t *limits)
|
||||
|
||||
/* Our queue is now created, assign it to our disk */
|
||||
zso->zvo_disk->queue = zso->zvo_queue;
|
||||
zvol_queue_limits_apply(limits, zso->zvo_queue);
|
||||
#endif
|
||||
|
||||
zvol_queue_limits_apply(limits, zso->zvo_queue);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1360,8 +1418,6 @@ zvol_alloc(dev_t dev, const char *name)
|
||||
if (ret != 0)
|
||||
goto out_kmem;
|
||||
|
||||
blk_queue_set_write_cache(zso->zvo_queue, B_TRUE, B_TRUE);
|
||||
|
||||
/* Limit read-ahead to a single page to prevent over-prefetching. */
|
||||
blk_queue_set_read_ahead(zso->zvo_queue, 1);
|
||||
|
||||
@@ -1370,9 +1426,6 @@ zvol_alloc(dev_t dev, const char *name)
|
||||
blk_queue_flag_set(QUEUE_FLAG_NOMERGES, zso->zvo_queue);
|
||||
}
|
||||
|
||||
/* Enable /proc/diskstats */
|
||||
blk_queue_flag_set(QUEUE_FLAG_IO_STAT, zso->zvo_queue);
|
||||
|
||||
zso->zvo_queue->queuedata = zv;
|
||||
zso->zvo_dev = dev;
|
||||
zv->zv_open_count = 0;
|
||||
@@ -1639,14 +1692,6 @@ zvol_os_create_minor(const char *name)
|
||||
|
||||
set_capacity(zv->zv_zso->zvo_disk, zv->zv_volsize >> 9);
|
||||
|
||||
|
||||
|
||||
blk_queue_physical_block_size(zv->zv_zso->zvo_queue,
|
||||
zv->zv_volblocksize);
|
||||
blk_queue_max_discard_sectors(zv->zv_zso->zvo_queue,
|
||||
(zvol_max_discard_blocks * zv->zv_volblocksize) >> 9);
|
||||
blk_queue_discard_granularity(zv->zv_zso->zvo_queue,
|
||||
zv->zv_volblocksize);
|
||||
#ifdef QUEUE_FLAG_DISCARD
|
||||
blk_queue_flag_set(QUEUE_FLAG_DISCARD, zv->zv_zso->zvo_queue);
|
||||
#endif
|
||||
|
||||
@@ -55,7 +55,7 @@ function display_status
|
||||
((ret |= $?))
|
||||
|
||||
typeset mntpnt=$(get_prop mountpoint $pool)
|
||||
dd if=/dev/random of=$mntpnt/testfile.$$ &
|
||||
dd if=/dev/urandom of=$mntpnt/testfile.$$ &
|
||||
typeset pid=$!
|
||||
|
||||
zpool iostat -v 1 3 > /dev/null
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ log_must truncate -s 1G $VDEV
|
||||
|
||||
log_must zpool create -o feature@block_cloning=enabled $TESTPOOL $VDEV
|
||||
|
||||
log_must dd if=/dev/random of=/$TESTPOOL/file1 bs=1 count=1000
|
||||
log_must dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1 count=1000
|
||||
|
||||
ulimit -f 2
|
||||
log_must clonefile -f /$TESTPOOL/file1 /$TESTPOOL/file2 0 0 all
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ log_onexit cleanup
|
||||
log_assert "ensure single-disk pool resumes properly after suspend and clear"
|
||||
|
||||
# create a file, and take a checksum, so we can compare later
|
||||
log_must dd if=/dev/random of=$DATAFILE bs=128K count=1
|
||||
log_must dd if=/dev/urandom of=$DATAFILE bs=128K count=1
|
||||
typeset sum1=$(cat $DATAFILE | md5sum)
|
||||
|
||||
# make a debug device that we can "unplug"
|
||||
|
||||
+17
-2
@@ -63,6 +63,7 @@ log_must mkfiles $TESTDIR/fs2/tf $((RANDOM % 100 + 1))
|
||||
log_must zfs create $TESTPOOL/fs3
|
||||
log_must mkdir $TESTDIR/fs3/dir
|
||||
log_must mkfiles $TESTDIR/fs3/tf $((RANDOM % 100 + 1))
|
||||
log_must set_xattr_stdin passwd $TESTDIR/fs3/dir < /etc/passwd
|
||||
|
||||
# Make sure project quota is disabled
|
||||
zfs projectspace -o used $TESTPOOL | grep -q "USED" &&
|
||||
@@ -109,9 +110,23 @@ log_must chattr -p 100 $TESTDIR/fs3/dir
|
||||
log_must sleep 5 # upgrade done in the background so let's wait for a while
|
||||
zfs projectspace -o used $TESTPOOL/fs3 | grep -q "USED" ||
|
||||
log_fail "project quota should be enabled for $TESTPOOL/fs3"
|
||||
dirino=$(stat -c '%i' $TESTDIR/fs3/dir)
|
||||
log_must zdb -ddddd $TESTPOOL/fs3 $dirino
|
||||
xattrdirino=$(zdb -ddddd $TESTPOOL/fs3 $dirino |grep -w "xattr" |awk '{print $2}')
|
||||
echo "xattrdirino: $xattrdirino"
|
||||
expectedcnt=1
|
||||
echo "expectedcnt: $expectedcnt"
|
||||
if [ "$xattrdirino" != "" ]; then
|
||||
expectedcnt=$(($expectedcnt + 1))
|
||||
echo "expectedcnt: $expectedcnt"
|
||||
log_must zdb -ddddd $TESTPOOL/fs3 $xattrdirino
|
||||
xattrinocnt=$(zdb -ddddd $TESTPOOL/fs3 $xattrdirino |grep -w "(type:" |wc -l)
|
||||
echo "xattrinocnt: $xattrinocnt"
|
||||
expectedcnt=$(($expectedcnt + $xattrinocnt))
|
||||
echo "expectedcnt: $expectedcnt"
|
||||
fi
|
||||
cnt=$(get_prop projectobjused@100 $TESTPOOL/fs3)
|
||||
# if 'xattr=on', then 'cnt = 2'
|
||||
[[ $cnt -ne 1 ]] && [[ $cnt -ne 2 ]] &&
|
||||
[[ $cnt -ne $expectedcnt ]] &&
|
||||
log_fail "projectquota accounting failed $cnt"
|
||||
|
||||
# All in all, after having been through this, the dataset for testpool
|
||||
|
||||
@@ -189,6 +189,9 @@
|
||||
/* blkdev_put() accepts void* as arg 2 */
|
||||
/* #undef HAVE_BLKDEV_PUT_HOLDER */
|
||||
|
||||
/* struct queue_limits has a features field */
|
||||
/* #undef HAVE_BLKDEV_QUEUE_LIMITS_FEATURES */
|
||||
|
||||
/* blkdev_reread_part() exists */
|
||||
/* #undef HAVE_BLKDEV_REREAD_PART */
|
||||
|
||||
@@ -228,6 +231,9 @@
|
||||
/* blk_queue_discard() is available */
|
||||
/* #undef HAVE_BLK_QUEUE_DISCARD */
|
||||
|
||||
/* backing_dev_info is available through queue gendisk */
|
||||
/* #undef HAVE_BLK_QUEUE_DISK_BDI */
|
||||
|
||||
/* blk_queue_flag_clear() exists */
|
||||
/* #undef HAVE_BLK_QUEUE_FLAG_CLEAR */
|
||||
|
||||
@@ -703,6 +709,9 @@
|
||||
/* Define to 1 if you have the 'mlockall' function. */
|
||||
#define HAVE_MLOCKALL 1
|
||||
|
||||
/* page_mapping() is available */
|
||||
/* #undef HAVE_MM_PAGE_MAPPING */
|
||||
|
||||
/* page_size() is available */
|
||||
/* #undef HAVE_MM_PAGE_SIZE */
|
||||
|
||||
@@ -748,6 +757,9 @@
|
||||
/* posix_acl_valid() wants user namespace */
|
||||
/* #undef HAVE_POSIX_ACL_VALID_WITH_NS */
|
||||
|
||||
/* proc_handler ctl_table arg is const */
|
||||
/* #undef HAVE_PROC_HANDLER_CTL_TABLE_CONST */
|
||||
|
||||
/* proc_ops structure exists */
|
||||
/* #undef HAVE_PROC_OPS_STRUCT */
|
||||
|
||||
@@ -772,6 +784,9 @@
|
||||
/* register_shrinker is vararg */
|
||||
/* #undef HAVE_REGISTER_SHRINKER_VARARG */
|
||||
|
||||
/* register_sysctl_sz exists */
|
||||
/* #undef HAVE_REGISTER_SYSCTL_SZ */
|
||||
|
||||
/* register_sysctl_table exists */
|
||||
/* #undef HAVE_REGISTER_SYSCTL_TABLE */
|
||||
|
||||
@@ -1200,7 +1215,7 @@
|
||||
/* #undef ZFS_IS_GPL_COMPATIBLE */
|
||||
|
||||
/* Define the project alias string. */
|
||||
#define ZFS_META_ALIAS "zfs-2.2.99-623-FreeBSD_g9c56b8ec7"
|
||||
#define ZFS_META_ALIAS "zfs-2.2.99-634-FreeBSD_gd2ccc2155"
|
||||
|
||||
/* Define the project author. */
|
||||
#define ZFS_META_AUTHOR "OpenZFS"
|
||||
@@ -1230,7 +1245,7 @@
|
||||
#define ZFS_META_NAME "zfs"
|
||||
|
||||
/* Define the project release. */
|
||||
#define ZFS_META_RELEASE "623-FreeBSD_g9c56b8ec7"
|
||||
#define ZFS_META_RELEASE "634-FreeBSD_gd2ccc2155"
|
||||
|
||||
/* Define the project version. */
|
||||
#define ZFS_META_VERSION "2.2.99"
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define ZFS_META_GITREV "zfs-2.2.99-623-g9c56b8ec7"
|
||||
#define ZFS_META_GITREV "zfs-2.2.99-634-gd2ccc2155"
|
||||
|
||||
Reference in New Issue
Block a user