Merge pull request #223 from mariuszbarczak/introducing-new-io-class-caching-rule-file-name-prefix
Introducing a new IO class caching rule - file name prefix
This commit is contained in:
commit
b1bd3578db
@ -190,14 +190,21 @@ error:
|
|||||||
static int _cas_cls_string_ctr(struct cas_classifier *cls,
|
static int _cas_cls_string_ctr(struct cas_classifier *cls,
|
||||||
struct cas_cls_condition *c, char *data)
|
struct cas_cls_condition *c, char *data)
|
||||||
{
|
{
|
||||||
|
size_t len;
|
||||||
struct cas_cls_string *ctx;
|
struct cas_cls_string *ctx;
|
||||||
|
|
||||||
if (!data || strlen(data) == 0) {
|
if (!data) {
|
||||||
CAS_CLS_MSG(KERN_ERR, "Missing string specifier\n");
|
CAS_CLS_MSG(KERN_ERR, "Missing string specifier\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(data) > MAX_STRING_SPECIFIER_LEN) {
|
len = strlen(data);
|
||||||
|
if (len == 0) {
|
||||||
|
CAS_CLS_MSG(KERN_ERR, "String specifier is empty\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > MAX_STRING_SPECIFIER_LEN) {
|
||||||
CAS_CLS_MSG(KERN_ERR, "String specifier to long: %s\n", data);
|
CAS_CLS_MSG(KERN_ERR, "String specifier to long: %s\n", data);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -207,6 +214,7 @@ static int _cas_cls_string_ctr(struct cas_classifier *cls,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
strcpy(ctx->string, data);
|
strcpy(ctx->string, data);
|
||||||
|
ctx->len = len;
|
||||||
|
|
||||||
c->context = ctx;
|
c->context = ctx;
|
||||||
|
|
||||||
@ -477,6 +485,41 @@ static cas_cls_eval_t _cas_cls_extension_test(
|
|||||||
return cas_cls_eval_no;
|
return cas_cls_eval_no;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File name prefix test function */
|
||||||
|
static cas_cls_eval_t _cas_cls_file_name_prefix_test(
|
||||||
|
struct cas_classifier *cls, struct cas_cls_condition *c,
|
||||||
|
struct cas_cls_io *io, ocf_part_id_t part_id)
|
||||||
|
{
|
||||||
|
struct cas_cls_string *ctx;
|
||||||
|
struct inode *inode;
|
||||||
|
struct dentry *dentry;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
ctx = c->context;
|
||||||
|
inode = io->inode;
|
||||||
|
|
||||||
|
if (!inode)
|
||||||
|
return cas_cls_eval_no;
|
||||||
|
|
||||||
|
/* I/O target inode dentry */
|
||||||
|
dentry = _cas_cls_dir_get_inode_dentry(inode);
|
||||||
|
|
||||||
|
/* Check if dentry and its name is valid */
|
||||||
|
if (!dentry || !dentry->d_name.name)
|
||||||
|
return cas_cls_eval_no;
|
||||||
|
|
||||||
|
/* Check if name is not too short, we expect full prefix in name */
|
||||||
|
if (dentry->d_name.len < ctx->len)
|
||||||
|
return cas_cls_eval_no;
|
||||||
|
|
||||||
|
/* Final string comparison check */
|
||||||
|
len = min(ctx->len, dentry->d_name.len);
|
||||||
|
if (strncmp(dentry->d_name.name, ctx->string, len) == 0)
|
||||||
|
return cas_cls_eval_yes;
|
||||||
|
|
||||||
|
return cas_cls_eval_no;
|
||||||
|
}
|
||||||
|
|
||||||
/* LBA test function */
|
/* LBA test function */
|
||||||
static cas_cls_eval_t _cas_cls_lba_test(
|
static cas_cls_eval_t _cas_cls_lba_test(
|
||||||
struct cas_classifier *cls, struct cas_cls_condition *c,
|
struct cas_classifier *cls, struct cas_cls_condition *c,
|
||||||
@ -566,6 +609,8 @@ static struct cas_cls_condition_handler _handlers[] = {
|
|||||||
_cas_cls_directory_dtr },
|
_cas_cls_directory_dtr },
|
||||||
{ "extension", _cas_cls_extension_test, _cas_cls_string_ctr,
|
{ "extension", _cas_cls_extension_test, _cas_cls_string_ctr,
|
||||||
_cas_cls_generic_dtr },
|
_cas_cls_generic_dtr },
|
||||||
|
{ "file_name_prefix", _cas_cls_file_name_prefix_test, _cas_cls_string_ctr,
|
||||||
|
_cas_cls_generic_dtr },
|
||||||
{ "lba", _cas_cls_lba_test, _cas_cls_numeric_ctr, _cas_cls_generic_dtr },
|
{ "lba", _cas_cls_lba_test, _cas_cls_numeric_ctr, _cas_cls_generic_dtr },
|
||||||
{ "pid", _cas_cls_pid_test, _cas_cls_numeric_ctr, _cas_cls_generic_dtr },
|
{ "pid", _cas_cls_pid_test, _cas_cls_numeric_ctr, _cas_cls_generic_dtr },
|
||||||
{ "process_name", _cas_cls_process_name_test, _cas_cls_string_ctr,
|
{ "process_name", _cas_cls_process_name_test, _cas_cls_string_ctr,
|
||||||
|
@ -124,6 +124,9 @@ struct cas_cls_numeric {
|
|||||||
struct cas_cls_string {
|
struct cas_cls_string {
|
||||||
/* String specifier*/
|
/* String specifier*/
|
||||||
char string[MAX_STRING_SPECIFIER_LEN];
|
char string[MAX_STRING_SPECIFIER_LEN];
|
||||||
|
|
||||||
|
/* String length */
|
||||||
|
uint32_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Directory condition context */
|
/* Directory condition context */
|
||||||
|
@ -99,8 +99,9 @@ class IoClass:
|
|||||||
return random_list
|
return random_list
|
||||||
|
|
||||||
def set_random_rule(self):
|
def set_random_rule(self):
|
||||||
rules = ["metadata", "direct", "file_size", "directory", "io_class", "extension", "lba",
|
rules = ["metadata", "direct", "file_size", "directory", "io_class",
|
||||||
"pid", "process_name", "file_offset", "request_size"]
|
"extension", "file_name_prefix", "lba", "pid", "process_name",
|
||||||
|
"file_offset", "request_size"]
|
||||||
if os_utils.get_kernel_version() >= version.Version("4.13"):
|
if os_utils.get_kernel_version() >= version.Version("4.13"):
|
||||||
rules.append("wlth")
|
rules.append("wlth")
|
||||||
|
|
||||||
@ -117,7 +118,7 @@ class IoClass:
|
|||||||
rule += f":{Operator(random.randrange(len(Operator))).name}:{random.randrange(1000000)}"
|
rule += f":{Operator(random.randrange(len(Operator))).name}:{random.randrange(1000000)}"
|
||||||
elif rule == "io_class":
|
elif rule == "io_class":
|
||||||
rule += f":{random.randrange(MAX_IO_CLASS_PRIORITY + 1)}"
|
rule += f":{random.randrange(MAX_IO_CLASS_PRIORITY + 1)}"
|
||||||
elif rule in ["extension", "process_name"]:
|
elif rule in ["extension", "process_name", "file_name_prefix"]:
|
||||||
rule += f":{random_string(random.randint(1, 10))}"
|
rule += f":{random_string(random.randint(1, 10))}"
|
||||||
if random.randrange(2):
|
if random.randrange(2):
|
||||||
rule += "&done"
|
rule += "&done"
|
||||||
|
@ -77,6 +77,84 @@ def test_ioclass_file_extension():
|
|||||||
assert stats["dirty"].get_value(Unit.Blocks4096) == 0
|
assert stats["dirty"].get_value(Unit.Blocks4096) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
|
||||||
|
@pytest.mark.require_disk("core", DiskTypeLowerThan("cache"))
|
||||||
|
def test_ioclass_file_name_prefix():
|
||||||
|
cache, core = prepare()
|
||||||
|
ioclass_id = 1
|
||||||
|
cached_files = ["test", "test.txt", "test1", "test1.txt"]
|
||||||
|
not_cached_files = ["file1", "file2", "file4", "file5", "tes"]
|
||||||
|
dd_size = Size(4, Unit.KibiByte)
|
||||||
|
dd_count = 10
|
||||||
|
|
||||||
|
ioclass_config.remove_ioclass_config()
|
||||||
|
ioclass_config.create_ioclass_config(False)
|
||||||
|
|
||||||
|
# Avoid caching anything else than files with specified prefix
|
||||||
|
ioclass_config.add_ioclass(
|
||||||
|
ioclass_id=0,
|
||||||
|
eviction_priority=255,
|
||||||
|
allocation=False,
|
||||||
|
rule=f"unclassified",
|
||||||
|
ioclass_config_path=ioclass_config_path,
|
||||||
|
)
|
||||||
|
# Enables file with specified prefix to be cached
|
||||||
|
ioclass_config.add_ioclass(
|
||||||
|
ioclass_id=ioclass_id,
|
||||||
|
eviction_priority=1,
|
||||||
|
allocation=True,
|
||||||
|
rule=f"file_name_prefix:test&done",
|
||||||
|
ioclass_config_path=ioclass_config_path,
|
||||||
|
)
|
||||||
|
casadm.load_io_classes(cache_id=cache.cache_id, file=ioclass_config_path)
|
||||||
|
|
||||||
|
TestRun.LOGGER.info(
|
||||||
|
f"Preparing filesystem and mounting {core.system_path} at {mountpoint}"
|
||||||
|
)
|
||||||
|
|
||||||
|
previous_occupancy = cache.get_occupancy()
|
||||||
|
|
||||||
|
core.create_filesystem(Filesystem.ext3)
|
||||||
|
core.mount(mountpoint)
|
||||||
|
|
||||||
|
assert previous_occupancy.get_value() <= cache.get_occupancy().get_value()
|
||||||
|
|
||||||
|
# Filesystem creation caused metadata IO which is not supposed
|
||||||
|
# to be cached
|
||||||
|
|
||||||
|
# Check if files with proper prefix are cached
|
||||||
|
TestRun.LOGGER.info(f"Writing files which are supposed to be cached.")
|
||||||
|
for f in cached_files:
|
||||||
|
dd = (
|
||||||
|
Dd()
|
||||||
|
.input("/dev/zero")
|
||||||
|
.output(f"{mountpoint}/{f}")
|
||||||
|
.count(dd_count)
|
||||||
|
.block_size(dd_size)
|
||||||
|
)
|
||||||
|
dd.run()
|
||||||
|
sync()
|
||||||
|
current_occupancy = cache.get_occupancy()
|
||||||
|
assert current_occupancy == previous_occupancy
|
||||||
|
previous_occupancy = current_occupancy
|
||||||
|
|
||||||
|
cache.flush_cache()
|
||||||
|
|
||||||
|
# Check if file with improper extension is not cached
|
||||||
|
TestRun.LOGGER.info(f"Writing files which are not supposed to be cached.")
|
||||||
|
for f in not_cached_files:
|
||||||
|
dd = (
|
||||||
|
Dd()
|
||||||
|
.input("/dev/zero")
|
||||||
|
.output(f"{mountpoint}/{f}")
|
||||||
|
.count(dd_count)
|
||||||
|
.block_size(dd_size)
|
||||||
|
)
|
||||||
|
dd.run()
|
||||||
|
sync()
|
||||||
|
current_occupancy = cache.get_occupancy()
|
||||||
|
assert current_occupancy != previous_occupancy
|
||||||
|
|
||||||
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
|
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
|
||||||
@pytest.mark.require_disk("core", DiskTypeLowerThan("cache"))
|
@pytest.mark.require_disk("core", DiskTypeLowerThan("cache"))
|
||||||
def test_ioclass_file_extension_preexisting_filesystem():
|
def test_ioclass_file_extension_preexisting_filesystem():
|
||||||
|
Loading…
Reference in New Issue
Block a user