Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131490226
D35883.id108438.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D35883.id108438.diff
View Options
diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c
--- a/sys/compat/lindebugfs/lindebugfs.c
+++ b/sys/compat/lindebugfs/lindebugfs.c
@@ -69,9 +69,9 @@
#include <compat/linux/linux_util.h>
#include <fs/pseudofs/pseudofs.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
#include <linux/compat.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
@@ -117,48 +117,40 @@
debugfs_fill(PFS_FILL_ARGS)
{
struct dentry_meta *d;
- struct linux_file lf = {};
- struct seq_file *sf;
+ struct linux_file lf;
struct vnode vn;
- void *buf;
+ char buf[sb->s_size];
int rc;
- size_t len;
- off_t off;
-
- d = pn->pn_data;
+ off_t off = 0;
if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
return (rc);
+
+ d = pn->pn_data;
vn.v_data = d->dm_data;
- if (uio->uio_rw == UIO_READ) {
- buf = uio->uio_iov[0].iov_base;
- len = min(uio->uio_iov[0].iov_len, uio->uio_resid);
- } else {
- sbuf_finish(sb);
- buf = sbuf_data(sb);
- len = sbuf_len(sb);
- }
- off = 0;
+
+ /* seq_file requires sbuf for r/w */
+ lf.private_data = (void *) sb;
+
rc = d->dm_fops->open(&vn, &lf);
if (rc < 0) {
#ifdef INVARIANTS
printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
#endif
- return (-rc);
+ return (rc);
}
- sf = lf.private_data;
- sf->buf = sb;
- if (uio->uio_rw == UIO_READ) {
- if (d->dm_fops->read)
- rc = d->dm_fops->read(&lf, NULL, len, &off);
- else
- rc = -ENODEV;
- } else {
- if (d->dm_fops->write)
- rc = d->dm_fops->write(&lf, buf, len, &off);
- else
- rc = -ENODEV;
+
+ rc = -ENODEV;
+ if (uio->uio_rw == UIO_READ && d->dm_fops->read) {
+ buf[0] = '\0';
+ rc = d->dm_fops->read(&lf, buf, sizeof(buf), &off);
+ if (strlen(buf) > 0)
+ sbuf_bcpy(sb, buf, strlen(buf));
+ } else if (uio->uio_rw == UIO_WRITE && d->dm_fops->write) {
+ sbuf_finish(sb);
+ rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb), &off);
}
+
if (d->dm_fops->release)
d->dm_fops->release(&vn, &lf);
else
@@ -168,7 +160,7 @@
#ifdef INVARIANTS
printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
#endif
- return (-rc);
+ return (rc);
}
return (0);
}
@@ -321,4 +313,9 @@
#else
PSEUDOFS(debugfs, 1, VFCF_JAIL);
#endif
+
+/* Module specifications */
+static moduledata_t lindebugfs_data = { "lindebugfs", NULL, NULL };
+DECLARE_MODULE(lindebugfs, lindebugfs_data, SI_SUB_EXEC, SI_ORDER_MIDDLE);
+MODULE_VERSION(lindebugfs, 1);
MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
diff --git a/sys/compat/linuxkpi/common/include/linux/dcache.h b/sys/compat/linuxkpi/common/include/linux/dcache.h
--- a/sys/compat/linuxkpi/common/include/linux/dcache.h
+++ b/sys/compat/linuxkpi/common/include/linux/dcache.h
@@ -29,8 +29,9 @@
#ifndef _LINUXKPI_LINUX_DCACHE_H
#define _LINUXKPI_LINUX_DCACHE_H
-struct vnode;
-struct pfs_node;
+#include <sys/vnode.h>
+
+#include <fs/pseudofs/pseudofs.h>
struct dentry {
struct vnode *d_inode;
diff --git a/sys/compat/linuxkpi/common/include/linux/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h
--- a/sys/compat/linuxkpi/common/include/linux/debugfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h
@@ -31,10 +31,22 @@
#define _LINUXKPI_LINUX_DEBUGFS_H_
#include <linux/fs.h>
+#include <linux/module.h>
#include <linux/seq_file.h>
-
#include <linux/types.h>
+MALLOC_DECLARE(M_DFSINT);
+
+struct debugfs_reg32 {
+ char *name;
+ unsigned long offset;
+};
+
+struct debugfs_regset32 {
+ const struct debugfs_reg32 *regs;
+ int nregs;
+};
+
void debugfs_remove(struct dentry *dentry);
struct dentry *debugfs_create_file(const char *name, umode_t mode,
@@ -48,4 +60,186 @@
void debugfs_remove_recursive(struct dentry *dentry);
-#endif
+/*
+ * debugfs_create_file_unsafe: create a new debugfs file with given file
+ * attributes
+ *
+ * @name: file name
+ * @mode: file permissions
+ * @parent: parent dentry
+ * @data: file data
+ * @fops: file operations
+ *
+ * Create a new debugfs file with given arguments.
+ *
+ * NOTE: the _unsafe moniker denotes that @fops are not protected against debugfs
+ * file removals. This behavior is not implemented in FreeBSD at this time.
+ *
+ * Return: new file dentry pointer
+ */
+static inline struct dentry *
+debugfs_create_file_unsafe(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops)
+{
+ return (debugfs_create_file(name, mode, parent, data, fops));
+}
+
+/*
+ * debugfs_create_mode_unsafe: create a new debugfs file with file operations
+ * dependent on @mode
+ *
+ * @name: file name
+ * @mode: file permissions
+ * @parent: parent dentry
+ * @data: file data
+ * @fops: file operations
+ * @fops_ro: read only file operations
+ * @fops_wo: write only file operations
+ *
+ * Create a new debugfs file with given arguments. Care should be taken
+ * when &ing S_IWUGO and S_IRUGO with @mode to see if r/w bits are set.
+ * Use the correct file operations based on those r/w bits. If both r/w
+ * bits are set, use @fops as file operations.
+ *
+ * Return: new file dentry pointer
+ */
+static inline struct dentry *
+debugfs_create_mode_unsafe(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ const struct file_operations *fops_ro,
+ const struct file_operations *fops_wo)
+{
+ umode_t read = mode & S_IRUGO;
+ umode_t write = mode & S_IWUGO;
+
+ if (read && !write)
+ return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
+
+ if (write && !read)
+ return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
+
+ return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
+}
+
+#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
+static inline int \
+__fops ## _open(struct inode *inode, struct file *filp) \
+{ \
+ return (simple_attr_open(inode, filp, __get, __set, __fmt)); \
+} \
+static const struct file_operations __fops = { \
+ .owner = THIS_MODULE, \
+ .open = __fops ## _open, \
+ .release = simple_attr_release, \
+ .read = debugfs_attr_read, \
+ .write = debugfs_attr_write, \
+ .llseek = no_llseek \
+}
+
+static inline ssize_t
+debugfs_attr_read(struct file *filp, char __user *buf,
+ size_t read_size, loff_t *ppos)
+{
+ return (simple_attr_read(filp, buf, read_size, ppos));
+}
+
+static inline ssize_t
+debugfs_attr_write(struct file *filp, const char __user *buf,
+ size_t write_size, loff_t *ppos)
+{
+ return (simple_attr_write(filp, buf, write_size, ppos));
+}
+
+static inline ssize_t
+debugfs_read_file_bool(struct file *filp, char __user *user_buf,
+ size_t read_size, loff_t *ppos)
+{
+ bool *value;
+ char *buf;
+
+ value = filp->private_data;
+ if (*value)
+ buf = "Y\n";
+ else
+ buf = "N\n";
+
+ return (simple_read_from_buffer(user_buf, read_size, ppos, buf, 2));
+}
+
+static inline ssize_t
+debugfs_write_file_bool(struct file *filp, const char __user *user_buf,
+ size_t write_size, loff_t *ppos)
+{
+ ssize_t ret;
+ bool *dest = filp->private_data;
+ bool value;
+
+ ret = kstrtobool_from_user(user_buf, write_size, &value);
+ if (ret)
+ return (ret);
+
+ *dest = value;
+
+ return (write_size);
+}
+
+static const struct file_operations fops_bool = {
+ .read = debugfs_read_file_bool,
+ .write = debugfs_write_file_bool,
+ .open = simple_open,
+ .llseek = no_llseek
+};
+
+static const struct file_operations fops_bool_ro = {
+ .read = debugfs_read_file_bool,
+ .open = simple_open,
+ .llseek = no_llseek
+};
+
+static const struct file_operations fops_bool_wo = {
+ .write = debugfs_write_file_bool,
+ .open = simple_open,
+ .llseek = no_llseek
+};
+
+static inline void
+debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent,
+ bool *value)
+{
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
+ &fops_bool_ro, &fops_bool_wo);
+ return;
+}
+
+static inline int
+debugfs_ulong_set(void *data, uint64_t value)
+{
+ uint64_t *ludata = data;
+ *ludata = value;
+ return (0);
+}
+
+static inline int
+debugfs_ulong_get(void *data, uint64_t *value)
+{
+ uint64_t *ludata = data;
+ *value = *ludata;
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
+
+static inline void
+debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent,
+ unsigned long *value)
+{
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
+ &fops_ulong_ro, &fops_ulong_wo);
+ return;
+}
+
+#endif /* _LINUXKPI_LINUX_DEBUGFS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
--- a/sys/compat/linuxkpi/common/include/linux/fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -45,6 +45,8 @@
#include <linux/dcache.h>
#include <linux/capability.h>
#include <linux/wait_bit.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
struct module;
struct kiocb;
@@ -250,6 +252,7 @@
static inline int
simple_open(struct inode *inode, struct file *filp)
{
+ filp->private_data = inode->i_private;
return 0;
}
@@ -296,6 +299,7 @@
return (-ESPIPE);
}
+#define default_llseek no_llseek
static inline loff_t
noop_llseek(struct linux_file *file, loff_t offset, int whence)
@@ -318,4 +322,76 @@
return (file->f_op->mmap(file, vma));
}
+static inline void
+i_size_write(struct inode *inode, loff_t i_size)
+{
+ /* inode->i_size = i_size; */
+ return;
+}
+
+/*
+ * simple_read_from_buffer: copy data from kernel-space origin
+ * buffer into user-space destination buffer
+ *
+ * @dest: destination buffer
+ * @read_size: number of bytes to be transferred
+ * @ppos: starting transfer position pointer
+ * @orig: origin buffer
+ * @buf_size: size of destination and origin buffers
+ *
+ * Return value:
+ * On success, total bytes copied with *ppos incremented accordingly.
+ * On failure, negative value.
+ */
+static inline ssize_t
+simple_read_from_buffer(void __user *dest, size_t read_size, loff_t *ppos,
+ void *orig, size_t buf_size)
+{
+ void *read_pos = ((char *) orig) + *ppos;
+ size_t buf_remain = buf_size - *ppos;
+ ssize_t num_read;
+
+ if (buf_remain < 0 || buf_remain > buf_size)
+ return -EINVAL;
+
+ if (read_size > buf_remain)
+ read_size = buf_remain;
+
+ /* copy_to_user returns number of bytes NOT read */
+ num_read = read_size - copy_to_user(dest, read_pos, read_size);
+ if (num_read == 0)
+ return -EFAULT;
+ *ppos += num_read;
+
+ return (num_read);
+}
+
+MALLOC_DECLARE(M_LSATTR);
+
+#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
+static inline int \
+__fops ## _open(struct inode *inode, struct file *filp) \
+{ \
+ return (simple_attr_open(inode, filp, __get, __set, __fmt)); \
+} \
+static const struct file_operations __fops = { \
+ .owner = THIS_MODULE, \
+ .open = __fops ## _open, \
+ .release = simple_attr_release, \
+ .read = simple_attr_read, \
+ .write = simple_attr_write, \
+ .llseek = no_llseek \
+}
+
+int simple_attr_open(struct inode *inode, struct file *filp,
+ int (*get)(void *, uint64_t *), int (*set)(void *, uint64_t),
+ const char *fmt);
+
+int simple_attr_release(struct inode *inode, struct file *filp);
+
+ssize_t simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos);
+
+ssize_t simple_attr_write(struct file *filp, const char __user *buf,
+ size_t write_size, loff_t *ppos);
+
#endif /* _LINUXKPI_LINUX_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -32,11 +32,12 @@
#include <linux/types.h>
#include <linux/fs.h>
-#include <sys/sbuf.h>
#undef file
#define inode vnode
+MALLOC_DECLARE(M_LSEQ);
+
#define DEFINE_SHOW_ATTRIBUTE(__name) \
static int __name ## _open(struct inode *inode, struct linux_file *file) \
{ \
@@ -51,11 +52,8 @@
.release = single_release, \
}
-struct seq_operations;
-
struct seq_file {
- struct sbuf *buf;
-
+ struct sbuf *buf;
const struct seq_operations *op;
const struct linux_file *file;
void *private;
@@ -78,7 +76,8 @@
int single_open(struct linux_file *, int (*)(struct seq_file *, void *), void *);
int single_release(struct inode *, struct linux_file *);
-#define seq_printf(m, fmt, ...) sbuf_printf((m)->buf, (fmt), ##__VA_ARGS__)
+void seq_vprintf(struct seq_file *m, const char *fmt, va_list args);
+void seq_printf(struct seq_file *m, const char *fmt, ...);
#define seq_puts(m, str) sbuf_printf((m)->buf, str)
#define seq_putc(m, str) sbuf_putc((m)->buf, str)
diff --git a/sys/compat/linuxkpi/common/include/linux/string.h b/sys/compat/linuxkpi/common/include/linux/string.h
--- a/sys/compat/linuxkpi/common/include/linux/string.h
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -97,6 +97,20 @@
return (dst);
}
+static inline char *
+strndup_user(const char __user *ustr, long n)
+{
+ char *kstr;
+
+ kstr = memdup_user(ustr, n);
+ if (IS_ERR(kstr))
+ return kstr;
+
+ kstr[n-1] = '\0';
+
+ return (kstr);
+}
+
static inline char *
kstrdup(const char *string, gfp_t gfp)
{
diff --git a/sys/compat/linuxkpi/common/src/linux_seq_file.c b/sys/compat/linuxkpi/common/src/linux_seq_file.c
--- a/sys/compat/linuxkpi/common/src/linux_seq_file.c
+++ b/sys/compat/linuxkpi/common/src/linux_seq_file.c
@@ -48,9 +48,8 @@
struct seq_file *m = f->private_data;
void *p;
int rc;
- off_t pos = 0;
- p = m->op->start(m, &pos);
+ p = m->op->start(m, ppos);
rc = m->op->show(m, p);
if (rc)
return (rc);
@@ -101,15 +100,20 @@
{
struct seq_file *p;
- if (f->private_data != NULL)
- log(LOG_WARNING, "%s private_data not NULL", __func__);
-
if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL)
return (-ENOMEM);
- f->private_data = p;
+ /*
+ * This seq_file's ->buf is passed in through f->private_data.
+ * A clean seq_file implementation is needed to remove the
+ * FreeBSD sbuf dependency.
+ */
+ if (f->private_data != NULL)
+ p->buf = (struct sbuf *) f->private_data;
+
p->op = op;
p->file = f;
+ f->private_data = (void *) p;
return (0);
}
@@ -160,3 +164,22 @@
free(__DECONST(void *, op), M_LSEQ);
return (rc);
}
+
+void
+seq_vprintf(struct seq_file *m, const char *fmt, va_list args)
+{
+ sbuf_vprintf(m->buf, fmt, args);
+ return;
+}
+
+void
+seq_printf(struct seq_file *m, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ seq_vprintf(m, fmt, args);
+ va_end(args);
+
+ return;
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_simple_attr.c b/sys/compat/linuxkpi/common/src/linux_simple_attr.c
new file mode 100644
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_simple_attr.c
@@ -0,0 +1,195 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022, Jake Freeland <jfree@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <linux/fs.h>
+
+MALLOC_DEFINE(M_LSATTR, "simple_attr", "Linux Simple Attribute File");
+
+struct simple_attr {
+ int (*get)(void *, uint64_t *);
+ int (*set)(void *, uint64_t);
+ void *data;
+ const char *fmt;
+ struct mutex mutex;
+};
+
+/*
+ * simple_attr_open: open and populate simple attribute data
+ *
+ * @inode: file inode
+ * @filp: file pointer
+ * @get: ->get() for reading file data
+ * @set: ->set() for writing file data
+ * @fmt: format specifier for data returned by @get
+ *
+ * Memory allocate a simple_attr and appropriately initialize its members.
+ * The simple_attr must be stored in filp->private_data.
+ * Simple attr files do not support seeking. Open the file as nonseekable.
+ *
+ * Return value: simple attribute file descriptor
+ */
+int
+simple_attr_open(struct inode *inode, struct file *filp,
+ int (*get)(void *, uint64_t *), int (*set)(void *, uint64_t),
+ const char *fmt)
+{
+ struct simple_attr *sattr;
+ sattr = malloc(sizeof(*sattr), M_LSATTR, M_ZERO | M_NOWAIT);
+ if (sattr == NULL)
+ return (-ENOMEM);
+
+ sattr->get = get;
+ sattr->set = set;
+ sattr->data = inode->i_private;
+ sattr->fmt = fmt;
+ mutex_init(&sattr->mutex);
+
+ filp->private_data = (void *) sattr;
+
+ return (nonseekable_open(inode, filp));
+}
+
+/*
+ * simple_attr_release: release file's simple attribute data
+ *
+ * @inode: file inode
+ * @filp: file pointer
+ *
+ * Return value: 0
+ */
+int
+simple_attr_release(struct inode *inode, struct file *filp)
+{
+ free(filp->private_data, M_LSATTR);
+ return (0);
+}
+
+/*
+ * simple_attr_read: read simple attr data and transfer into buffer
+ *
+ * @filp: file pointer
+ * @buf: kernel space buffer
+ * @read_size: number of bytes to be transferred
+ * @ppos: starting pointer position for transfer
+ *
+ * The simple_attr structure is stored in filp->private_data.
+ * ->get() retrieves raw file data.
+ * The ->fmt specifier can format this data to be human readable.
+ * This output is then transferred into the @buf buffer.
+ *
+ * Return value:
+ * On success, number of bytes transferred
+ * On failure, negative signed ERRNO
+ */
+ssize_t
+simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos)
+{
+ struct simple_attr *sattr;
+ uint64_t data;
+ ssize_t ret;
+ char prebuf[24];
+
+ sattr = filp->private_data;
+
+ if (sattr->get == NULL)
+ return (-EFAULT);
+
+ if (*ppos > sizeof(prebuf))
+ return (-EINVAL);
+
+ mutex_lock(&sattr->mutex);
+
+ ret = sattr->get(sattr->data, &data);
+ if (ret)
+ goto unlock;
+
+ scnprintf(prebuf, sizeof(prebuf), sattr->fmt, data);
+ read_size = min((strlen(prebuf) + 1) - *ppos, read_size);
+ ret = strscpy(buf, prebuf + *ppos, read_size);
+
+ /* add 1 for null terminator */
+ if (ret > 0)
+ ret += 1;
+
+unlock:
+ mutex_unlock(&sattr->mutex);
+ return (ret);
+}
+
+/*
+ * simple_attr_write: write contents of buffer into simple attribute file
+ *
+ * @filp: file pointer
+ * @buf: kernel space buffer
+ * @write_size: number bytes to be transferred
+ * @ppos: starting pointer position for transfer
+ *
+ * The simple_attr structure is stored in filp->private_data.
+ * Convert the @buf string to unsigned long long.
+ * ->set() writes unsigned long long data into the simple attr file.
+ *
+ * Return value:
+ * On success, number of bytes written to simple attr
+ * On failure, negative signed ERRNO
+ */
+ssize_t
+simple_attr_write(struct file *filp, const char __user *buf,
+ size_t write_size, loff_t *ppos)
+{
+ struct simple_attr *sattr;
+ unsigned long long data;
+ ssize_t ret;
+
+ sattr = filp->private_data;
+
+ if (sattr->set == NULL)
+ return (-EFAULT);
+
+ if (*ppos > sizeof(data))
+ return (-EINVAL);
+
+ mutex_lock(&sattr->mutex);
+
+ ret = kstrtoull(buf + *ppos, 0, &data);
+ if (ret)
+ goto unlock;
+
+ ret = sattr->set(sattr->data, data);
+ if (ret)
+ goto unlock;
+
+ ret = strlen(buf) - *ppos;
+
+unlock:
+ mutex_unlock(&sattr->mutex);
+ return (ret);
+}
+
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4604,9 +4604,10 @@
compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/lkpi_iic_if.m optional compat_linuxkpi
-compat/linuxkpi/common/src/linux_seq_file.c optional compat_linuxkpi | lindebugfs \
+compat/linuxkpi/common/src/linux_seq_file.c optional compat_linuxkpi | lindebugfs \
+ compile-with "${LINUXKPI_C}"
+compat/linuxkpi/common/src/linux_simple_attr.c optional compat_linuxkpi | lindebugfs \
compile-with "${LINUXKPI_C}"
-
compat/lindebugfs/lindebugfs.c optional lindebugfs \
compile-with "${LINUXKPI_C}"
diff --git a/sys/modules/linuxkpi/Makefile b/sys/modules/linuxkpi/Makefile
--- a/sys/modules/linuxkpi/Makefile
+++ b/sys/modules/linuxkpi/Makefile
@@ -22,10 +22,11 @@
linux_pci.c \
linux_radix.c \
linux_rcu.c \
- linux_seq_file.c \
linux_schedule.c \
+ linux_seq_file.c \
linux_shmemfs.c \
linux_shrinker.c \
+ linux_simple_attr.c \
linux_skbuff.c \
linux_slab.c \
linux_tasklet.c \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Oct 9, 1:46 PM (21 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23497935
Default Alt Text
D35883.id108438.diff (21 KB)
Attached To
Mode
D35883: LinuxKPI drm-kmod debugfs support
Attached
Detach File
Event Timeline
Log In to Comment