Path: blob/main/sys/compat/linuxkpi/common/src/linux_simple_attr.c
39586 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2022, Jake Freeland <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/types.h>28#include <linux/fs.h>2930MALLOC_DEFINE(M_LSATTR, "simple_attr", "Linux Simple Attribute File");3132struct simple_attr {33int (*get)(void *, uint64_t *);34int (*set)(void *, uint64_t);35void *data;36const char *fmt;37struct mutex mutex;38};3940/*41* simple_attr_open: open and populate simple attribute data42*43* @inode: file inode44* @filp: file pointer45* @get: ->get() for reading file data46* @set: ->set() for writing file data47* @fmt: format specifier for data returned by @get48*49* Memory allocate a simple_attr and appropriately initialize its members.50* The simple_attr must be stored in filp->private_data.51* Simple attr files do not support seeking. Open the file as nonseekable.52*53* Return value: simple attribute file descriptor54*/55int56simple_attr_open(struct inode *inode, struct file *filp,57int (*get)(void *, uint64_t *), int (*set)(void *, uint64_t),58const char *fmt)59{60struct simple_attr *sattr;61sattr = malloc(sizeof(*sattr), M_LSATTR, M_ZERO | M_NOWAIT);62if (sattr == NULL)63return (-ENOMEM);6465sattr->get = get;66sattr->set = set;67sattr->data = inode->i_private;68sattr->fmt = fmt;69mutex_init(&sattr->mutex);7071filp->private_data = (void *) sattr;7273return (nonseekable_open(inode, filp));74}7576int77simple_attr_release(struct inode *inode, struct file *filp)78{79free(filp->private_data, M_LSATTR);80return (0);81}8283/*84* simple_attr_read: read simple attr data and transfer into buffer85*86* @filp: file pointer87* @buf: kernel space buffer88* @read_size: number of bytes to be transferred89* @ppos: starting pointer position for transfer90*91* The simple_attr structure is stored in filp->private_data.92* ->get() retrieves raw file data.93* The ->fmt specifier can format this data to be human readable.94* This output is then transferred into the @buf buffer.95*96* Return value:97* On success, number of bytes transferred98* On failure, negative signed ERRNO99*/100ssize_t101simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos)102{103struct simple_attr *sattr;104uint64_t data;105ssize_t ret;106char prebuf[24];107108sattr = filp->private_data;109110if (sattr->get == NULL)111return (-EFAULT);112113mutex_lock(&sattr->mutex);114115ret = sattr->get(sattr->data, &data);116if (ret)117goto unlock;118119scnprintf(prebuf, sizeof(prebuf), sattr->fmt, data);120121ret = strlen(prebuf) + 1;122if (*ppos >= ret || read_size < 1) {123ret = -EINVAL;124goto unlock;125}126127read_size = min(ret - *ppos, read_size);128ret = strscpy(buf, prebuf + *ppos, read_size);129130/* add 1 for null terminator */131if (ret > 0)132ret += 1;133134unlock:135mutex_unlock(&sattr->mutex);136return (ret);137}138139/*140* simple_attr_write_common: write contents of buffer into simple attribute file141*142* @filp: file pointer143* @buf: kernel space buffer144* @write_size: number bytes to be transferred145* @ppos: starting pointer position for transfer146* @is_signed: signedness of data in @buf147*148* The simple_attr structure is stored in filp->private_data.149* Convert the @buf string to unsigned long long.150* ->set() writes unsigned long long data into the simple attr file.151*152* Return value:153* On success, number of bytes written to simple attr154* On failure, negative signed ERRNO155*/156static ssize_t157simple_attr_write_common(struct file *filp, const char *buf, size_t write_size,158loff_t *ppos, bool is_signed)159{160struct simple_attr *sattr;161unsigned long long data;162size_t bufsize;163ssize_t ret;164165sattr = filp->private_data;166bufsize = strlen(buf) + 1;167168if (sattr->set == NULL)169return (-EFAULT);170171if (*ppos >= bufsize || write_size < 1)172return (-EINVAL);173174mutex_lock(&sattr->mutex);175176if (is_signed)177ret = kstrtoll(buf + *ppos, 0, &data);178else179ret = kstrtoull(buf + *ppos, 0, &data);180if (ret)181goto unlock;182183ret = sattr->set(sattr->data, data);184if (ret)185goto unlock;186187ret = bufsize - *ppos;188189unlock:190mutex_unlock(&sattr->mutex);191return (ret);192}193194ssize_t195simple_attr_write(struct file *filp, const char *buf, size_t write_size,196loff_t *ppos)197{198return (simple_attr_write_common(filp, buf, write_size, ppos, false));199}200201ssize_t202simple_attr_write_signed(struct file *filp, const char *buf, size_t write_size,203loff_t *ppos)204{205return (simple_attr_write_common(filp, buf, write_size, ppos, true));206}207208209