From nobody Sun Feb 8 05:24:02 2026 Received: from mail-yx1-f47.google.com (mail-yx1-f47.google.com [74.125.224.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3505842981F for ; Fri, 6 Feb 2026 19:13:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405190; cv=none; b=u8FTMA/CvJHDBzu+DYOxuR0Ql0LAUXN/DaIXUo1venx7dBevD902Q0ESFLT8LYj0cxHnswCBHHUIGUq65TTYq186krHrpNULBVsfSnlZKzgP3upQvL6WX9stMdt/04+WbSViVyqsNMaoaS1n7FKzrEEN02v71o0gqp8tp7i673s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405190; c=relaxed/simple; bh=h9Tf2g6p95uHGjNW/hGwPXe+6bpAWGHAV9ausLLvgVA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=KE8AMfL9vDTINt1UCr0sl444njdHYG43jNlPPCJuMagTroE8XVAG0X3Xpwcr3CE44tt/bqJxG93IaISMrdGIommSO/5DhZTdn2867FwQk+SPki4X93r+c65kXI5A+vhBUG3Uwp5JZ15cKGzkUddIYN0lC3fYmPsd6KaW4ormDcs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b=krzW3a93; arc=none smtp.client-ip=74.125.224.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b="krzW3a93" Received: by mail-yx1-f47.google.com with SMTP id 956f58d0204a3-649f2d9fe48so1104214d50.2 for ; Fri, 06 Feb 2026 11:13:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20230601.gappssmtp.com; s=20230601; t=1770405189; x=1771009989; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=kl58u+sFBQ4YmsvUDIxZwjfmqlOJxFYb10cvJ3X1hxk=; b=krzW3a93bA4TERNeBEvT0Eq8aUwXLNd2FYaUicXq0ldRYWgAw2VKc+XFjTUBuA+k6D TcjZ2vNFYYwhvhueF3jowrJzO2Ol0ZYU2MtlzaAM62Um53WNhY82j2jlSPxBnQSmFW4Y ytRltH2A9kmE5d0FcFwD2QgEoiMparpNNzM0V0BbP2rLYBS6VX45E6YcQ6499SvF7QaG jwKfDi1lgM9kWsn0fQaF7iACLd+tagLu3pkDrq7JmKfsDAFMJWFTGTpqoM68e9H2o8bN 91RaxDJ0JuqHklmLQLJQheDon3hUIz8LzBsfPyCZ50NEd+VwpHWlZgzBn9USD4/Jm7sY KzoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770405189; x=1771009989; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=kl58u+sFBQ4YmsvUDIxZwjfmqlOJxFYb10cvJ3X1hxk=; b=LjQF4n81ijuvxRC8gaKsVi7pJQeGPBDXSmA85Dp6YPyMJj1aiLBrBa7bH+mja8umdF mrjnyolXWEsKvqTgMCxLq6H/f7UDCF02eBRRirhaNlP+NbH8/JcZ0xDPDzoPk/kZzFns voS032s9Z5PWUmo29v/sp/PLR8GuxJJz9jJ0CKZ+7gnW3dCA69tZMqe/I4kYb6pK3o7j rSGFarQKilspX548psBkUvDQikOFHoQoi19Ir+5cBvy3fEbwSAcwmnmFNHNvj1PWEQ6/ Rc6fKaR6GJglM4NCdCmOdJlS+k9lDViXPrmA18U+EqAGx5JfY0U+HLcg8lgaP29FF38s rYsA== X-Forwarded-Encrypted: i=1; AJvYcCXM8Fn9Krlwk2Pu2ROBnsfMebU+d/nkHUbXtANiM1qyVxnMbeGTkSORmnEaQWDc5n5c0/EmcPdizpWyRG8=@vger.kernel.org X-Gm-Message-State: AOJu0Yz3Tzzf9S/QJOMJAhrracAyTvTSgrhz32dzBAYwll2wMbqi8eal dALPfGANliOsAdMXBCq3z/N9QobLF3kBSO3Ji2sI/M31JyF/L/SMt7XPy45VAxDXouk= X-Gm-Gg: AZuq6aIqxAMGnvfOAh1Zh6Iyiwb5f25/K0k1QoGgHtXobgjkVYE85tM+L5C2q2TNNTS LvRkVGSnDJJM3frKUa1+36lNcOC3vvnMAWAq/gqGyGfCIl//2L52kV3PJe+C5OEWiDKyOjrgWUy g2csavQYtbNREOgScqSLL1epQsG47JfoehBuxQzxh3jINr7PDAc44J+hryBa5DZH0tzzeRVioTI /cxMGphyxPXOtjqZQmrTWsVJcM3Yqf9vyHiK+pCf4gOa7ExBv8W275YYwXrgDlkeyWKx/1crI7q NDD01r07fcB2Gmoz6fatAIutDCvU1+z3woMnErJifyyU6pEzlwvMjMYUM0nCPInlMWDGxvM675Z Bpli87gdg9IU4Guwflw1T/DayfFy4Ieg5yxdg2IsSOVheVvnTRptOCqQ0F5PZ4cSNSHo4f2PzGV /GAIAcAB1Hdl6NmHiuMrjBlKnlGj6RFDvYcrbl/vjA3VepxM/6neebaNT1meQqgn2MDgONW6CKj qvoNPBpaGCnHIHDzC2yI5I= X-Received: by 2002:a81:b813:0:b0:795:294c:fd3d with SMTP id 00721157ae682-7952ab55894mr57194667b3.50.1770405189073; Fri, 06 Feb 2026 11:13:09 -0800 (PST) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:9fc0:ed7d:72bd:ecd1]) by smtp.gmail.com with ESMTPSA id 00721157ae682-7952a28697fsm29051277b3.50.2026.02.06.11.13.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Feb 2026 11:13:08 -0800 (PST) From: Viacheslav Dubeyko To: linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, bpf@vger.kernel.org Cc: Slava.Dubeyko@ibm.com, slava@dubeyko.com, linux-kernel@vger.kernel.org Subject: [RFC PATCH v1 1/4] ml-lib: Introduce Machine Learning (ML) library declarations Date: Fri, 6 Feb 2026 11:11:33 -0800 Message-Id: <20260206191136.2609767-2-slava@dubeyko.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260206191136.2609767-1-slava@dubeyko.com> References: <20260206191136.2609767-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Any kernel subsystem can be extended by one or several ML model(s). ML model is represented by struct ml_lib_model that contains: (1) ML model mode, (2) ML model state, (3) pointer on parent kernel subsystem, (4) parent kernel subsystem state, (5) ML model options, (6) current dataset, (7) ML model specialized operations, (8) dataset specialized operations. Any kernel subsystem can be in several modes that define how this subsystem interacts with ML model in user-space: (1) EMERGENCY_MODE - ignore ML model and run default algorithm(s), (2) LEARNING_MODE - ML model is learning and any recommendations requires of checking and errors back-propagation, (3) COLLABORATION_MODE - ML model has good prediction but still requires correction by default algorithm(s), (4) RECOMMENDATION_MODE - ML model is capable to substitute the default algorithm(s). ML model can be: (1) created, (2) initialized, (3) started, (4) running, (5) stopped, (6) shutted down. The API of ML model includes: (1) ml_model_create() - create ML model and initialize generic field (2) ml_model_init() - execute specialized logic of ML model initialization (3) ml_model_re_init() - execute specialized logic of ML model re-init (4) ml_model_start() - start ML model activity (5) ml_model_stop() - stop ML model activity (6) ml_model_destroy() - destroy ML model and free all allocated memory (7) get_system_state() - get current state of parent kernel subsystem (8) ml_model_get_dataset() - prepare dataset for extraction by user-space a= gent (9) ml_model_discard_dataset() - discard/obsolete dataset by user-space age= nt (10) ml_model_preprocess_data() - preprocess data of current dataset (11) ml_model_publish_data() - notify user-space agent about new dataset (12) ml_model_preprocess_recommendation() - preprocess ML model recommendat= ions (13) estimate_system_state() - estimate parent kernel subsystem mode (14) apply_ml_model_recommendation() - apply ML model recommendations (15) execute_ml_model_operation() - execute logic following ML model mode (16) estimate_ml_model_efficiency() - estimate ML model efficiency (17) ml_model_error_backpropagation() - execute error backpropagation (18) correct_system_state() - correct parent kernel subsystem mode Signed-off-by: Viacheslav Dubeyko --- include/linux/ml-lib/ml_lib.h | 425 ++++++++++++++++++++++++++++++++++ 1 file changed, 425 insertions(+) create mode 100644 include/linux/ml-lib/ml_lib.h diff --git a/include/linux/ml-lib/ml_lib.h b/include/linux/ml-lib/ml_lib.h new file mode 100644 index 000000000000..001e781e0bf1 --- /dev/null +++ b/include/linux/ml-lib/ml_lib.h @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Machine Learning (ML) library + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + */ + +#ifndef _LINUX_ML_LIB_H +#define _LINUX_ML_LIB_H + +/* + * Any kernel subsystem can be in several modes + * that define how this subsystem interacts with + * ML model in user-space: + * (1) EMERGENCY_MODE - ignore ML model and run default algorithm(s). + * (2) LEARNING_MODE - ML model is learning and any recommendations + * requires of checking and errors back-propagation. + * (3) COLLABORATION_MODE - ML model has good prediction but still + * requires correction by default algorithm(s). + * (4) RECOMMENDATION_MODE - ML model is capable to substitute + * the default algorithm(s). + */ +enum ml_lib_system_mode { + ML_LIB_UNKNOWN_MODE, + ML_LIB_EMERGENCY_MODE, + ML_LIB_LEARNING_MODE, + ML_LIB_COLLABORATION_MODE, + ML_LIB_RECOMMENDATION_MODE, + ML_LIB_MODE_MAX +}; + +enum { + ML_LIB_UNKNOWN_MODEL_STATE, + ML_LIB_MODEL_CREATED, + ML_LIB_MODEL_INITIALIZED, + ML_LIB_MODEL_STARTED, + ML_LIB_MODEL_RUNNING, + ML_LIB_MODEL_STOPPED, + ML_LIB_MODEL_SHUTTING_DOWN, + ML_LIB_MODEL_STATE_MAX +}; + +struct ml_lib_model; + +#define ML_LIB_SLEEP_TIMEOUT_DEFAULT (10) + +/* + * struct ml_lib_model_options - ML model global options + * @sleep_timeout: main thread's sleep timeout + * + * These options define behavior of ML model. + * The options can be defined during init() or re-init() call. + */ +struct ml_lib_model_options { + u32 sleep_timeout; +}; + +/* + * struct ml_lib_model_run_config - ML model run config + * @sleep_timeout: main thread's sleep timeout + * + * The run config is used for correction of ML model options + * by means of start/stop methods pair. + */ +struct ml_lib_model_run_config { + u32 sleep_timeout; +}; + +/* + * struct ml_lib_subsystem - kernel subsystem object + * @type: object type + * @size: number of bytes in allocated object + * @private: private data of subsystem + */ +struct ml_lib_subsystem { + atomic_t type; + size_t size; + + void *private; +}; + +enum { + ML_LIB_UNKNOWN_SUBSYSTEM_TYPE, + ML_LIB_GENERIC_SUBSYSTEM, + ML_LIB_SPECIALIZED_SUBSYSTEM, + ML_LIB_SUBSYSTEM_TYPE_MAX +}; + +/* + * struct ml_lib_subsystem_state - shared kernel subsystem state + * @state: object state + * @size: number of bytes in allocated object + */ +struct ml_lib_subsystem_state { + atomic_t state; + size_t size; +}; + +enum { + ML_LIB_UNKNOWN_SUBSYSTEM_STATE, + ML_LIB_SUBSYSTEM_CREATED, + ML_LIB_SUBSYSTEM_INITIALIZED, + ML_LIB_SUBSYSTEM_STARTED, + ML_LIB_SUBSYSTEM_RUNNING, + ML_LIB_SUBSYSTEM_SHUTTING_DOWN, + ML_LIB_SUBSYSTEM_STOPPED, + ML_LIB_SUBSYSTEM_STATE_MAX +}; + +struct ml_lib_subsystem_state_operations { + void *(*allocate)(size_t size, gfp_t gfp); + void (*free)(struct ml_lib_subsystem_state *state); + int (*init)(struct ml_lib_subsystem_state *state); + int (*destroy)(struct ml_lib_subsystem_state *state); + int (*check_state)(struct ml_lib_subsystem_state *state); + struct ml_lib_subsystem_state * + (*snapshot_state)(struct ml_lib_subsystem *object); + int (*estimate_system_state)(struct ml_lib_model *ml_model); + int (*correct_system_state)(struct ml_lib_model *ml_model); +}; + +/* + * struct ml_lib_dataset - exported subsystem's dataset + * @type: object type + * @state: object state + * @allocated_size: number of bytes in allocated object + * @portion_offset: portion offset in the data stream + * @portion_size: extracted portion size + */ +struct ml_lib_dataset { + atomic_t type; + atomic_t state; + size_t allocated_size; + + u64 portion_offset; + u32 portion_size; +}; + +enum { + ML_LIB_UNKNOWN_DATASET_TYPE, + ML_LIB_EMPTY_DATASET, + ML_LIB_VALUE_DATASET, + ML_LIB_STRUCTURE_DATASET, + ML_LIB_MEMORY_STREAM_DATASET, + ML_LIB_DATASET_TYPE_MAX +}; + +enum { + ML_LIB_UNKNOWN_DATASET_STATE, + ML_LIB_DATASET_ALLOCATED, + ML_LIB_DATASET_CLEAN, + ML_LIB_DATASET_EXTRACTED_PARTIALLY, + ML_LIB_DATASET_EXTRACTED_COMPLETELY, + ML_LIB_DATASET_OBSOLETE, + ML_LIB_DATASET_EXTRACTION_FAILURE, + ML_LIB_DATASET_CORRUPTED, + ML_LIB_DATASET_STATE_MAX +}; + +struct ml_lib_dataset_operations { + void *(*allocate)(size_t size, gfp_t gfp); + void (*free)(struct ml_lib_dataset *dataset); + int (*init)(struct ml_lib_dataset *dataset); + int (*destroy)(struct ml_lib_dataset *dataset); + int (*extract)(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); + int (*preprocess_data)(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); + int (*publish_data)(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); +}; + +/* + * struct ml_lib_request_config - dataset operation configuration + * @type: object type + * @state: object state + * @size: number of bytes in allocated object + */ +struct ml_lib_request_config { + atomic_t type; + atomic_t state; + size_t size; +}; + +enum { + ML_LIB_UNKNOWN_REQUEST_CONFIG_TYPE, + ML_LIB_EMPTY_REQUEST_CONFIG, + ML_LIB_REQUEST_CONFIG_TYPE_MAX +}; + +enum { + ML_LIB_UNKNOWN_REQUEST_CONFIG_STATE, + ML_LIB_REQUEST_CONFIG_ALLOCATED, + ML_LIB_REQUEST_CONFIG_INITIALIZED, + ML_LIB_REQUEST_CONFIG_STATE_MAX +}; + +struct ml_lib_request_config_operations { + void *(*allocate)(size_t size, gfp_t gfp); + void (*free)(struct ml_lib_request_config *config); + int (*init)(struct ml_lib_request_config *config); + int (*destroy)(struct ml_lib_request_config *config); +}; + +struct ml_lib_user_space_request { +}; + +struct ml_lib_user_space_request_operations { + int (*operation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_request *request); +}; + +struct ml_lib_user_space_notification { +}; + +struct ml_lib_user_space_notification_operations { + int (*operation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_notification *notify); +}; + +struct ml_lib_user_space_recommendation { +}; + +struct ml_lib_user_space_recommendation_operations { + int (*operation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); +}; + +struct ml_lib_backpropagation_feedback { +}; + +struct ml_lib_backpropagation_operations { + int (*operation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); +}; + +/* + * struct ml_lib_model_operations - ML model operations + * @create: specialized method of ML model creation + * @init: specialized method of ML model initialization + * @re_init: specialized method of ML model re-initialization + * @start: specialized method of ML model start + * @stop: specialized method of ML model stop + * @destroy: specialized method of ML model destroy + * @get_system_state: specialized method of getting subsystem state + * @get_dataset: specialized method of getting a dataset + * @preprocess_data: specialized method of data preprocessing + * @publish_data: specialized method of sharing data with user-space + * @preprocess_recommendation: specialized method of preprocess recomendat= ions + * @estimate_system_state: specialized method of system state estimation + * @apply_recommendation: specialized method of recommendations applying + * @execute_operation: specialized method of operation execution + * @estimate_efficiency: specialized method of operation efficiency estima= tion + * @error_backpropagation: specialized method of error backpropagation + * @correct_system_state: specialized method of subsystem state correction + */ +struct ml_lib_model_operations { + int (*create)(struct ml_lib_model *ml_model); + int (*init)(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options); + int (*re_init)(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options); + int (*start)(struct ml_lib_model *ml_model, + struct ml_lib_model_run_config *config); + int (*stop)(struct ml_lib_model *ml_model); + void (*destroy)(struct ml_lib_model *ml_model); + struct ml_lib_subsystem_state * + (*get_system_state)(struct ml_lib_model *ml_model); + int (*get_dataset)(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); + int (*preprocess_data)(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); + int (*publish_data)(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset, + struct ml_lib_user_space_notification *notify); + int (*preprocess_recommendation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); + int (*estimate_system_state)(struct ml_lib_model *ml_model); + int (*apply_recommendation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); + int (*execute_operation)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request); + int (*estimate_efficiency)(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request); + int (*error_backpropagation)(struct ml_lib_model *ml_model, + struct ml_lib_backpropagation_feedback *feedback, + struct ml_lib_user_space_notification *notify); + int (*correct_system_state)(struct ml_lib_model *ml_model); +}; + +/* + * struct ml_lib_model - ML model declaration + * @mode: ML model mode (enum ml_lib_system_mode) + * @state: ML model state + * @subsystem_name: name of susbsystem + * @model_name: name of the ML model + * @parent: parent kernel subsystem + * @parent_state: parent kernel subsystem's state + * @options: ML model options + * @model_ops: ML model specialized operations + * @system_state_ops: subsystem state specialized operations + * @dataset_ops: dataset specialized operations + * @request_config_ops: specialized dataset configuration operations + * @kobj: /sys/// ML model object + * @kobj_unregister: completion state for kernel object + */ +struct ml_lib_model { + atomic_t mode; + atomic_t state; + const char *subsystem_name; + const char *model_name; + + struct ml_lib_subsystem *parent; + + spinlock_t parent_state_lock; + struct ml_lib_subsystem_state * __rcu parent_state; + + spinlock_t options_lock; + struct ml_lib_model_options * __rcu options; + + spinlock_t dataset_lock; + struct ml_lib_dataset * __rcu dataset; + + struct ml_lib_model_operations *model_ops; + struct ml_lib_subsystem_state_operations *system_state_ops; + struct ml_lib_dataset_operations *dataset_ops; + struct ml_lib_request_config_operations *request_config_ops; + + /* /sys/// */ + struct kobject kobj; + struct completion kobj_unregister; +}; + +/* ML library API */ + +void *allocate_ml_model(size_t size, gfp_t gfp); +void free_ml_model(struct ml_lib_model *ml_model); +void *allocate_subsystem_object(size_t size, gfp_t gfp); +void free_subsystem_object(struct ml_lib_subsystem *object); +void *allocate_ml_model_options(size_t size, gfp_t gfp); +void free_ml_model_options(struct ml_lib_model_options *options); +void *allocate_subsystem_state(size_t size, gfp_t gfp); +void free_subsystem_state(struct ml_lib_subsystem_state *state); +void *allocate_dataset(size_t size, gfp_t gfp); +void free_dataset(struct ml_lib_dataset *dataset); +void *allocate_request_config(size_t size, gfp_t gfp); +void free_request_config(struct ml_lib_request_config *config); + +int ml_model_create(struct ml_lib_model *ml_model, + const char *subsystem_name, + const char *model_name, + struct kobject *subsystem_kobj); +int ml_model_init(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options); +int ml_model_re_init(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options); +int ml_model_start(struct ml_lib_model *ml_model, + struct ml_lib_model_run_config *config); +int ml_model_stop(struct ml_lib_model *ml_model); +void ml_model_destroy(struct ml_lib_model *ml_model); +struct ml_lib_subsystem_state *get_system_state(struct ml_lib_model *ml_mo= del); +int ml_model_get_dataset(struct ml_lib_model *ml_model, + struct ml_lib_request_config *config, + struct ml_lib_user_space_request *request); +int ml_model_discard_dataset(struct ml_lib_model *ml_model); +int ml_model_preprocess_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); +int ml_model_publish_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset, + struct ml_lib_user_space_notification *notify); +int ml_model_preprocess_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); +int estimate_system_state(struct ml_lib_model *ml_model); +int apply_ml_model_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); +int execute_ml_model_operation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request); +int estimate_ml_model_efficiency(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request); +int ml_model_error_backpropagation(struct ml_lib_model *ml_model, + struct ml_lib_backpropagation_feedback *feedback, + struct ml_lib_user_space_notification *notify); +int correct_system_state(struct ml_lib_model *ml_model); + +/* Generic implementation of ML model's methods */ + +int generic_create_ml_model(struct ml_lib_model *ml_model); +int generic_init_ml_model(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options); +int generic_re_init_ml_model(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options); +int generic_start_ml_model(struct ml_lib_model *ml_model, + struct ml_lib_model_run_config *config); +int generic_stop_ml_model(struct ml_lib_model *ml_model); +void generic_destroy_ml_model(struct ml_lib_model *ml_model); +struct ml_lib_subsystem_state * +generic_get_system_state(struct ml_lib_model *ml_model); +int generic_get_dataset(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); +int generic_preprocess_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); +int generic_publish_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset, + struct ml_lib_user_space_notification *notify); +int generic_preprocess_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); +int generic_estimate_system_state(struct ml_lib_model *ml_model); +int generic_apply_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint); +int generic_execute_operation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request); +int generic_estimate_efficiency(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request); +int generic_error_backpropagation(struct ml_lib_model *ml_model, + struct ml_lib_backpropagation_feedback *feedback, + struct ml_lib_user_space_notification *notify); +int generic_correct_system_state(struct ml_lib_model *ml_model); + +#endif /* _LINUX_ML_LIB_H */ --=20 2.34.1 From nobody Sun Feb 8 05:24:02 2026 Received: from mail-yw1-f179.google.com (mail-yw1-f179.google.com [209.85.128.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AAE4742B724 for ; Fri, 6 Feb 2026 19:13:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405191; cv=none; b=Ll1/tuQYbUzj4rGhwB2K2MJVcWs2jfLLDTn4k6ONioaJOM5LqES9na43+voanoPAodfC7ayA+YgAqJ2i7o7lrchG6BjrbV3wTkoNlH6m7SfrChiVTcUTe0gpR81/KIwYh/6OaVDbZCAof/sK9bPnvIE9nylmdrbpsfFAvnS1Ks0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405191; c=relaxed/simple; bh=uzb0Wmip9GI4B1gGq8HYrnW2SoCSKaczLTjwlI4YvRs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YREXrdEkXqQytr3HNNSkyrHHpY5b9VuzGLENoSfFiZ7GPCErb0WTeNNLDcRu5I0kohwcsfWjmyVlBtmesgUWj36dCvktUzOi3DAH462Aq447uwcni5m5aegO88G7Yp+sJqr6xDQk048JhHECEVBU0hwgywn4fPOeGRZ4z4GSYkw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b=sdYCdS6y; arc=none smtp.client-ip=209.85.128.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b="sdYCdS6y" Received: by mail-yw1-f179.google.com with SMTP id 00721157ae682-79427f739b0so27807727b3.3 for ; Fri, 06 Feb 2026 11:13:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20230601.gappssmtp.com; s=20230601; t=1770405191; x=1771009991; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=eb1OdGpCtAwc8beSe19LPmFPW+UDoGnStsGyK3KBbAk=; b=sdYCdS6yPNJcxM9SkyHcwMajxeK1f1j0kNTWs4p52la1wEkLGwnK724yqo2OAuqBcJ Opa2pNvGV4tVB1xbqmlMR4QVnMO26AjHNYWxgNsLY5MX5T3l9Pvbde5U1wp9kexriSRU x9wRZOsnxjoS7NUkqpkabil6lcI4B+i6SKNpoqwmHAIcyQwThPHmq3Acs5ds3DrM03Ee B16t9PRvU2LLirh5cu901TXbS0ESqn65WpDnCQWkdbjBgj7DFHgTIK3p8t6hmXVo1kEM znBkhBfazcwQbmMsQT0RVH3Bow8wbRQe08jBmtnjea9PVz54mZVGnsBas09JNLpuv/69 gsRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770405191; x=1771009991; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=eb1OdGpCtAwc8beSe19LPmFPW+UDoGnStsGyK3KBbAk=; b=cRLslW7ZujrnERBysNIxUbk+ANe/uZ9Ofswuri02o7A3AiVSTrdZEyQAsd7EBlldyl mP1KVNNH0pCv5bWXNuDSTAyow6BIB3X7p5lCre4iWHTgdJG0MSwiLCDlEXbaWzsWVjkB 5DQsp3EoGoCLKI932qegSCH7sBjo5OL6QhplqeAPAbh1Wr4a4gVEyytgAVoiSzujCx5w CrqqN8o+vszOcDTyt38n2expN2YdMQgyZsf3Msb7Cb/kUBCAZ6a8eTSWldeh4+pkcbe6 IgGYdnECLMnSkgjRg71ZcYhYZtElHHtHcCWnLtUDsJR/d384w09K61lXsOaOe0KERPpD M6Jg== X-Forwarded-Encrypted: i=1; AJvYcCUdfegczQBXoW7jKSaj0bVcjE1wV++VtZAgo2fHZnwG4L1y7e7IS8l5ITv5CeOYsbm9p/E72jkOdTGv8cg=@vger.kernel.org X-Gm-Message-State: AOJu0YyZeTqfDWZZ8isUpLPfwXteARygfoLlQdTECWd/tzt+JyUXGsEq Cw+tU2LVp4w/zRTz3aSGshzOjD77wRfVylO5eKWzIR/CFMFJeO6hJon7zhAnUGAyMCk= X-Gm-Gg: AZuq6aKVT/XT5JhwsHZjCm6IeYqR7q6DpjEbkzUzwXfsXGFd0Bm05G0MmSa9krw5eO0 0pMO0a4PRYqZ7Oy3K80HCNuxA6DkkO+HRTobwyWG9E52QtqW6SzSuqvVQZY582Bcg1UKfwQSFTG 5kYDpY4W6sPJsAOmMvjINjEQ/kLcXKA1hJ02NLf88+NoFYUB/hszV+a1YhNBlbr8YjlKMNkOKfD MTASrYJMRBFOPyB6vwPez/0cO5ccAl2ycFqK9Jhx/QQbX9Hr/5M8xrkPZbTiwlUJm7gDHJ0GvfN k10e6ElD1gMlWp1RspJKzooD2BJ/un2TDsqewIP3Se7uRltOtANcAMiKu7JZV3gMcSPUS+fVBh7 YxIYGB/YaBQSodjYvcwFp6B3GiydJtQK7Z2i8bhsuPbYokS4iIA0txgw6gBQeAffA1KOQTPRcLj 38yj2YqJ37zKNDOfj4oa/ZRuKV3AVnt8ClcjKiGHRgn/iiKjavhI5fd6PMwG8j/BXblsZErXz0M hOI/gD4aKCF X-Received: by 2002:a05:690c:6b09:b0:795:294c:fd30 with SMTP id 00721157ae682-7952ab3fc08mr29459087b3.39.1770405190554; Fri, 06 Feb 2026 11:13:10 -0800 (PST) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:9fc0:ed7d:72bd:ecd1]) by smtp.gmail.com with ESMTPSA id 00721157ae682-7952a28697fsm29051277b3.50.2026.02.06.11.13.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Feb 2026 11:13:09 -0800 (PST) From: Viacheslav Dubeyko To: linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, bpf@vger.kernel.org Cc: Slava.Dubeyko@ibm.com, slava@dubeyko.com, linux-kernel@vger.kernel.org Subject: [RFC PATCH v1 2/4] ml-lib: Implement PoC of Machine Learning (ML) library functionality Date: Fri, 6 Feb 2026 11:11:34 -0800 Message-Id: <20260206191136.2609767-3-slava@dubeyko.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260206191136.2609767-1-slava@dubeyko.com> References: <20260206191136.2609767-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ML model can be represented by process/thread running in user-space. Particular kernel subsystem needs to implement ML model proxy on kernel-space side. The process of loading kernel subsystem creates and intializes the ML model proxy, create sysfs entries, and character device, for example. The sysfs entries and character device create the mechanism of interaction and collaboration of kernel subsystem and ML model in user-space. The simplest model of collaboration could include such steps: (1) user-space process/thread (ML model) sends START command to kernel subsystem through sysfs control entry; (2) user-space process/thread (ML model) requests to prepare a dataset by means of PREPARE_DATASET command through sysfs control entry; (3) user-space process/thread (ML model) extracts the dataset by means of reading data from character device; (4) dataset can be marked as obsolete after extraction by means of DISCARD_DATASET command through sysfs control entry and new dataset can be requested and extracted; (5) extracted data can be used as training data by ML model on user-space side; (6) ML model can execute the inference after some number of training cycles and to elaborate some recommendations or optimized logic for kernel subsystem; (7) ML model's recommendations can be written into character device, for example, by user-space process/thread and kernel subsystem can use this recommendations for optimization or changing the logic; (8) based on kernel subsystem's mode, recommendations can be completely ignored, partially applied, tested, or used instead of default configuration/logic; (9) every time efficiency of applied recommendations or logic needs to be estimated; (10) if ML model recommendations degrade efficiency of kernel subsystem, then error backpropagation needs to be used for ML model correction on user-space side. Signed-off-by: Viacheslav Dubeyko --- lib/Kconfig | 6 + lib/Makefile | 2 + lib/ml-lib/Kconfig | 18 + lib/ml-lib/Makefile | 7 + lib/ml-lib/ml_lib_main.c | 758 +++++++++++++++++++++++++++++++++++++++ lib/ml-lib/sysfs.c | 187 ++++++++++ lib/ml-lib/sysfs.h | 17 + 7 files changed, 995 insertions(+) create mode 100644 lib/ml-lib/Kconfig create mode 100644 lib/ml-lib/Makefile create mode 100644 lib/ml-lib/ml_lib_main.c create mode 100644 lib/ml-lib/sysfs.c create mode 100644 lib/ml-lib/sysfs.h diff --git a/lib/Kconfig b/lib/Kconfig index 2923924bea78..2d56977c0638 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -604,6 +604,12 @@ config LWQ_TEST help Run boot-time test of light-weight queuing. =20 +# +# Machine Learning (ML) library configuration +# + +source "lib/ml-lib/Kconfig" + endmenu =20 config GENERIC_IOREMAP diff --git a/lib/Makefile b/lib/Makefile index aaf677cf4527..154e7fd220ab 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -332,3 +332,5 @@ obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) +=3D devmem= _is_allowed.o obj-$(CONFIG_FIRMWARE_TABLE) +=3D fw_table.o =20 subdir-$(CONFIG_FORTIFY_SOURCE) +=3D test_fortify + +obj-$(CONFIG_ML_LIB) +=3D ml-lib/ diff --git a/lib/ml-lib/Kconfig b/lib/ml-lib/Kconfig new file mode 100644 index 000000000000..d2f2ea40a833 --- /dev/null +++ b/lib/ml-lib/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# +# Machine Learning (ML) library configuration +# + +config ML_LIB + tristate "ML library support" + help + Machine Learning (ML) library has goal to provide + the interaction and communication of ML models in + user-space with kernel subsystems. It implements + the basic code primitives that builds the way of + ML models integration into Linux kernel functionality. + + If unsure, say N. + +source "lib/ml-lib/test_driver/Kconfig" diff --git a/lib/ml-lib/Makefile b/lib/ml-lib/Makefile new file mode 100644 index 000000000000..b1103ab3e1c8 --- /dev/null +++ b/lib/ml-lib/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_ML_LIB) +=3D ml_lib.o + +ml_lib-y :=3D sysfs.o ml_lib_main.o + +obj-$(CONFIG_ML_LIB_TEST_DRIVER) +=3D test_driver/ diff --git a/lib/ml-lib/ml_lib_main.c b/lib/ml-lib/ml_lib_main.c new file mode 100644 index 000000000000..ef336d6a83fb --- /dev/null +++ b/lib/ml-lib/ml_lib_main.c @@ -0,0 +1,758 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Machine Learning (ML) library + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + */ + +#include +#include + +#include + +#include "sysfs.h" + +#define UNKNOWN_SUBSYSTEM_NAME "unknown_subsystem" +#define UNKNOWN_ML_MODEL_NAME "unknown_model" + +/* + * default_ml_model_ops - default ML model operations + */ +struct ml_lib_model_operations default_ml_model_ops =3D { + .create =3D generic_create_ml_model, + .init =3D generic_init_ml_model, + .re_init =3D generic_re_init_ml_model, + .start =3D generic_start_ml_model, + .stop =3D generic_stop_ml_model, + .destroy =3D generic_destroy_ml_model, + .get_system_state =3D generic_get_system_state, + .get_dataset =3D generic_get_dataset, + .preprocess_data =3D generic_preprocess_data, + .publish_data =3D generic_publish_data, + .preprocess_recommendation =3D generic_preprocess_recommendation, + .estimate_system_state =3D generic_estimate_system_state, + .apply_recommendation =3D generic_apply_recommendation, + .execute_operation =3D generic_execute_operation, + .estimate_efficiency =3D generic_estimate_efficiency, + .error_backpropagation =3D generic_error_backpropagation, + .correct_system_state =3D generic_correct_system_state, +}; + +/*************************************************************************= ***** + * ML library API = * + *************************************************************************= *****/ + +void *allocate_ml_model(size_t size, gfp_t gfp) +{ + struct ml_lib_model *ml_model; + + if (size < sizeof(struct ml_lib_model)) + return ERR_PTR(-EINVAL); + + ml_model =3D kzalloc(size, gfp); + if (unlikely(!ml_model)) + return ERR_PTR(-ENOMEM); + + atomic_set(&ml_model->mode, ML_LIB_UNKNOWN_MODE); + atomic_set(&ml_model->state, ML_LIB_UNKNOWN_MODEL_STATE); + ml_model->model_ops =3D &default_ml_model_ops; + + return (void *)ml_model; +} +EXPORT_SYMBOL(allocate_ml_model); + +void free_ml_model(struct ml_lib_model *ml_model) +{ + if (!ml_model) + return; + + free_subsystem_object(ml_model->parent); + kfree(ml_model); +} +EXPORT_SYMBOL(free_ml_model); + +void *allocate_subsystem_object(size_t size, gfp_t gfp) +{ + struct ml_lib_subsystem *subsystem; + + if (size < sizeof(struct ml_lib_subsystem)) + return ERR_PTR(-EINVAL); + + subsystem =3D kzalloc(size, gfp); + if (unlikely(!subsystem)) + return ERR_PTR(-ENOMEM); + + subsystem->size =3D size; + atomic_set(&subsystem->type, ML_LIB_UNKNOWN_SUBSYSTEM_TYPE); + + return (void *)subsystem; +} +EXPORT_SYMBOL(allocate_subsystem_object); + +void free_subsystem_object(struct ml_lib_subsystem *object) +{ + if (!object) + return; + + kfree(object); +} +EXPORT_SYMBOL(free_subsystem_object); + +void *allocate_ml_model_options(size_t size, gfp_t gfp) +{ + struct ml_lib_model_options *options; + + if (size < sizeof(struct ml_lib_model_options)) + return ERR_PTR(-EINVAL); + + options =3D kzalloc(size, gfp); + if (unlikely(!options)) + return ERR_PTR(-ENOMEM); + + options->sleep_timeout =3D U32_MAX; + + return (void *)options; +} +EXPORT_SYMBOL(allocate_ml_model_options); + +void free_ml_model_options(struct ml_lib_model_options *options) +{ + if (!options) + return; + + kfree(options); +} +EXPORT_SYMBOL(free_ml_model_options); + +void *allocate_subsystem_state(size_t size, gfp_t gfp) +{ + return NULL; +} +EXPORT_SYMBOL(allocate_subsystem_state); + +void free_subsystem_state(struct ml_lib_subsystem_state *state) +{ +} +EXPORT_SYMBOL(free_subsystem_state); + +void *allocate_dataset(size_t size, gfp_t gfp) +{ + struct ml_lib_dataset *dataset; + + if (size < sizeof(struct ml_lib_dataset)) + return ERR_PTR(-EINVAL); + + dataset =3D kzalloc(size, gfp); + if (unlikely(!dataset)) + return ERR_PTR(-ENOMEM); + + atomic_set(&dataset->type, ML_LIB_UNKNOWN_DATASET_TYPE); + atomic_set(&dataset->state, ML_LIB_UNKNOWN_DATASET_STATE); + + return (void *)dataset; +} +EXPORT_SYMBOL(allocate_dataset); + +void free_dataset(struct ml_lib_dataset *dataset) +{ + if (!dataset) + return; + + kfree(dataset); +} +EXPORT_SYMBOL(free_dataset); + +void *allocate_request_config(size_t size, gfp_t gfp) +{ + return NULL; +} +EXPORT_SYMBOL(allocate_request_config); + +void free_request_config(struct ml_lib_request_config *config) +{ +} +EXPORT_SYMBOL(free_request_config); + +int ml_model_create(struct ml_lib_model *ml_model, + const char *subsystem_name, + const char *model_name, + struct kobject *subsystem_kobj) +{ + struct kobject *parent =3D NULL; + size_t size; + int err =3D 0; + + if (!ml_model) + return -EINVAL; + + if (!subsystem_name) + ml_model->subsystem_name =3D UNKNOWN_SUBSYSTEM_NAME; + else + ml_model->subsystem_name =3D subsystem_name; + + if (!model_name) + ml_model->model_name =3D UNKNOWN_ML_MODEL_NAME; + else + ml_model->model_name =3D model_name; + + if (!subsystem_kobj) + parent =3D kernel_kobj; + else + parent =3D subsystem_kobj; + + spin_lock_init(&ml_model->parent_state_lock); + spin_lock_init(&ml_model->options_lock); + spin_lock_init(&ml_model->dataset_lock); + + err =3D ml_model_create_sysfs_group(ml_model, parent); + if (err) { + pr_err("ml_lib: failed to create sysfs group: err %d\n", err); + goto finish_model_create; + } + + if (!ml_model->model_ops || !ml_model->model_ops->create) { + size =3D sizeof(struct ml_lib_subsystem); + + ml_model->parent =3D allocate_subsystem_object(size, GFP_KERNEL); + if (unlikely(!ml_model->parent)) { + err =3D -ENOMEM; + goto remove_sysfs_group; + } + + atomic_set(&ml_model->parent->type, ML_LIB_GENERIC_SUBSYSTEM); + } else { + err =3D ml_model->model_ops->create(ml_model); + if (unlikely(err)) { + pr_err("ml_lib: failed to create ML model: err %d\n", + err); + goto remove_sysfs_group; + } + } + + atomic_set(&ml_model->state, ML_LIB_MODEL_CREATED); + + return 0; + +remove_sysfs_group: + ml_model_delete_sysfs_group(ml_model); + +finish_model_create: + return err; +} +EXPORT_SYMBOL(ml_model_create); + +int ml_model_init(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options) +{ + struct ml_lib_model_options *old_options; + int err =3D 0; + + if (!ml_model) + return -EINVAL; + + if (!ml_model->model_ops || !ml_model->model_ops->init) + options->sleep_timeout =3D ML_LIB_SLEEP_TIMEOUT_DEFAULT; + else { + err =3D ml_model->model_ops->init(ml_model, options); + if (unlikely(err)) { + pr_err("ml_lib: failed to init ML model: err %d\n", + err); + goto finish_model_init; + } + } + + spin_lock(&ml_model->options_lock); + old_options =3D rcu_dereference_protected(ml_model->options, + lockdep_is_held(&ml_model->options_lock)); + rcu_assign_pointer(ml_model->options, options); + spin_unlock(&ml_model->options_lock); + synchronize_rcu(); + free_ml_model_options(old_options); + + atomic_set(&ml_model->state, ML_LIB_MODEL_INITIALIZED); + +finish_model_init: + return err; +} +EXPORT_SYMBOL(ml_model_init); + +int ml_model_re_init(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options) +{ + struct ml_lib_model_options *old_options; + + if (!ml_model) + return -EINVAL; + + spin_lock(&ml_model->options_lock); + old_options =3D rcu_dereference_protected(ml_model->options, + lockdep_is_held(&ml_model->options_lock)); + rcu_assign_pointer(ml_model->options, options); + spin_unlock(&ml_model->options_lock); + synchronize_rcu(); + free_ml_model_options(old_options); + + return 0; +} +EXPORT_SYMBOL(ml_model_re_init); + +int ml_model_start(struct ml_lib_model *ml_model, + struct ml_lib_model_run_config *config) +{ + if (!ml_model) + return -EINVAL; + + /* TODO: implement ML model start logic*/ + atomic_set(&ml_model->state, ML_LIB_MODEL_STARTED); + pr_err("ml_lib: TODO: implement start ML model\n"); + return 0; +} +EXPORT_SYMBOL(ml_model_start); + +int ml_model_stop(struct ml_lib_model *ml_model) +{ + if (!ml_model) + return -EINVAL; + + /* TODO: implement ML model stop logic*/ + atomic_set(&ml_model->state, ML_LIB_MODEL_STOPPED); + pr_err("ml_lib: TODO: implement stop ML model\n"); + return 0; +} +EXPORT_SYMBOL(ml_model_stop); + +void ml_model_destroy(struct ml_lib_model *ml_model) +{ + struct ml_lib_model_options *old_options; + struct ml_lib_dataset *old_dataset; + + if (!ml_model) + return; + + atomic_set(&ml_model->state, ML_LIB_MODEL_SHUTTING_DOWN); + + ml_model_delete_sysfs_group(ml_model); + + spin_lock(&ml_model->options_lock); + old_options =3D rcu_dereference_protected(ml_model->options, + lockdep_is_held(&ml_model->options_lock)); + rcu_assign_pointer(ml_model->options, NULL); + spin_unlock(&ml_model->options_lock); + synchronize_rcu(); + free_ml_model_options(old_options); + + spin_lock(&ml_model->dataset_lock); + old_dataset =3D rcu_dereference_protected(ml_model->dataset, + lockdep_is_held(&ml_model->dataset_lock)); + rcu_assign_pointer(ml_model->dataset, NULL); + spin_unlock(&ml_model->dataset_lock); + synchronize_rcu(); + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->destroy) { + /* + * Do nothing + */ + } else + ml_model->dataset_ops->destroy(old_dataset); + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->free) + free_dataset(old_dataset); + else + ml_model->dataset_ops->free(old_dataset); + + if (!ml_model->model_ops || !ml_model->model_ops->destroy) { + atomic_set(&ml_model->parent->type, + ML_LIB_UNKNOWN_SUBSYSTEM_TYPE); + } else + ml_model->model_ops->destroy(ml_model); + + atomic_set(&ml_model->state, ML_LIB_MODEL_STATE_MAX); +} +EXPORT_SYMBOL(ml_model_destroy); + +struct ml_lib_subsystem_state *get_system_state(struct ml_lib_model *ml_mo= del) +{ + return NULL; +} +EXPORT_SYMBOL(get_system_state); + +int ml_model_get_dataset(struct ml_lib_model *ml_model, + struct ml_lib_request_config *config, + struct ml_lib_user_space_request *request) +{ + struct ml_lib_dataset *old_dataset; + struct ml_lib_dataset *new_dataset; + size_t desc_size =3D sizeof(struct ml_lib_dataset); + int state; + int err =3D 0; + + if (!ml_model) + return -EINVAL; + + atomic_set(&ml_model->state, ML_LIB_MODEL_RUNNING); + + rcu_read_lock(); + old_dataset =3D rcu_dereference(ml_model->dataset); + if (old_dataset) + state =3D atomic_read(&old_dataset->state); + else + state =3D ML_LIB_UNKNOWN_DATASET_STATE; + rcu_read_unlock(); + + switch (state) { + case ML_LIB_DATASET_CLEAN: + case ML_LIB_DATASET_EXTRACTED_PARTIALLY: + case ML_LIB_DATASET_EXTRACTED_COMPLETELY: + /* nothing should be done */ + goto finish_get_dataset; + + default: + /* continue logic */ + break; + } + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->allocate) + new_dataset =3D allocate_dataset(desc_size, GFP_KERNEL); + else { + new_dataset =3D ml_model->dataset_ops->allocate(desc_size, + GFP_KERNEL); + } + + if (IS_ERR(new_dataset)) { + err =3D PTR_ERR(new_dataset); + pr_err("ml_lib: Failed to allocate dataset\n"); + return err; + } else if (!new_dataset) { + err =3D -ENOMEM; + pr_err("ml_lib: Failed to allocate dataset\n"); + return err; + } + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->init) { + /* + * Do nothing + */ + } else { + err =3D ml_model->dataset_ops->init(new_dataset); + if (err) { + pr_err("ml_lib: Failed to init dataset: err %d\n", + err); + goto fail_get_dataset; + } + } + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->extract) { + atomic_set(&new_dataset->type, ML_LIB_EMPTY_DATASET); + atomic_set(&new_dataset->state, ML_LIB_DATASET_CLEAN); + new_dataset->allocated_size =3D 0; + new_dataset->portion_offset =3D 0; + new_dataset->portion_size =3D 0; + } else { + err =3D ml_model->dataset_ops->extract(ml_model, new_dataset); + if (err) { + pr_err("ml_lib: Failed to extract dataset: err %d\n", + err); + goto fail_get_dataset; + } + } + + spin_lock(&ml_model->dataset_lock); + old_dataset =3D rcu_dereference_protected(ml_model->dataset, + lockdep_is_held(&ml_model->dataset_lock)); + rcu_assign_pointer(ml_model->dataset, new_dataset); + spin_unlock(&ml_model->dataset_lock); + synchronize_rcu(); + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->destroy) { + /* + * Do nothing + */ + } else + ml_model->dataset_ops->destroy(old_dataset); + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->free) + free_dataset(old_dataset); + else + ml_model->dataset_ops->free(old_dataset); + +finish_get_dataset: + return 0; + +fail_get_dataset: + if (!ml_model->dataset_ops || !ml_model->dataset_ops->destroy) { + /* + * Do nothing + */ + } else + ml_model->dataset_ops->destroy(new_dataset); + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->free) + free_dataset(new_dataset); + else + ml_model->dataset_ops->free(new_dataset); + + return err; +} +EXPORT_SYMBOL(ml_model_get_dataset); + +int ml_model_discard_dataset(struct ml_lib_model *ml_model) +{ + struct ml_lib_dataset *old_dataset; + struct ml_lib_dataset *new_dataset; + size_t desc_size =3D sizeof(struct ml_lib_dataset); + int err; + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->allocate) + new_dataset =3D allocate_dataset(desc_size, GFP_KERNEL); + else { + new_dataset =3D ml_model->dataset_ops->allocate(desc_size, + GFP_KERNEL); + } + + if (IS_ERR(new_dataset)) { + err =3D PTR_ERR(new_dataset); + pr_err("ml_lib: Failed to allocate dataset\n"); + return err; + } else if (!new_dataset) { + err =3D -ENOMEM; + pr_err("ml_lib: Failed to allocate dataset\n"); + return err; + } + + spin_lock(&ml_model->dataset_lock); + old_dataset =3D rcu_dereference_protected(ml_model->dataset, + lockdep_is_held(&ml_model->dataset_lock)); + if (old_dataset) { + atomic_set(&new_dataset->type, atomic_read(&old_dataset->type)); + new_dataset->allocated_size =3D old_dataset->allocated_size; + new_dataset->portion_offset =3D old_dataset->portion_offset; + new_dataset->portion_size =3D old_dataset->portion_size; + } else { + atomic_set(&new_dataset->type, ML_LIB_EMPTY_DATASET); + new_dataset->allocated_size =3D 0; + new_dataset->portion_offset =3D 0; + new_dataset->portion_size =3D 0; + } + atomic_set(&new_dataset->state, ML_LIB_DATASET_OBSOLETE); + rcu_assign_pointer(ml_model->dataset, new_dataset); + spin_unlock(&ml_model->dataset_lock); + synchronize_rcu(); + + if (!ml_model->dataset_ops || !ml_model->dataset_ops->free) + free_dataset(old_dataset); + else + ml_model->dataset_ops->free(old_dataset); + + return 0; +} +EXPORT_SYMBOL(ml_model_discard_dataset); + +int ml_model_preprocess_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(ml_model_preprocess_data); + +int ml_model_publish_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset, + struct ml_lib_user_space_notification *notify) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(ml_model_publish_data); + +int ml_model_preprocess_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(ml_model_preprocess_recommendation); + +int estimate_system_state(struct ml_lib_model *ml_model) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(estimate_system_state); + +int apply_ml_model_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(apply_ml_model_recommendation); + +int execute_ml_model_operation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(execute_ml_model_operation); + +int estimate_ml_model_efficiency(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(estimate_ml_model_efficiency); + +int ml_model_error_backpropagation(struct ml_lib_model *ml_model, + struct ml_lib_backpropagation_feedback *feedback, + struct ml_lib_user_space_notification *notify) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(ml_model_error_backpropagation); + +int correct_system_state(struct ml_lib_model *ml_model) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(correct_system_state); + +/*************************************************************************= ***** + * Generic implementation of ML model's methods = * + *************************************************************************= *****/ + +int generic_create_ml_model(struct ml_lib_model *ml_model) +{ + size_t size =3D sizeof(struct ml_lib_subsystem); + + ml_model->parent =3D allocate_subsystem_object(size, GFP_KERNEL); + if (unlikely(!ml_model->parent)) + return -ENOMEM; + + atomic_set(&ml_model->parent->type, ML_LIB_GENERIC_SUBSYSTEM); + atomic_set(&ml_model->mode, ML_LIB_EMERGENCY_MODE); + + return 0; +} +EXPORT_SYMBOL(generic_create_ml_model); + +int generic_init_ml_model(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options) +{ + options->sleep_timeout =3D ML_LIB_SLEEP_TIMEOUT_DEFAULT; + return 0; +} +EXPORT_SYMBOL(generic_init_ml_model); + +int generic_re_init_ml_model(struct ml_lib_model *ml_model, + struct ml_lib_model_options *options) +{ + options->sleep_timeout =3D ML_LIB_SLEEP_TIMEOUT_DEFAULT; + return 0; +} +EXPORT_SYMBOL(generic_re_init_ml_model); + +int generic_start_ml_model(struct ml_lib_model *ml_model, + struct ml_lib_model_run_config *config) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_start_ml_model); + +int generic_stop_ml_model(struct ml_lib_model *ml_model) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_stop_ml_model); + +void generic_destroy_ml_model(struct ml_lib_model *ml_model) +{ + atomic_set(&ml_model->parent->type, ML_LIB_UNKNOWN_SUBSYSTEM_TYPE); + atomic_set(&ml_model->mode, ML_LIB_UNKNOWN_MODE); +} +EXPORT_SYMBOL(generic_destroy_ml_model); + +struct ml_lib_subsystem_state * +generic_get_system_state(struct ml_lib_model *ml_model) +{ + return NULL; +} +EXPORT_SYMBOL(generic_get_system_state); + +int generic_get_dataset(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset) +{ + atomic_set(&dataset->type, ML_LIB_EMPTY_DATASET); + atomic_set(&dataset->state, ML_LIB_DATASET_CLEAN); + dataset->allocated_size =3D 0; + dataset->portion_offset =3D 0; + dataset->portion_size =3D 0; + + return 0; +} +EXPORT_SYMBOL(generic_get_dataset); + +int generic_preprocess_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_preprocess_data); + +int generic_publish_data(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset, + struct ml_lib_user_space_notification *notify) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_publish_data); + +int generic_preprocess_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_preprocess_recommendation); + +int generic_estimate_system_state(struct ml_lib_model *ml_model) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_estimate_system_state); + +int generic_apply_recommendation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_apply_recommendation); + +int generic_execute_operation(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_execute_operation); + +int generic_estimate_efficiency(struct ml_lib_model *ml_model, + struct ml_lib_user_space_recommendation *hint, + struct ml_lib_user_space_request *request) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_estimate_efficiency); + +int generic_error_backpropagation(struct ml_lib_model *ml_model, + struct ml_lib_backpropagation_feedback *feedback, + struct ml_lib_user_space_notification *notify) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_error_backpropagation); + +int generic_correct_system_state(struct ml_lib_model *ml_model) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(generic_correct_system_state); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Viacheslav Dubeyko "); +MODULE_DESCRIPTION("ML library"); +MODULE_VERSION("1.0"); diff --git a/lib/ml-lib/sysfs.c b/lib/ml-lib/sysfs.c new file mode 100644 index 000000000000..fb4b7f44f793 --- /dev/null +++ b/lib/ml-lib/sysfs.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Machine Learning (ML) library + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + */ + +#include +#include + +#include + +#include "sysfs.h" + +struct ml_lib_feature_attr { + struct attribute attr; + ssize_t (*show)(struct ml_lib_feature_attr *, + struct ml_lib_model *, + char *); + ssize_t (*store)(struct ml_lib_feature_attr *, + struct ml_lib_model *, + const char *, size_t); +}; + +#define ML_LIB_ATTR(type, name, mode, show, store) \ + static struct ml_lib_##type##_attr ml_lib_##type##_attr_##name =3D \ + __ATTR(name, mode, show, store) + +#define ML_LIB_FEATURE_INFO_ATTR(name) \ + ML_LIB_ATTR(feature, name, 0444, NULL, NULL) +#define ML_LIB_FEATURE_RO_ATTR(name) \ + ML_LIB_ATTR(feature, name, 0444, ml_lib_feature_##name##_show, NULL) +#define ML_LIB_FEATURE_W_ATTR(name) \ + ML_LIB_ATTR(feature, name, 0220, NULL, ml_lib_feature_##name##_store) +#define ML_LIB_FEATURE_RW_ATTR(name) \ + ML_LIB_ATTR(feature, name, 0644, \ + ml_lib_feature_##name##_show, ml_lib_feature_##name##_store) + +enum { + ML_LIB_START_COMMAND, + ML_LIB_STOP_COMMAND, + ML_LIB_PREPARE_DATASET_COMMAND, + ML_LIB_DISCARD_DATASET_COMMAND, + ML_LIB_COMMAND_NUMBER +}; + +static const char *control_command_str[ML_LIB_COMMAND_NUMBER] =3D { + "start", + "stop", + "prepare_dataset", + "discard_dataset", +}; + +static ssize_t ml_lib_feature_control_store(struct ml_lib_feature_attr *at= tr, + struct ml_lib_model *ml_model, + const char *buf, size_t len) +{ + struct ml_lib_model_run_config config =3D {0}; + int i; + int err; + + for (i =3D 0; i < ML_LIB_COMMAND_NUMBER; i++) { + size_t iter_len =3D min(len, strlen(control_command_str[i])); + + if (strncmp(control_command_str[i], buf, iter_len) =3D=3D 0) + break; + } + + if (i >=3D ML_LIB_COMMAND_NUMBER) + return -EOPNOTSUPP; + + switch (i) { + case ML_LIB_START_COMMAND: + err =3D ml_model_start(ml_model, &config); + break; + + case ML_LIB_STOP_COMMAND: + err =3D ml_model_stop(ml_model); + break; + + case ML_LIB_PREPARE_DATASET_COMMAND: + err =3D ml_model_get_dataset(ml_model, NULL, NULL); + break; + + case ML_LIB_DISCARD_DATASET_COMMAND: + err =3D ml_model_discard_dataset(ml_model); + break; + } + + if (unlikely(err)) + return err; + + return len; +} + +ML_LIB_FEATURE_W_ATTR(control); + +static struct attribute *ml_model_attrs[] =3D { + &ml_lib_feature_attr_control.attr, + NULL, +}; + +static const struct attribute_group ml_model_group =3D { + .attrs =3D ml_model_attrs, +}; + +static const struct attribute_group *ml_model_groups[] =3D { + &ml_model_group, + NULL, +}; + +static +ssize_t ml_model_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct ml_lib_model *ml_model =3D container_of(kobj, + struct ml_lib_model, + kobj); + struct ml_lib_feature_attr *ml_model_attr =3D + container_of(attr, struct ml_lib_feature_attr, attr); + + if (!ml_model_attr->show) + return -EIO; + + return ml_model_attr->show(ml_model_attr, ml_model, buf); +} + +static +ssize_t ml_model_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t len) +{ + struct ml_lib_model *ml_model =3D container_of(kobj, + struct ml_lib_model, + kobj); + struct ml_lib_feature_attr *ml_model_attr =3D + container_of(attr, struct ml_lib_feature_attr, attr); + + if (!ml_model_attr->store) + return -EIO; + + return ml_model_attr->store(ml_model_attr, ml_model, buf, len); +} + +static const struct sysfs_ops ml_model_attr_ops =3D { + .show =3D ml_model_attr_show, + .store =3D ml_model_attr_store, +}; + +static inline +void ml_model_kobj_release(struct kobject *kobj) +{ + struct ml_lib_model *ml_model =3D container_of(kobj, + struct ml_lib_model, + kobj); + complete(&ml_model->kobj_unregister); +} + +static struct kobj_type ml_model_ktype =3D { + .default_groups =3D ml_model_groups, + .sysfs_ops =3D &ml_model_attr_ops, + .release =3D ml_model_kobj_release, +}; + +int ml_model_create_sysfs_group(struct ml_lib_model *ml_model, + struct kobject *subsystem_kobj) +{ + int err; + + init_completion(&ml_model->kobj_unregister); + + err =3D kobject_init_and_add(&ml_model->kobj, &ml_model_ktype, + subsystem_kobj, + "%s", ml_model->model_name); + if (err) + pr_err("ml_lib: failed to create sysfs group: err %d\n", err); + + return err; +} + +void ml_model_delete_sysfs_group(struct ml_lib_model *ml_model) +{ + kobject_del(&ml_model->kobj); + kobject_put(&ml_model->kobj); + wait_for_completion(&ml_model->kobj_unregister); +} diff --git a/lib/ml-lib/sysfs.h b/lib/ml-lib/sysfs.h new file mode 100644 index 000000000000..6bd3ab64a1c0 --- /dev/null +++ b/lib/ml-lib/sysfs.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Machine Learning (ML) library + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + */ + +#ifndef _LINUX_ML_LIB_SYSFS_H +#define _LINUX_ML_LIB_SYSFS_H + +#include + +int ml_model_create_sysfs_group(struct ml_lib_model *ml_model, + struct kobject *subsystem_kobj); +void ml_model_delete_sysfs_group(struct ml_lib_model *ml_model); + +#endif /* _LINUX_ML_LIB_SYSFS_H */ --=20 2.34.1 From nobody Sun Feb 8 05:24:02 2026 Received: from mail-yw1-f174.google.com (mail-yw1-f174.google.com [209.85.128.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E81ED42EEA0 for ; Fri, 6 Feb 2026 19:13:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405193; cv=none; b=AaKeZwqvZOGa1X2iBmRVJfgx7P690VgnCRbhW6snJ+rxp8+2+f7IBNZHeeS3L0wmngsqLgeFf3mr5+Lfj8xY7/bpJmNvHwFz6mIcOtwk1rxpVxxrB+xbrZriZeYC8Kpo2akm+5lUdurNCKj2mUJOWATHsMChJV5mqkIDeIch9Cg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405193; c=relaxed/simple; bh=8DOELj3d1YF5vnkKTf0ls4Z7dKSAOmVY1KhPtSJlYno=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=G//phFgPa2Th5Vr4WzjKmdBQk0OD72GLjx/wFWOYIQWgkVXsNaTYpcgjrzpAVzlJWQKaMLqeB7AbWSRONu5rHEDXcRgK3jZQnoqbPS8RvrhvGOHn9uTc5h96xS916aukKLQkf2xQ+k0a5VZr4aSFoeqxjmLHI6yIRH9nPqfq9Zo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b=qMUZ3y7v; arc=none smtp.client-ip=209.85.128.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b="qMUZ3y7v" Received: by mail-yw1-f174.google.com with SMTP id 00721157ae682-7950881727cso18585517b3.3 for ; Fri, 06 Feb 2026 11:13:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20230601.gappssmtp.com; s=20230601; t=1770405192; x=1771009992; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=YEXgdq0izXJsGpGxsVLN8S/Y6PSgZJ5yVJf6Tpti494=; b=qMUZ3y7v4CUyHnCq9dui3zjSqmd7Vbk3gInTWAmUREBPnJnHU+Uugjs6XhxEbztUJY 6MIAuVy7i4q17GZzyT3vqqUbzI0iZbrPR11PXUvNUqkUgSZaQmoL3dQJxn7ON80uRcCB 0MdK7XDrS0SvPeodUezrKPUZAknAXJ2383hc+mACzyvortOxi+JlfE6qcv50cH/qeGho T7WRppCGoFPndU7EJTf65pl9ipgGgsXFcIJ/XbfLbplNKBuS3zpJWq9Oj+DORvN4gUTM ABKB4YRV+55SHIx4WiiiCLtC8DkzZAIucRHCjxkTx+AH5gW3EFE+GodfGEj+IwWc30qr rCvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770405192; x=1771009992; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=YEXgdq0izXJsGpGxsVLN8S/Y6PSgZJ5yVJf6Tpti494=; b=n+hSZR8OULAozmOgwxG1W58pP++2Z7b68kqEp6gHYgCrx8kfIJ5BlrsspR7rO6wFNI UnKDg0Ym8HY5QcTcICLYc2uiJg2qTopTnc7fLA3Rvkbz7qCTqvAq5Kb6vFAsK3WoPMuM H9IOZ56NjDtjCtHrMbpPSiLjKaNGYVuJGCCsMEryQ6BJftN07yIvGYy8/ui8/KAb71Ii p6mYAkw7rUvZKZTWm0dH82899zwjhYpUS80ZcO9V2xCQW+71rdpq00EAAk5+awAxMQQ5 GM61BWnHu6dkCcFKCQGO5dm4Yl7SA6vEvM49CdEAhXZPoUb330PtC4/w/TeDJARgFDyx a5dg== X-Forwarded-Encrypted: i=1; AJvYcCVTJf8Cx33WXB0TP49N8ly1U7Vbs37S+5MQhbJxNJghb5rqVvWguSdRlUfRkLinlWLMve/bWntHB+xCOvg=@vger.kernel.org X-Gm-Message-State: AOJu0YyFtns3NEMjXW+7v/0yKKtA7IFDcqVbFv7XNfq7iksYI1xD03XR vdBBQXWCh242eJr//BxH6grjEaGyrYn/3Qhh01iJk+lfK5AlWvWD0rCOlaj9jPTDH96RuF2sQDt XpbbKr6s= X-Gm-Gg: AZuq6aKeNKJ32ztS8rGqzXoeWYgQrjv9dLP2N4Z277EwvdRtTLPK4NyKwQ2Phpp6ZTG RZvKWYo0tbc8RZAUOGT3GPgs/Sm+ouYvfsMtSJda2t0L4KPOJfpuqfDyLeVMBKCn5cJhoN/o0fU f1fQM12QAlfptWcfXgKZmGfgcAv3x+RwjjT9ExtPlUnjzaLdCFxb+PsuBZz/9fPOxpfqN+BSF86 Y6XmMw1UFKqewX8V1WnWkzqZXif+OGsfDTKrgphNR/aRu7/RzWHCwGxFyF+Pt4X4DJdDkUA4jh9 iKKLh4hUXuGbNvU/Z9dIr3J/2OaBHQyp6DHqxgi+sTTPB9rziQguxCiAjw8if/sjtEhmmnbVVsF WbHa8kR3AHV1umDFSWEieY6ljYeoOAzT5d+5IblXCHjU1ITCjE6aMLKVG/V5xShvRBF3AKrBwqM ngmL4htZN9+wrEwOpQfw5Rgc6Zy7SYZImO/cTEtT1z5A3qXUBEBp3nQ3SqN6Osqr4fVBsU7nVqZ jbe5606Jhys X-Received: by 2002:a05:690c:9c04:b0:796:1eee:b8f7 with SMTP id 00721157ae682-7961eeebef9mr45307667b3.58.1770405191900; Fri, 06 Feb 2026 11:13:11 -0800 (PST) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:9fc0:ed7d:72bd:ecd1]) by smtp.gmail.com with ESMTPSA id 00721157ae682-7952a28697fsm29051277b3.50.2026.02.06.11.13.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Feb 2026 11:13:11 -0800 (PST) From: Viacheslav Dubeyko To: linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, bpf@vger.kernel.org Cc: Slava.Dubeyko@ibm.com, slava@dubeyko.com, linux-kernel@vger.kernel.org Subject: [RFC PATCH v1 3/4] ml-lib: Implement simple testing character device driver Date: Fri, 6 Feb 2026 11:11:35 -0800 Message-Id: <20260206191136.2609767-4-slava@dubeyko.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260206191136.2609767-1-slava@dubeyko.com> References: <20260206191136.2609767-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement simple testing character device driver Signed-off-by: Viacheslav Dubeyko --- lib/ml-lib/test_driver/Kconfig | 22 + lib/ml-lib/test_driver/Makefile | 5 + lib/ml-lib/test_driver/README.md | 233 ++++++++++ lib/ml-lib/test_driver/ml_lib_char_dev.c | 530 +++++++++++++++++++++++ 4 files changed, 790 insertions(+) create mode 100644 lib/ml-lib/test_driver/Kconfig create mode 100644 lib/ml-lib/test_driver/Makefile create mode 100644 lib/ml-lib/test_driver/README.md create mode 100644 lib/ml-lib/test_driver/ml_lib_char_dev.c diff --git a/lib/ml-lib/test_driver/Kconfig b/lib/ml-lib/test_driver/Kconfig new file mode 100644 index 000000000000..183fc1de57a8 --- /dev/null +++ b/lib/ml-lib/test_driver/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 + +config ML_LIB_TEST_DRIVER + tristate "ML library testing character device driver" + depends on ML_LIB + default n + help + This is a ML library testing character device driver for + testing generic ML library functionality. It provides: + + - Basic read/write operations + - IOCTL interface for device control + - Sysfs attributes for runtime information + - Procfs entry for debugging + + The driver creates a /dev/mllibdev device node that can be + used to read and write data to a kernel buffer. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called mllibdev. diff --git a/lib/ml-lib/test_driver/Makefile b/lib/ml-lib/test_driver/Makef= ile new file mode 100644 index 000000000000..6444bcf8985b --- /dev/null +++ b/lib/ml-lib/test_driver/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_ML_LIB_TEST_DRIVER) +=3D ml_lib_test_dev.o + +ml_lib_test_dev-y :=3D ml_lib_char_dev.o diff --git a/lib/ml-lib/test_driver/README.md b/lib/ml-lib/test_driver/READ= ME.md new file mode 100644 index 000000000000..0bb4105c8aa4 --- /dev/null +++ b/lib/ml-lib/test_driver/README.md @@ -0,0 +1,233 @@ +# ML Library Testing Device Driver (mllibdev) + +ML library testing character device driver for the Linux kernel: +- Basic read/write operations +- IOCTL interface for device control +- Sysfs attributes for runtime information +- Procfs entry for debugging + +## Features + +### Character Device Operations +- **Open/Close**: Device can be opened and closed multiple times +- **Read**: Read data from a kernel buffer +- **Write**: Write data to a kernel buffer (1KB capacity) +- **Seek**: Support for lseek() operations + +### IOCTL Commands +- `ML_LIB_TEST_DEV_IOCRESET`: Clear the device buffer +- `ML_LIB_TEST_DEV_IOCGETSIZE`: Get current data size +- `ML_LIB_TEST_DEV_IOCSETSIZE`: Set data size + +### Sysfs Attributes +Located at `/sys/class/ml_lib_test/mllibdev`: +- `buffer_size`: Maximum buffer capacity (read-only) +- `data_size`: Current amount of data in buffer (read-only) +- `access_count`: Number of times device has been opened (read-only) +- `stats`: Comprehensive statistics (opens, reads, writes) + +### Procfs Entry +Located at `/proc/mllibdev`: Provides formatted driver information + +## Building the Driver + +### Option 1: Build as a Module + +1. Configure the kernel to build mllibdev as a module: + ```bash + make menuconfig + # Navigate to: Library routines -> ML library testing character device = driver + # Select: ML library testing character device driver + ``` + +2. Build the module: + ```bash + make -j$(nproc) M=3Dlib/ml-lib/test_driver + ``` + +### Option 2: Build into Kernel + +1. Configure the kernel: + ```bash + make menuconfig + # Navigate to: Library routines -> ML library testing character device = driver + # Select: <*> ML library testing character device driver + ``` + +2. Build the kernel: + ```bash + make -j$(nproc) + ``` + +### Option 3: Quick Module Build (Out-of-Tree) + +For quick testing, you can build just the module: + +```bash +cd lib/ml-lib/test_driver +make -C /lib/modules/$(uname -r)/build M=3D$(pwd) modules +``` + +## Loading the Driver + +If built as a module: + +```bash +# Load the module +sudo insmod /lib/modules/$(uname -r)/build/lib/ml-lib/test_driver/ml_lib_t= est_dev.ko + +# Verify it's loaded +sudo lsmod | grep ml_lib_test_dev + +# Check kernel messages +sudo dmesg | tail -20 +``` + +You should see messages like: +``` +ml_lib_test_dev: Initializing driver +ml_lib_test_dev: Device number allocated: XXX:0 +ml_lib_test_dev: Driver initialized successfully +ml_lib_test_dev: Device created at /dev/mllibdev +ml_lib_test_dev: Proc entry created at /proc/mllibdev +``` + +## Testing the Driver + +### Quick Manual Test + +```bash +# Write data to the device +sudo su +echo "Hello, kernel!" > /dev/mllibdev + +# Read data back +sudo su +cat /dev/mllibdev + +# Check sysfs attributes +cat /sys/class/ml_lib_test/mllibdev/stats + +# Check proc entry +cat /proc/mllibdev +``` + +### Using the Test Program + +1. Compile the test program: + ```bash + cd lib/ml-lib/test_driver/test_application + gcc -o ml_lib_test_dev test_ml_lib_char_dev.c + ``` + +2. Run the test program: + ```bash + sudo ./ml_lib_test_dev + ``` + +The test program will: +- Open the device +- Write test data +- Read the data back +- Test all IOCTL commands +- Display sysfs attributes +- Show procfs information + +### Example Test Output + +``` +ML Library Testing Device Driver Test Program +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Device opened successfully: /dev/mllibdev + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Write Test =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Successfully wrote 62 bytes +Data: "Hello from userspace! This is a test of the mllibdev driver." + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Read Test =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Successfully read 62 bytes +Data: "Hello from userspace! This is a test of the mllibdev driver." + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D IOCTL Tests =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Current data size: 62 bytes +Set data size to: 50 bytes +Verified new size: 50 bytes +Buffer reset successfully +Size after reset: 0 bytes + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Sysfs Attributes =3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +buffer_size: 1024 +data_size: 0 +access_count: 1 + +stats: Opens: 1 +Reads: 1 +Writes: 1 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Procfs Information =3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +ML Library Testing Device Driver Information +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D +Device name: mllibdev +Buffer size: 1024 bytes +Data size: 0 bytes +Access count: 1 +Read count: 1 +Write count: 1 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Final Test =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +All tests completed successfully! +``` + +## Unloading the Driver + +```bash +# Remove the module +sudo rmmod ml_lib_test_dev + +# Verify it's unloaded +sudo lsmod | grep ml_lib_test_dev + +# Check cleanup messages +sudo dmesg | tail -10 +``` + +## Troubleshooting + +### Device node doesn't exist +```bash +# Check if udev created the device +ls -l /dev/mllibdev + +# Manually create if needed (shouldn't be necessary) +sudo mknod /dev/mllibdev c MAJOR MINOR +``` + +### Permission denied +```bash +# Run commands with sudo +sudo cat /dev/mllibdev + +# Or change permissions +sudo chmod 666 /dev/mllibdev +``` + +### Module won't load +```bash +# Check kernel messages for errors +dmesg | tail -20 + +# Verify module dependencies +modinfo lib/ml-lib/test_driver/ml_lib_test_dev.ko +``` + +## License + +This driver is licensed under GPL-2.0. + +## Author + +Viacheslav Dubeyko + +## Version + +1.0 diff --git a/lib/ml-lib/test_driver/ml_lib_char_dev.c b/lib/ml-lib/test_dri= ver/ml_lib_char_dev.c new file mode 100644 index 000000000000..b2d6e27ece28 --- /dev/null +++ b/lib/ml-lib/test_driver/ml_lib_char_dev.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Machine Learning (ML) library + * Testing Character Device Driver + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "mllibdev" +#define CLASS_NAME "ml_lib_test" +#define BUFFER_SIZE 1024 + +/* IOCTL commands */ +#define ML_LIB_TEST_DEV_IOC_MAGIC 'M' +#define ML_LIB_TEST_DEV_IOCRESET _IO(ML_LIB_TEST_DEV_IOC_MAGIC, 0) +#define ML_LIB_TEST_DEV_IOCGETSIZE _IOR(ML_LIB_TEST_DEV_IOC_MAGIC, 1, int) +#define ML_LIB_TEST_DEV_IOCSETSIZE _IOW(ML_LIB_TEST_DEV_IOC_MAGIC, 2, int) + +/* Device data structure */ +struct ml_lib_test_dev_data { + struct cdev cdev; + struct device *device; + char *dataset_buf; + size_t dataset_buf_size; + size_t dataset_size; + char *recommendations_buf; + size_t recommendations_buf_size; + size_t recommendations_size; + struct mutex lock; + unsigned long access_count; + unsigned long read_count; + unsigned long write_count; + + struct ml_lib_model *ml_model1; +}; + +#define ML_MODEL_1_NAME "ml_model1" + +static +int ml_lib_test_dev_extract_dataset(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset); + +static struct ml_lib_dataset_operations ml_lib_test_dev_dataset_ops =3D { + .extract =3D ml_lib_test_dev_extract_dataset, +}; + +static dev_t dev_number; +static struct class *ml_lib_test_dev_class; +static struct ml_lib_test_dev_data *dev_data; +static struct proc_dir_entry *proc_entry; + +/* ML model operations */ +static +int ml_lib_test_dev_extract_dataset(struct ml_lib_model *ml_model, + struct ml_lib_dataset *dataset) +{ + struct ml_lib_test_dev_data *data =3D + (struct ml_lib_test_dev_data *)ml_model->parent->private; + u8 pattern; + + mutex_lock(&data->lock); + get_random_bytes(&pattern, 1); + memset(data->dataset_buf, pattern, data->dataset_buf_size); + data->dataset_size =3D data->dataset_buf_size; + atomic_set(&dataset->type, ML_LIB_MEMORY_STREAM_DATASET); + atomic_set(&dataset->state, ML_LIB_DATASET_CLEAN); + dataset->allocated_size =3D data->dataset_buf_size; + dataset->portion_offset =3D 0; + dataset->portion_size =3D data->dataset_buf_size; + mutex_unlock(&data->lock); + + return 0; +} + +/* File operations */ +static int ml_lib_test_dev_open(struct inode *inode, struct file *file) +{ + struct ml_lib_test_dev_data *data =3D container_of(inode->i_cdev, + struct ml_lib_test_dev_data, + cdev); + + file->private_data =3D data; + + mutex_lock(&data->lock); + data->access_count++; + mutex_unlock(&data->lock); + + pr_info("ml_lib_test_dev: Device opened (total opens: %lu)\n", + data->access_count); + + return 0; +} + +static int ml_lib_test_dev_release(struct inode *inode, struct file *file) +{ + pr_info("ml_lib_test_dev: Device closed\n"); + return 0; +} + +static ssize_t ml_lib_test_dev_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct ml_lib_test_dev_data *data =3D file->private_data; + size_t to_read; + int ret; + + mutex_lock(&data->lock); + + if (*ppos >=3D data->dataset_size) { + mutex_unlock(&data->lock); + return 0; + } + + to_read =3D min(count, data->dataset_size - (size_t)*ppos); + + ret =3D copy_to_user(buf, data->dataset_buf + *ppos, to_read); + if (ret) { + mutex_unlock(&data->lock); + return -EFAULT; + } + + *ppos +=3D to_read; + data->read_count++; + + mutex_unlock(&data->lock); + + pr_info("ml_lib_test_dev: Read %zu bytes\n", to_read); + + return to_read; +} + +static ssize_t ml_lib_test_dev_write(struct file *file, const char __user = *buf, + size_t count, loff_t *ppos) +{ + struct ml_lib_test_dev_data *data =3D file->private_data; + size_t to_write; + int ret; + + mutex_lock(&data->lock); + + if (*ppos >=3D data->recommendations_buf_size) { + mutex_unlock(&data->lock); + return -ENOSPC; + } + + to_write =3D min(count, data->recommendations_buf_size - (size_t)*ppos); + + ret =3D copy_from_user(data->recommendations_buf + *ppos, buf, to_write); + if (ret) { + mutex_unlock(&data->lock); + return -EFAULT; + } + + *ppos +=3D to_write; + if (*ppos > data->recommendations_size) + data->recommendations_size =3D *ppos; + + data->write_count++; + + mutex_unlock(&data->lock); + + pr_info("ml_lib_test_dev: Wrote %zu bytes\n", to_write); + + return to_write; +} + +static long ml_lib_test_dev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ml_lib_test_dev_data *data =3D file->private_data; + int size; + + switch (cmd) { + case ML_LIB_TEST_DEV_IOCRESET: + mutex_lock(&data->lock); + memset(data->dataset_buf, + 0, data->dataset_buf_size); + data->dataset_size =3D 0; + memset(data->recommendations_buf, + 0, data->recommendations_buf_size); + data->recommendations_size =3D 0; + mutex_unlock(&data->lock); + pr_info("ml_lib_test_dev: Buffer reset via IOCTL\n"); + break; + + case ML_LIB_TEST_DEV_IOCGETSIZE: + mutex_lock(&data->lock); + size =3D data->dataset_size; + mutex_unlock(&data->lock); + if (copy_to_user((int __user *)arg, &size, sizeof(size))) + return -EFAULT; + break; + + case ML_LIB_TEST_DEV_IOCSETSIZE: + if (copy_from_user(&size, (int __user *)arg, sizeof(size))) + return -EFAULT; + if (size < 0 || size > data->recommendations_buf_size) + return -EINVAL; + mutex_lock(&data->lock); + data->recommendations_size =3D size; + mutex_unlock(&data->lock); + pr_info("ml_lib_test_dev: Data size set to %d via IOCTL\n", size); + break; + + default: + return -ENOTTY; + } + + return 0; +} + +static const struct file_operations ml_lib_test_dev_fops =3D { + .owner =3D THIS_MODULE, + .open =3D ml_lib_test_dev_open, + .release =3D ml_lib_test_dev_release, + .read =3D ml_lib_test_dev_read, + .write =3D ml_lib_test_dev_write, + .unlocked_ioctl =3D ml_lib_test_dev_ioctl, + .llseek =3D default_llseek, +}; + +/* Sysfs attributes */ +static ssize_t buffer_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ml_lib_test_dev_data *data =3D dev_get_drvdata(dev); + + return sprintf(buf, "%zu\n", data->dataset_buf_size); +} + +static ssize_t data_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ml_lib_test_dev_data *data =3D dev_get_drvdata(dev); + size_t size; + + mutex_lock(&data->lock); + size =3D data->dataset_size; + mutex_unlock(&data->lock); + + return sprintf(buf, "%zu\n", size); +} + +static ssize_t access_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ml_lib_test_dev_data *data =3D dev_get_drvdata(dev); + + return sprintf(buf, "%lu\n", data->access_count); +} + +static ssize_t stats_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ml_lib_test_dev_data *data =3D dev_get_drvdata(dev); + + return sprintf(buf, "Opens: %lu\nReads: %lu\nWrites: %lu\n", + data->access_count, data->read_count, + data->write_count); +} + +static DEVICE_ATTR_RO(buffer_size); +static DEVICE_ATTR_RO(data_size); +static DEVICE_ATTR_RO(access_count); +static DEVICE_ATTR_RO(stats); + +static struct attribute *ml_lib_test_dev_attrs[] =3D { + &dev_attr_buffer_size.attr, + &dev_attr_data_size.attr, + &dev_attr_access_count.attr, + &dev_attr_stats.attr, + NULL, +}; + +static const struct attribute_group ml_lib_test_dev_attr_group =3D { + .attrs =3D ml_lib_test_dev_attrs, +}; + +/* Procfs operations */ +static int ml_lib_test_dev_proc_show(struct seq_file *m, void *v) +{ + struct ml_lib_test_dev_data *data =3D dev_data; + + seq_printf(m, "ML Library Testing Device Driver Information\n"); + seq_printf(m, "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + seq_printf(m, "Device name: %s\n", DEVICE_NAME); + seq_printf(m, "Buffer size: %zu bytes\n", data->dataset_buf_size); + seq_printf(m, "Data size: %zu bytes\n", data->dataset_size); + seq_printf(m, "Access count: %lu\n", data->access_count); + seq_printf(m, "Read count: %lu\n", data->read_count); + seq_printf(m, "Write count: %lu\n", data->write_count); + + return 0; +} + +static int ml_lib_test_dev_proc_open(struct inode *inode, struct file *fil= e) +{ + return single_open(file, ml_lib_test_dev_proc_show, NULL); +} + +static const struct proc_ops ml_lib_test_dev_proc_ops =3D { + .proc_open =3D ml_lib_test_dev_proc_open, + .proc_read =3D seq_read, + .proc_lseek =3D seq_lseek, + .proc_release =3D single_release, +}; + +/* Module initialization */ +static int __init ml_lib_test_dev_init(void) +{ + struct ml_lib_model_options *options; + int ret; + + pr_info("ml_lib_test_dev: Initializing driver\n"); + + /* Allocate device data */ + dev_data =3D kzalloc(sizeof(struct ml_lib_test_dev_data), GFP_KERNEL); + if (!dev_data) + return -ENOMEM; + + /* Allocate dataset buffer */ + dev_data->dataset_buf =3D kzalloc(BUFFER_SIZE, GFP_KERNEL); + if (!dev_data->dataset_buf) { + ret =3D -ENOMEM; + goto err_free_data; + } + + dev_data->dataset_buf_size =3D BUFFER_SIZE; + dev_data->dataset_size =3D 0; + + /* Allocate recomendations buffer */ + dev_data->recommendations_buf =3D kzalloc(BUFFER_SIZE, GFP_KERNEL); + if (!dev_data->recommendations_buf) { + ret =3D -ENOMEM; + goto err_free_dataset_buffer; + } + + dev_data->recommendations_buf_size =3D BUFFER_SIZE; + dev_data->recommendations_size =3D 0; + + mutex_init(&dev_data->lock); + + /* Allocate device number */ + ret =3D alloc_chrdev_region(&dev_number, 0, 1, DEVICE_NAME); + if (ret < 0) { + pr_err("ml_lib_test_dev: Failed to allocate device number\n"); + goto err_free_recommendations_buffer; + } + + pr_info("ml_lib_test_dev: Device number allocated: %d:%d\n", + MAJOR(dev_number), MINOR(dev_number)); + + /* Create device class */ + ml_lib_test_dev_class =3D class_create(CLASS_NAME); + if (IS_ERR(ml_lib_test_dev_class)) { + ret =3D PTR_ERR(ml_lib_test_dev_class); + pr_err("ml_lib_test_dev: Failed to create class\n"); + goto err_unregister_chrdev; + } + + /* Initialize and add cdev */ + cdev_init(&dev_data->cdev, &ml_lib_test_dev_fops); + dev_data->cdev.owner =3D THIS_MODULE; + + ret =3D cdev_add(&dev_data->cdev, dev_number, 1); + if (ret < 0) { + pr_err("ml_lib_test_dev: Failed to add cdev\n"); + goto err_class_destroy; + } + + /* Create device */ + dev_data->device =3D device_create(ml_lib_test_dev_class, + NULL, dev_number, + dev_data, DEVICE_NAME); + if (IS_ERR(dev_data->device)) { + ret =3D PTR_ERR(dev_data->device); + pr_err("ml_lib_test_dev: Failed to create device\n"); + goto err_cdev_del; + } + + /* Create sysfs attributes */ + ret =3D sysfs_create_group(&dev_data->device->kobj, + &ml_lib_test_dev_attr_group); + if (ret < 0) { + pr_err("ml_lib_test_dev: Failed to create sysfs group\n"); + goto err_device_destroy; + } + + /* Create procfs entry */ + proc_entry =3D proc_create(DEVICE_NAME, 0444, NULL, + &ml_lib_test_dev_proc_ops); + if (!proc_entry) { + pr_err("ml_lib_test_dev: Failed to create proc entry\n"); + ret =3D -ENOMEM; + goto err_sysfs_remove; + } + + dev_data->ml_model1 =3D allocate_ml_model(sizeof(struct ml_lib_model), + GFP_KERNEL); + if (IS_ERR(dev_data->ml_model1)) { + ret =3D PTR_ERR(dev_data->ml_model1); + pr_err("ml_lib_test_dev: Failed to allocate ML model\n"); + goto err_procfs_remove; + } else if (!dev_data->ml_model1) { + ret =3D -ENOMEM; + pr_err("ml_lib_test_dev: Failed to allocate ML model\n"); + goto err_procfs_remove; + } + + ret =3D ml_model_create(dev_data->ml_model1, CLASS_NAME, + ML_MODEL_1_NAME, &dev_data->device->kobj); + if (ret < 0) { + pr_err("ml_lib_test_dev: Failed to create ML model\n"); + goto err_ml_model_free; + } + + dev_data->ml_model1->parent->private =3D dev_data; + dev_data->ml_model1->model_ops =3D NULL; + dev_data->ml_model1->dataset_ops =3D &ml_lib_test_dev_dataset_ops; + + options =3D allocate_ml_model_options(sizeof(struct ml_lib_model_options), + GFP_KERNEL); + if (IS_ERR(options)) { + ret =3D PTR_ERR(options); + pr_err("ml_lib_test_dev: Failed to allocate ML model options\n"); + goto err_ml_model_destroy; + } else if (!options) { + ret =3D -ENOMEM; + pr_err("ml_lib_test_dev: Failed to allocate ML model options\n"); + goto err_ml_model_destroy; + } + + ret =3D ml_model_init(dev_data->ml_model1, options); + if (ret < 0) { + pr_err("ml_lib_test_dev: Failed to init ML model\n"); + goto err_ml_model_options_free; + } + + pr_info("ml_lib_test_dev: Driver initialized successfully\n"); + pr_info("ml_lib_test_dev: Device created at /dev/%s\n", + DEVICE_NAME); + pr_info("ml_lib_test_dev: Proc entry created at /proc/%s\n", + DEVICE_NAME); + + return 0; + +err_ml_model_options_free: + free_ml_model_options(options); +err_ml_model_destroy: + ml_model_destroy(dev_data->ml_model1); +err_ml_model_free: + free_ml_model(dev_data->ml_model1); +err_procfs_remove: + proc_remove(proc_entry); +err_sysfs_remove: + sysfs_remove_group(&dev_data->device->kobj, + &ml_lib_test_dev_attr_group); +err_device_destroy: + device_destroy(ml_lib_test_dev_class, dev_number); +err_cdev_del: + cdev_del(&dev_data->cdev); +err_class_destroy: + class_destroy(ml_lib_test_dev_class); +err_unregister_chrdev: + unregister_chrdev_region(dev_number, 1); +err_free_recommendations_buffer: + kfree(dev_data->recommendations_buf); +err_free_dataset_buffer: + kfree(dev_data->dataset_buf); +err_free_data: + kfree(dev_data); + return ret; +} + +/* Module cleanup */ +static void __exit ml_lib_test_dev_exit(void) +{ + pr_info("ml_lib_test_dev: Cleaning up driver\n"); + + /* Destroy ML model */ + ml_model_destroy(dev_data->ml_model1); + free_ml_model(dev_data->ml_model1); + + /* Remove procfs entry */ + proc_remove(proc_entry); + + /* Remove sysfs attributes */ + sysfs_remove_group(&dev_data->device->kobj, + &ml_lib_test_dev_attr_group); + + /* Destroy device */ + device_destroy(ml_lib_test_dev_class, dev_number); + + /* Delete cdev */ + cdev_del(&dev_data->cdev); + + /* Destroy class */ + class_destroy(ml_lib_test_dev_class); + + /* Unregister device number */ + unregister_chrdev_region(dev_number, 1); + + /* Free buffers */ + kfree(dev_data->recommendations_buf); + kfree(dev_data->dataset_buf); + kfree(dev_data); + + pr_info("ml_lib_test_dev: Driver removed successfully\n"); +} + +module_init(ml_lib_test_dev_init); +module_exit(ml_lib_test_dev_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Viacheslav Dubeyko "); +MODULE_DESCRIPTION("ML libraray testing character device driver"); +MODULE_VERSION("1.0"); --=20 2.34.1 From nobody Sun Feb 8 05:24:02 2026 Received: from mail-yw1-f175.google.com (mail-yw1-f175.google.com [209.85.128.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F8F443E493 for ; Fri, 6 Feb 2026 19:13:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405194; cv=none; b=PYUgUZiXXXodVOIVQ3O9Qodt3qawSw7BBSQZOlYfa+RwHCL9x0mz9Vvn5zsP4wnSFKZpLuhFBsN7CjQKAudW7z7lJTqCsACcRIkYRng+U/5gd6dzq43ptWw3Cjzvc0UCwmF7Tk9+OPzYaHXAx3nu90J24nRX4Oj18eAAMKAhvtc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405194; c=relaxed/simple; bh=K/DVzBOCmPx/5xulxQPQA2jh8fJo6vYnCVmEwIInAPw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=dOycXW+3XTpBFRZkqCqF6LUkJTn1Sdcenpxbvevy+JXKxEmC1JSbM/Q6qKT5SjcheovCeQ8Ht8Ro8bL9TaGA/XhttK22tD5PnznqQhxEVwveO2a2YO/cRNnGDCgAckPX74dA+/tc5lqn+BxwRhin8xENftUxzmVZjDkeFB7pXXo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b=GoJSOBy5; arc=none smtp.client-ip=209.85.128.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20230601.gappssmtp.com header.i=@dubeyko-com.20230601.gappssmtp.com header.b="GoJSOBy5" Received: by mail-yw1-f175.google.com with SMTP id 00721157ae682-794ed669269so40449737b3.1 for ; Fri, 06 Feb 2026 11:13:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20230601.gappssmtp.com; s=20230601; t=1770405193; x=1771009993; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Hp7dE9rfuLorTfLe8+rhBEONpAq5JPSPoipR3P8yp2s=; b=GoJSOBy5vbp0HCrKs9pVp1eQlwvUg7H3Me6IfbkTJqTi6s/0Scgya6AiM5ls2dOqvU YrF8cAmBYUjLxkGR5uGOkU8ptIX42ZPDpkLFDvuXZEmfbcakzhc60CHARBFLqNiFy2r4 bPD+U2zxaacb6A5X3eoL8R9gj3zRSj5dWM2wthcPVvFrBGrvOEEq4QiJ6v0XuIoet4P6 mVPzTLV9waiCKS3dlD0/kF6NZxwbMS18uC4tmKOimgew/lOdZDTyNAg4wjZ1OYBUEu4G p9fbruLPt9aXlkor7SYjgr5db1ODXZxeSVBOeyE6D1mcMYgEM4FLRlwzioUJ3HbhsShG UH1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770405193; x=1771009993; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Hp7dE9rfuLorTfLe8+rhBEONpAq5JPSPoipR3P8yp2s=; b=KKTVpBljHuZHmV/ECr+ghr5RLczfozd69FwVVWCOi+jxDorSr5M3D2gJIW5ZZkREPf iqmn9p2Jqok5AbksuvT0aiArsP8cYlv0FgRXG0Nl6auEBceMwklvsZgPFvI25TjNSE35 PXIgIZ0L8nqbPKEYFxQjZF/+kHXMKqlovqqedGF5w9PIzhtkzHMl9hUH0ZvzOEecvqKj oz5R4Kz98Iwxqe4ZBMjTRcOyQH/xej01eMfJ51OxyQq8HbnHmA/w7WZxq5ADe3XMJJIo YD8dUBJVlBCL92l0+EzFl7AoNEQIfeSisGzaWG6+y1ALWrieh4tFiAb+XNDWxWn3BNas Rh+w== X-Forwarded-Encrypted: i=1; AJvYcCVQnv4m350d41kVZfwT+yQLD5JRYSxPfzJXHhYWYL+QxduvAyH20BVKC5sVM4kF/lGNjb6cGom08rL9+kA=@vger.kernel.org X-Gm-Message-State: AOJu0YwLW4AnN+21x0kv+crJhuS4x0vULAQhherXK8og4dDlRvbElyI+ KGKTjfon0jC8z8Kz7pQs7Ihhlv6ZDokynvT7IgOOtwzhIPGPBiRMxjjzLtuErlOGe23fKpJjH3r lWrNiEQQ= X-Gm-Gg: AZuq6aIxR6psllb0Cg/UtdWuPx9okTv4Ex9h9CHdbzF3ZGT2sQrd+G/QSOHESGkXZd9 l4EAdcoCng3Ggff898hZ90bkBasFpOKMdanc0MiU53TF8I+7HCnr3zFXaeBiaqfnQuohn2kJPoi ByEx9bUpMpgned/BC7skIe9d17ldT8u6zb8XheC3XRc5Ors+LKZ0PTcukbDj/gMMm3dn8bfwUQV 1U9zAtUUpcM+6YOAqWoEetm5VJSOnTfyTjCLyaFi8mR3VGxAauSfNMZGlzQhZCKaUOtfxwMZuRh it+k+9yFp7HEoVY4P1Zsz9XkJJAvPlw8JvYTJNzdAas+mK6cbSAd+cNjuA3TKjcfIALjiteqAGT y/8ZfXP0tWTwF6zSM1hOLeQAApPspNnCk6ULe6y6JqtS7Ryh/rpGNoeQMNqbC9yBbUfc7CIM8J/ mQL/kvcL/Ckqel+W5c6SoHuCon0AjTdqUXPnHpccDtu+mSCJKCEfT3oj09jnP5MUE+M8uPgrxof YylbuJFG/fV X-Received: by 2002:a05:690c:d8b:b0:788:181b:86c1 with SMTP id 00721157ae682-7952a63e4bcmr38138647b3.5.1770405193303; Fri, 06 Feb 2026 11:13:13 -0800 (PST) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:9fc0:ed7d:72bd:ecd1]) by smtp.gmail.com with ESMTPSA id 00721157ae682-7952a28697fsm29051277b3.50.2026.02.06.11.13.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Feb 2026 11:13:12 -0800 (PST) From: Viacheslav Dubeyko To: linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, bpf@vger.kernel.org Cc: Slava.Dubeyko@ibm.com, slava@dubeyko.com, linux-kernel@vger.kernel.org Subject: [RFC PATCH v1 4/4] ml-lib: Implement simple user-space testing application Date: Fri, 6 Feb 2026 11:11:36 -0800 Message-Id: <20260206191136.2609767-5-slava@dubeyko.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260206191136.2609767-1-slava@dubeyko.com> References: <20260206191136.2609767-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement simple user-space testing application Signed-off-by: Viacheslav Dubeyko --- .../test_application/ml_lib_char_dev_ioctl.h | 21 ++ .../test_application/test_ml_lib_char_dev.c | 206 ++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 lib/ml-lib/test_driver/test_application/ml_lib_char_dev= _ioctl.h create mode 100644 lib/ml-lib/test_driver/test_application/test_ml_lib_cha= r_dev.c diff --git a/lib/ml-lib/test_driver/test_application/ml_lib_char_dev_ioctl.= h b/lib/ml-lib/test_driver/test_application/ml_lib_char_dev_ioctl.h new file mode 100644 index 000000000000..7ea74e840fda --- /dev/null +++ b/lib/ml-lib/test_driver/test_application/ml_lib_char_dev_ioctl.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Machine Learning (ML) library + * + * Userspace API for ml_lib_dev testing driver + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + */ + +#ifndef _ML_LIB_TEST_DEV_IOCTL_H +#define _ML_LIB_TEST_DEV_IOCTL_H + +#include + +/* IOCTL commands */ +#define ML_LIB_TEST_DEV_IOC_MAGIC 'M' +#define ML_LIB_TEST_DEV_IOCRESET _IO(ML_LIB_TEST_DEV_IOC_MAGIC, 0) +#define ML_LIB_TEST_DEV_IOCGETSIZE _IOR(ML_LIB_TEST_DEV_IOC_MAGIC, 1, int) +#define ML_LIB_TEST_DEV_IOCSETSIZE _IOW(ML_LIB_TEST_DEV_IOC_MAGIC, 2, int) + +#endif /* _ML_LIB_TEST_DEV_IOCTL_H */ diff --git a/lib/ml-lib/test_driver/test_application/test_ml_lib_char_dev.c= b/lib/ml-lib/test_driver/test_application/test_ml_lib_char_dev.c new file mode 100644 index 000000000000..432b8a0ad068 --- /dev/null +++ b/lib/ml-lib/test_driver/test_application/test_ml_lib_char_dev.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Machine Learning (ML) library + * + * Test program for ml_lib_dev testing driver + * + * Copyright (C) 2025-2026 Viacheslav Dubeyko + * + * Compile with: gcc -o test_ml_lib_char_dev test_ml_lib_char_dev.c + * Run with: sudo ./test_ml_lib_char_dev + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ml_lib_char_dev_ioctl.h" + +#define DEVICE_PATH "/dev/mllibdev" +#define SYSFS_BASE "/sys/class/ml_lib_test/mllibdev" +#define PROC_PATH "/proc/mllibdev" + +static void print_separator(const char *title) +{ + printf("\n=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D %s =3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D\n", title); +} + +static void read_sysfs_attr(const char *attr_name) +{ + char path[256]; + char buffer[256]; + FILE *fp; + + snprintf(path, sizeof(path), "%s/%s", SYSFS_BASE, attr_name); + fp =3D fopen(path, "r"); + if (!fp) { + perror("Failed to open sysfs attribute"); + return; + } + + if (fgets(buffer, sizeof(buffer), fp)) { + printf(" %s: %s", attr_name, buffer); + } + + fclose(fp); +} + +static void show_sysfs_info(void) +{ + print_separator("Sysfs Attributes"); + read_sysfs_attr("buffer_size"); + read_sysfs_attr("data_size"); + read_sysfs_attr("access_count"); + printf("\n"); + read_sysfs_attr("stats"); +} + +static void show_proc_info(void) +{ + char buffer[1024]; + FILE *fp; + + print_separator("Procfs Information"); + + fp =3D fopen(PROC_PATH, "r"); + if (!fp) { + perror("Failed to open procfs entry"); + return; + } + + while (fgets(buffer, sizeof(buffer), fp)) { + printf("%s", buffer); + } + + fclose(fp); +} + +static void test_write(int fd) +{ + const char *test_data =3D "Hello from userspace! This is a test of the ml= libdev driver."; + ssize_t ret; + + print_separator("Write Test"); + + ret =3D write(fd, test_data, strlen(test_data)); + if (ret < 0) { + perror("Write failed"); + return; + } + + printf("Successfully wrote %zd bytes\n", ret); + printf("Data: \"%s\"\n", test_data); +} + +static void test_read(int fd) +{ + char buffer[256]; + ssize_t ret; + + print_separator("Read Test"); + + /* Seek to beginning */ + lseek(fd, 0, SEEK_SET); + + ret =3D read(fd, buffer, sizeof(buffer) - 1); + if (ret < 0) { + perror("Read failed"); + return; + } + + buffer[ret] =3D '\0'; + printf("Successfully read %zd bytes\n", ret); + printf("Data: \"%s\"\n", buffer); +} + +static void test_ioctl(int fd) +{ + int size; + int ret; + + print_separator("IOCTL Tests"); + + /* Get current size */ + ret =3D ioctl(fd, ML_LIB_TEST_DEV_IOCGETSIZE, &size); + if (ret < 0) { + perror("IOCTL GETSIZE failed"); + return; + } + printf("Current data size: %d bytes\n", size); + + /* Set new size */ + size =3D 50; + ret =3D ioctl(fd, ML_LIB_TEST_DEV_IOCSETSIZE, &size); + if (ret < 0) { + perror("IOCTL SETSIZE failed"); + return; + } + printf("Set data size to: %d bytes\n", size); + + /* Verify new size */ + ret =3D ioctl(fd, ML_LIB_TEST_DEV_IOCGETSIZE, &size); + if (ret < 0) { + perror("IOCTL GETSIZE failed"); + return; + } + printf("Verified new size: %d bytes\n", size); + + /* Reset buffer */ + ret =3D ioctl(fd, ML_LIB_TEST_DEV_IOCRESET); + if (ret < 0) { + perror("IOCTL RESET failed"); + return; + } + printf("Buffer reset successfully\n"); + + /* Verify size after reset */ + ret =3D ioctl(fd, ML_LIB_TEST_DEV_IOCGETSIZE, &size); + if (ret < 0) { + perror("IOCTL GETSIZE failed"); + return; + } + printf("Size after reset: %d bytes\n", size); +} + +int main(void) +{ + int fd; + + printf("ML Library Testing Device Driver Test Program\n"); + printf("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); + + /* Open the device */ + fd =3D open(DEVICE_PATH, O_RDWR); + if (fd < 0) { + perror("Failed to open device"); + printf("\nMake sure:\n"); + printf("1. The driver module is loaded (lsmod | grep mllibdev)\n"); + printf("2. You have proper permissions (run with sudo)\n"); + printf("3. The device node exists (ls -l /dev/mllibdev)\n"); + return 1; + } + + printf("Device opened successfully: %s\n", DEVICE_PATH); + + /* Run tests */ + test_write(fd); + test_read(fd); + test_ioctl(fd); + + /* Show sysfs and proc information */ + show_sysfs_info(); + show_proc_info(); + + /* Final stats */ + print_separator("Final Test"); + printf("All tests completed successfully!\n\n"); + + /* Close the device */ + close(fd); + + return 0; +} --=20 2.34.1