Create the first draft of ksudoku subsystem in one file

Signed-off-by: Sameer Rahmani <lxsameer@gnu.org>
This commit is contained in:
Sameer Rahmani 2020-04-04 16:48:13 +01:00
parent 5344bbf719
commit 171b0f6946
3 changed files with 232 additions and 81 deletions

248
ksudoku.c
View File

@ -1,65 +1,239 @@
#include "ksudoku.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sysfs.h>
#include <asm/atomic.h>
#include <linux/slab.h>
#define KSUDOKU_VERSION "0.1"
#define KSUDOKU_DESC "Kernel Sudoku Module"
#define KSUDOKU_READY 0
#define KSUDOKU_BUSY 1
static SUDOKU_ATTR_RO(is_valid);
static SUDOKU_ATTR_RO(is_solved);
struct ksudoku {
struct kobject kobj;
const struct attribute_group *attr_group;
char *matrix;
atomic_t status;
};
#define to_ksudoku(obj) container_of(obj, struct ksudoku, kobj)
/**
* sudoku_create_file - create sysfs attribute file for the given sudoku.
* @sudoku: sudoku
* @attr: sudoku attribute descriptor.
*/
int sudoku_create_file(struct sudoku *s,
const struct sudoku_attribute *attr)
struct ksudoku_attribute {
struct attribute attr;
ssize_t (*show)(struct ksudoku *s, struct ksudoku_attribute *attr,
char *buf);
ssize_t (*store)(struct ksudoku *s, struct ksudoku_attribute *attr,
const char *buf, size_t count);
bool value;
};
#define to_ksudoku_attr(_attr) container_of(_attr, struct ksudoku_attribute, attr)
/*
* The default show callback that is called by sysfs when ever a read
* operation happens on any attribute on ksudoku subsystem.
*/
static ssize_t ksudoku_default_attr_show(struct kobject *kobj,
struct attribute *attr,
char *buf)
{
int error = 0;
struct ksudoku_attribute *attribute;
struct ksudoku *sudoku;
if (s) {
WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
"Attribute %s: write permission without 'store'\n",
attr->attr.name);
WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
"Attribute %s: read permission without 'show'\n",
attr->attr.name);
error = sysfs_create_file(&s->kobj, &attr->attr);
}
attribute = to_ksudoku_attr(attr);
sudoku = to_ksudoku(kobj);
return error;
if (!attribute->show)
return -EIO;
return attribute->show(sudoku, attribute, buf);
}
EXPORT_SYMBOL_GPL(sudoku_create_file);
/* static ssize_t is_valid_show(struct kobject *kobj, struct attribute *attr, */
/* char *buf) */
/* { */
/* struct sudoku_attribute *s_attr = to_sudoku_attr(attr); */
/* struct sudoku *s = to_sudoku(kobj); */
/* ssize_t ret = -EIO; */
/*
* The default show callback that is called by sysfs when ever a write
* operation happens on any attribute on ksudoku subsystem.
*/
static ssize_t ksudoku_default_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf,
size_t len)
{
struct ksudoku_attribute *attribute;
struct ksudoku *sudoku;
/* if (s_attr->show) */
/* ret = s_attr->show(s, s_attr, buf); */
attribute = to_ksudoku_attr(attr);
sudoku = to_ksudoku(kobj);
/* if (ret >= (ssize_t)PAGE_SIZE) { */
/* printk("is_valid_show: %pS returned bad count\n", */
/* s_attr->show); */
/* } */
/* return ret; */
/* } */
if (!attribute->store)
return -EIO;
return attribute->store(sudoku, attribute, buf, len);
}
/*
* Create a `sysfs_ops` structure in order to register
* the default IO operation handlers of ksudoku subsystem.
*/
static const struct sysfs_ops ksudoku_sysfs_ops = {
.show = ksudoku_default_attr_show,
.store = ksudoku_default_attr_store,
};
/*
* The release function for ksudoku. This is REQUIRED by the kernel to
* have. We free the memory held in our object here.
*
* We should free the memory here rather than the exit method of the
* module. Kernel will call this function as soon as the reference
* counter on the kobject embedded inside the ksudoku object hits
* zero. So it might happen before or after exit function.
*
* The release function is per kobject so we're going to free
* different ksudoku instances separated from eachother.
*/
static void ksudoku_release(struct kobject *kobj)
{
struct ksudoku *s;
s = to_ksudoku(kobj);
kfree(s);
}
/*
* The show handler of `status` attribute. This callback will
* be called via `ksudoku_default_attr_show` which is the
* default read handler on ksudoku_type for ksudoku subsystem.
*
* Since `status` suppose to read only there would not be
* a store handler.
*/
static ssize_t status_show(struct ksudoku *s,
struct ksudoku_attribute *attr,
char *buf)
{
return sprintf(buf, "%d", atomic_read(&s->status));
}
// __ATTR_RO macro will set the `.show` member of
// `status_attribute` to `status_show` (name + _show)
static struct ksudoku_attribute status_attribute = __ATTR_RO(status);
static ssize_t matrix_show(struct ksudoku *s,
struct ksudoku_attribute *attr,
char *buf)
{
return sprintf(buf, "%s", s->matrix);
}
static ssize_t matrix_store(struct ksudoku *s,
struct ksudoku_attribute *attr,
const char *buf,
size_t len)
{
int status = atomic_read(&s->status);
if (status == KSUDOKU_BUSY)
return -EBUSY;
if (len != 81)
return -EIO;
strncpy(s->matrix, buf, len);
return len;
}
static struct ksudoku_attribute matrix_attribute =
__ATTR(matrix, 0664, matrix_show, matrix_store);
static struct attribute *ksudoku_default_attrs[] = {
&status_attribute.attr,
&matrix_attribute.attr,
NULL
};
ATTRIBUTE_GROUPS(ksudoku_default);
static struct kobj_type ksudoku_type = {
.sysfs_ops = &ksudoku_sysfs_ops,
.release = ksudoku_release,
.default_groups = ksudoku_default_groups,
};
static struct kset *ksudoku_set;
static struct ksudoku *create_ksudoku(const char *name)
{
struct ksudoku *s;
int result;
s = kzalloc(sizeof(*s), GFP_KERNEL);
if (!s)
return NULL;
s->kobj.kset = ksudoku_set;
result = kobject_init_and_add(&s->kobj, &ksudoku_type,
NULL, "%s", name);
if (result) {
kobject_put(&s->kobj);
return NULL;
}
atomic_set(&s->status, KSUDOKU_READY);
// Let the world now about the new registered kobj
kobject_uevent(&s->kobj, KOBJ_ADD);
return s;
}
static void destroy_ksudoku(struct ksudoku *s)
{
kobject_put(&s->kobj);
}
static int ksudoku_init(void)
{
printk(KERN_ALERT "Init ksudoku.\n");
printk(KERN_ALERT "Init ksudoku subsystem.\n");
// kernel_kobj is the kobject related to /sys/kernel
ksudoku_set = kset_create_and_add("ksudoku", NULL, kernel_kobj);
if (!ksudoku_set)
return -ENOMEM;
printk(KERN_ALERT "Ready to register sudokus.\n");
/* sudoku = kmalloc(sizeof (struct ksudoku), GFP_KERNEL); */
/* atomic_set(&sudoku->status, 0); */
/* sudoku->attr_group = &attr_group; */
/* if (!sudoku) */
/* return -ENOMEM; */
/* sudoku->kobj = kobject_create_and_add("ksudoku", kernel_kobj); */
/* if (!&sudoku->kobj) */
/* return -ENOMEM; */
/* sysfs_result = sysfs_create_group(sudoku->kobj, sudoku->attr_group); */
/* if (sysfs_result) */
/* kobject_put(sudoku->kobj); */
return 0;
}
static void ksudoku_exit(void)
{
//kobject_put(sudoku->kobj);
kset_unregister(ksudoku_set);
printk(KERN_ALERT "Exit ksudoku.\n");
}

