if (!test_bit(LL_SBI_HYBRID_IO, sbi->ll_flags))
RETURN(false);
+
+ if (iot == CIT_WRITE &&
+ count >= sbi->ll_hybrid_io_write_threshold_bytes)
+ RETURN(true);
+
+ if (iot == CIT_READ &&
+ count >= sbi->ll_hybrid_io_read_threshold_bytes)
+ RETURN(true);
#endif
RETURN(false);
}
/* Time in ms after last file close we no longer count prior opens*/
u32 ll_oc_max_ms;
+ /* I/O size thresholds for switching from buffered I/O to direct I/O */
+ u32 ll_hybrid_io_write_threshold_bytes;
+ u32 ll_hybrid_io_read_threshold_bytes;
+
/* filesystem fsname */
char ll_fsname[LUSTRE_MAXFSNAME + 1];
return !ll_d2d(dentry) || ll_d2d(dentry)->lld_invalid;
}
+/* 8 MiB is where reads are reliably better as DIO on most configs */
+#define SBI_DEFAULT_HYBRID_IO_READ_THRESHOLD (8 * 1024 * 1024) /* 8 MiB */
+/* 2 MiB is where writes are reliably better as DIO on most configs */
+#define SBI_DEFAULT_HYBRID_IO_WRITE_THRESHOLD (2 * 1024 * 1024) /* 2 MiB */
+
/*
* Mark dentry INVALID, if dentry refcount is zero (this is normally case for
* ll_md_blocking_ast), it will be pruned by ll_prune_aliases() and
set_bit(LL_SBI_STATFS_PROJECT, sbi->ll_flags);
ll_sbi_set_encrypt(sbi, true);
ll_sbi_set_name_encrypt(sbi, true);
- set_bit(LL_SBI_HYBRID_IO, sbi->ll_flags);
/* root squash */
sbi->ll_squash.rsi_uid = 0;
sbi->ll_oc_thrsh_count = SBI_DEFAULT_OPENCACHE_THRESHOLD_COUNT;
sbi->ll_oc_max_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MAX_MS;
sbi->ll_oc_thrsh_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MS;
+ sbi->ll_hybrid_io_write_threshold_bytes =
+ SBI_DEFAULT_HYBRID_IO_WRITE_THRESHOLD;
+ sbi->ll_hybrid_io_read_threshold_bytes =
+ SBI_DEFAULT_HYBRID_IO_READ_THRESHOLD;
INIT_LIST_HEAD(&sbi->ll_all_quota_list);
RETURN(sbi);
}
LUSTRE_RW_ATTR(inode_cache);
+/* an arbitrary but very large maximum value for sanity */
+#define HYBRID_IO_THRESHOLD_BYTES_MAX (2 * 1024 * 1024 * 1024UL) /* 2 GiB */
+static ssize_t hybrid_io_write_threshold_bytes_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
+ ll_kset.kobj);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ sbi->ll_hybrid_io_write_threshold_bytes);
+}
+
+static ssize_t hybrid_io_write_threshold_bytes_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer,
+ size_t count)
+{
+ struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
+ ll_kset.kobj);
+ u64 val;
+ int rc;
+
+ rc = sysfs_memparse(buffer, count, &val, "B");
+ if (rc)
+ return rc;
+
+ if (val > HYBRID_IO_THRESHOLD_BYTES_MAX)
+ return -ERANGE;
+
+ sbi->ll_hybrid_io_write_threshold_bytes = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(hybrid_io_write_threshold_bytes);
+
+static ssize_t hybrid_io_read_threshold_bytes_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
+ ll_kset.kobj);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ sbi->ll_hybrid_io_read_threshold_bytes);
+}
+
+static ssize_t hybrid_io_read_threshold_bytes_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer,
+ size_t count)
+{
+ struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
+ ll_kset.kobj);
+ u64 val;
+ int rc;
+
+ rc = sysfs_memparse(buffer, count, &val, "B");
+ if (rc)
+ return rc;
+
+ if (val > HYBRID_IO_THRESHOLD_BYTES_MAX)
+ return -ERANGE;
+
+ sbi->ll_hybrid_io_read_threshold_bytes = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(hybrid_io_read_threshold_bytes);
+
static int ll_unstable_stats_seq_show(struct seq_file *m, void *v)
{
struct super_block *sb = m->private;
&lustre_attr_opencache_threshold_ms.attr,
&lustre_attr_opencache_max_ms.attr,
&lustre_attr_inode_cache.attr,
+ &lustre_attr_hybrid_io_write_threshold_bytes.attr,
+ &lustre_attr_hybrid_io_read_threshold_bytes.attr,
#ifdef CONFIG_LL_ENCRYPTION
&lustre_attr_enable_filename_encryption.attr,
#endif
#define OBD_FAIL_OST_ENOSPC 0x215
do_facet ost1 "$LCTL set_param fail_loc=0x80000215"
$LFS setstripe -i 0 -c 1 $DIR/$tfile
+ # DIO does not support partial writes to a single stripe - a write to
+ # each stripe will fail or succeed entirely. So we disable hybrid IO
+ # so we can see the partial write behavior of buffered IO
+ local hybrid=$($LCTL get_param -n llite.*.hybrid_io)
+ $LCTL set_param llite.*.hybrid_io=0
+ stack_trap "$LCTL set_param -n llite.*.hybrid_io=$hybrid" EXIT
$MULTIOP $DIR/$tfile oO_WRONLY:P$((4 * 1024 * 1024 + 10 * 4096))c ||
error "multiop failed"
}
$LFS setstripe -c 1 -i 0 $DIR/$tfile || error "lfs setstripe failed"
+ # Hybrid means this won't really be buffered IO, so we disable it for
+ # this part of the test
+ local hybrid=$($LCTL get_param -n llite.*.hybrid_io)
+ $LCTL set_param llite.*.hybrid_io=0
+ stack_trap "$LCTL set_param -n llite.*.hybrid_io=$hybrid" EXIT
# Testing that buffered IO consumes grant on the client
# Delay the RPC on the server so it's guaranteed to not complete even
test_101h() {
$LFS setstripe -i 0 -c 1 $DIR/$tfile
+ local hybrid=$($LCTL get_param -n llite.*.hybrid_io)
+ $LCTL set_param llite.*.hybrid_io=0
+ stack_trap "$LCTL set_param -n llite.*.hybrid_io=$hybrid" EXIT
dd if=/dev/zero of=$DIR/$tfile bs=1M count=70 ||
error "dd 70M file failed"
local file_size=$((1048576 * 16))
local old_ra=$($LCTL get_param -n llite.*.max_read_ahead_mb | head -n 1)
stack_trap "$LCTL set_param -n llite.*.max_read_ahead_mb $old_ra" EXIT
+ local hybrid=$($LCTL get_param -n llite.*.hybrid_io)
+ $LCTL set_param llite.*.hybrid_io=0
+ stack_trap "$LCTL set_param -n llite.*.hybrid_io=$hybrid" EXIT
echo Disable read-ahead
$LCTL set_param -n llite.*.max_read_ahead_mb=0
local average_cache=0
local average_ladvise=0
+ # Hybrid IO switches to DIO, which invalidates much of the caching
+ # So disable it for this test
+ local hybrid=$($LCTL get_param -n llite.*.hybrid_io)
+ $LCTL set_param llite.*.hybrid_io=0
+ stack_trap "$LCTL set_param -n llite.*.hybrid_io=$hybrid" EXIT
+
for ((i = 1; i <= $repeat; i++)); do
echo "Iter $i/$repeat: reading without willread hint"
cancel_lru_locks osc
lctl set_param -n mdc.*.stats=clear
lctl set_param -n osc.*.stats=clear
+ # Hybrid switches to DIO, so does not hold the required lock to skip
+ # the glimpse, so we disable it here...
+ local hybrid=$($LCTL get_param -n llite.*.hybrid_io)
+ $LCTL set_param llite.*.hybrid_io=0
+ stack_trap "$LCTL set_param -n llite.*.hybrid_io=$hybrid" EXIT
dd if=/dev/zero of=$dom bs=2048K count=1 || return 1
cancel_lru_locks mdc
$CHECKSTAT -t file -s 2097152 $dom || error "stat"