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 @@ -120,6 +120,7 @@ struct linux_file lf = {}; struct vnode vn; char *buf; + size_t buf_len; int rc; off_t off = 0; @@ -137,20 +138,19 @@ return (-rc); } - rc = -ENODEV; + buf = uio->uio_iov[0].iov_base; + + rc = -EIO; if (uio->uio_rw == UIO_READ && d->dm_fops->read) { - rc = -ENOMEM; - buf = (char *) malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT); - if (buf != NULL) { - rc = d->dm_fops->read(&lf, buf, sb->s_size, &off); - if (rc > 0) - sbuf_bcpy(sb, buf, strlen(buf)); - - free(buf, M_DFSINT); - } + buf_len = min(uio->uio_iov[0].iov_len, uio->uio_resid); + if ((rc = d->dm_fops->read(&lf, buf, buf_len, &off)) > 0) + sbuf_bcopyin(sb, buf, rc); } 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 ((rc = sbuf_finish(sb)) == 0) { + buf_len = sbuf_len(sb); + copyout(sbuf_data(sb), buf, buf_len); + rc = d->dm_fops->write(&lf, buf, buf_len, &off); + } } if (d->dm_fops->release) 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 @@ -54,12 +54,10 @@ sbuf = m->buf; p = m->op->start(m, ppos); - rc = m->op->show(m, p); - if (rc) + if ((rc = m->op->show(m, p))) return (rc); - rc = sbuf_finish(sbuf); - if (rc) + if ((rc = sbuf_finish(sbuf))) return (rc); rc = sbuf_len(sbuf); @@ -67,11 +65,7 @@ return (-EINVAL); size = min(rc - *ppos, size); - rc = strscpy(ubuf, sbuf_data(sbuf) + *ppos, size); - - /* add 1 for null terminator */ - if (rc > 0) - rc += 1; + rc = size - copy_to_user(ubuf, sbuf_data(sbuf) + *ppos, size); return (rc); } diff --git a/sys/compat/linuxkpi/common/src/linux_simple_attr.c b/sys/compat/linuxkpi/common/src/linux_simple_attr.c --- a/sys/compat/linuxkpi/common/src/linux_simple_attr.c +++ b/sys/compat/linuxkpi/common/src/linux_simple_attr.c @@ -36,6 +36,8 @@ struct simple_attr { int (*get)(void *, uint64_t *); int (*set)(void *, uint64_t); + char get_buf[24]; + char set_buf[24]; void *data; const char *fmt; struct mutex mutex; @@ -88,68 +90,66 @@ * simple_attr_read: read simple attr data and transfer into buffer * * @filp: file pointer - * @buf: kernel space buffer + * @ubuf: user 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. + * This output is then transferred into the @ubuf 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) +simple_attr_read(struct file *filp, char *ubuf, size_t read_size, loff_t *ppos) { struct simple_attr *sattr; uint64_t data; - ssize_t ret; - char prebuf[24]; + ssize_t bytes; + char *prebuf; sattr = filp->private_data; + prebuf = sattr->get_buf; if (sattr->get == NULL) return (-EFAULT); mutex_lock(&sattr->mutex); - ret = sattr->get(sattr->data, &data); - if (ret) + if ((bytes = sattr->get(sattr->data, &data))) goto unlock; - scnprintf(prebuf, sizeof(prebuf), sattr->fmt, data); + scnprintf(prebuf, sizeof(sattr->get_buf), sattr->fmt, data); - ret = strlen(prebuf) + 1; - if (*ppos >= ret || read_size < 1) { - ret = -EINVAL; + bytes = strlen(prebuf); + if (*ppos >= bytes || read_size < 1) { + bytes = -EINVAL; goto unlock; } - read_size = min(ret - *ppos, read_size); - ret = strscpy(buf, prebuf + *ppos, read_size); - - /* add 1 for null terminator */ - if (ret > 0) - ret += 1; + /* increment bytes for null terminator */ + read_size = min(++bytes - *ppos, read_size); + prebuf[read_size - 1] = '\0'; + bytes = read_size - copy_to_user(ubuf, prebuf + *ppos, read_size); unlock: mutex_unlock(&sattr->mutex); - return (ret); + return (bytes); } /* * simple_attr_write: write contents of buffer into simple attribute file * * @filp: file pointer - * @buf: kernel space buffer + * @ubuf: user 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. + * Convert the @ubuf string to unsigned long long. * ->set() writes unsigned long long data into the simple attr file. * * Return value: @@ -157,35 +157,34 @@ * On failure, negative signed ERRNO */ ssize_t -simple_attr_write(struct file *filp, const char *buf, size_t write_size, loff_t *ppos) +simple_attr_write(struct file *filp, const char *ubuf, size_t write_size, loff_t *ppos) { struct simple_attr *sattr; unsigned long long data; - size_t bufsize; - ssize_t ret; + ssize_t bytes; + char *prebuf; sattr = filp->private_data; - bufsize = strlen(buf) + 1; + prebuf = sattr->set_buf; if (sattr->set == NULL) return (-EFAULT); - if (*ppos >= bufsize || write_size < 1) - return (-EINVAL); - mutex_lock(&sattr->mutex); - ret = kstrtoull(buf + *ppos, 0, &data); - if (ret) + write_size = min(write_size, sizeof(sattr->set_buf)); + write_size -= copy_from_user(prebuf, ubuf + *ppos, write_size); + prebuf[write_size - 1] = '\0'; + + if ((bytes = kstrtoull(prebuf, 0, &data))) goto unlock; - ret = sattr->set(sattr->data, data); - if (ret) + if ((bytes = sattr->set(sattr->data, data))) goto unlock; - ret = bufsize - *ppos; + bytes = write_size; unlock: mutex_unlock(&sattr->mutex); - return (ret); + return (bytes); }