View File

@ -1,36 +1,22 @@
#ifndef _KSUDOKU_H_
#define _KSUDOKU_H_
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sysfs.h>
#include <asm/atomic.h>
#define to_sudoku(obj) container_of(obj, struct sudoku, kobj)
#define to_sudoku_attr(_attr) container_of(_attr, struct sudoku_attribute, attr)
struct sudoku;
static ssize_t is_valid_show(struct kobject *kobj,
struct attribute *attr,
char *buf);
static ssize_t is_valid_store(struct kobject *,
struct attribute *,
const char *, size_t);
static ssize_t is_solved_show(struct kobject *kobj,
struct attribute *attr,
char *buf);
static ssize_t is_solved_store(struct kobject *,
struct attribute *,
const char *, size_t);
struct ksudoku;
#define to_ksudoku(obj) container_of(obj, struct ksudoku, kobj)
#define to_ksudoku_attr(_attr) container_of(_attr, struct kobj_attribute, attr)
struct sudoku_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
char *buf);
ssize_t (*store)(void);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
bool value;
};
@ -44,32 +30,25 @@ struct sudoku_attribute {
* If "name" is specified, the uevent will contain it in
* the DEVTYPE variable.
*/
struct sudoku_type {
const char *name;
const struct attribute_group **groups;
int (*uevent)(struct sudoku *s, struct kobj_uevent_env *env);
char *(*devnode)(struct sudoku *s, umode_t *mode,
kuid_t *uid, kgid_t *gid);
void (*release)(struct sudoku *s);
/* struct sudoku_type { */
/* const char *name; */
/* const struct attribute_group **groups; */
/* int (*uevent)(struct sudoku *s, struct kobj_uevent_env *env); */
/* void (*release)(struct kobject *kobj); */
/* const struct sysfs_ops *sysfs_ops; */
/* }; */
const struct sysfs_ops *sysfs_ops;
};
struct sudoku {
struct kobject kobj;
struct sudoku *parent;
const struct sudoku_type *type;
struct ksudoku {
struct kobject *kobj;
const struct attribute_group *attr_group;
char matrix[81];
};
atomic_t status;
} ;
#define SUDOKU_ATTR_RO(_name) \
struct sudoku_attribute sudoku_##_name = __ATTR_RO(_name)
struct kobj_attribute sudoku_##_name = __ATTR_RO(_name)
#define SUDOKU_ATTR_WO(_name) \
struct sudoku_attribute sudoku_##_name = __ATTR_WO(_name)
extern int sudoku_create_file(struct sudoku *s,
const struct sudoku_attribute *attr);
struct kobj_attribute sudoku_##_name = __ATTR_WO(_name)
#endif

View File

@ -1,2 +0,0 @@
/home/lxsameer/src/linux/ksudoku/ksudoku.o