/** * flush_write_buffer - push buffer to kobject * @of: open file * @buf: data buffer for file * @off: file offset to write to * @count: number of bytes * * Get the correct pointers for the kobject and the attribute we're dealing * with, then call the store() method for it with @buf. */ static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off, size_t count) { struct kobject *kobj = of->sd->s_parent->s_dir.kobj; int rc = 0; /* * Need @of->sd for attr and ops, its parent for kobj. @of->mutex * nests outside active ref and is just to ensure that the ops * aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); if (!sysfs_get_active(of->sd)) { mutex_unlock(&of->mutex); return -ENODEV; } if (sysfs_is_bin(of->sd)) { struct bin_attribute *battr = of->sd->s_attr.bin_attr; rc = -EIO; if (battr->write) rc = battr->write(of->file, kobj, battr, buf, off, count); } else { const struct sysfs_ops *ops = sysfs_file_ops(of->sd); rc = ops->store(kobj, of->sd->s_attr.attr, buf, count); } sysfs_put_active(of->sd); mutex_unlock(&of->mutex); return rc; }
/* * Reads on sysfs are handled through seq_file, which takes care of hairy * details like buffering and seeking. The following function pipes * sysfs_ops->show() result through seq_file. */ static int sysfs_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; struct kobject *kobj = of->sd->s_parent->s_dir.kobj; const struct sysfs_ops *ops; char *buf; ssize_t count; /* acquire buffer and ensure that it's >= PAGE_SIZE */ count = seq_get_buf(sf, &buf); if (count < PAGE_SIZE) { seq_commit(sf, -1); return 0; } /* * Need @of->sd for attr and ops, its parent for kobj. @of->mutex * nests outside active ref and is just to ensure that the ops * aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); if (!sysfs_get_active(of->sd)) { mutex_unlock(&of->mutex); return -ENODEV; } of->event = atomic_read(&of->sd->s_attr.open->event); /* * Lookup @ops and invoke show(). Control may reach here via seq * file lseek even if @ops->show() isn't implemented. */ ops = sysfs_file_ops(of->sd); if (ops->show) count = ops->show(kobj, of->sd->s_attr.attr, buf); else count = 0; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); if (count < 0) return count; /* * The code works fine with PAGE_SIZE return but it's likely to * indicate truncated result or overflow in normal use cases. */ if (count >= (ssize_t)PAGE_SIZE) { print_symbol("fill_read_buffer: %s returned bad count\n", (unsigned long)ops->show); /* Try to struggle along */ count = PAGE_SIZE - 1; } seq_commit(sf, count); return 0; }
/* kernfs write callback for regular sysfs files */ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { const struct sysfs_ops *ops = sysfs_file_ops(of->kn); struct kobject *kobj = of->kn->parent->priv; if (!count) return 0; return ops->store(kobj, of->kn->priv, buf, count); }
/* kernfs read callback for regular sysfs files with pre-alloc */ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { const struct sysfs_ops *ops = sysfs_file_ops(of->kn); struct kobject *kobj = of->kn->parent->priv; /* * If buf != of->prealloc_buf, we don't know how * large it is, so cannot safely pass it to ->show */ if (pos || WARN_ON_ONCE(buf != of->prealloc_buf)) return 0; return ops->show(kobj, of->kn->priv, buf); }
/* * Reads on sysfs are handled through seq_file, which takes care of hairy * details like buffering and seeking. The following function pipes * sysfs_ops->show() result through seq_file. */ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) { struct kernfs_open_file *of = sf->private; struct kobject *kobj = of->kn->parent->priv; const struct sysfs_ops *ops = sysfs_file_ops(of->kn); ssize_t count; char *buf; /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */ count = seq_get_buf(sf, &buf); if (count < PAGE_SIZE) { seq_commit(sf, -1); return 0; } memset(buf, 0, PAGE_SIZE); /* * Invoke show(). Control may reach here via seq file lseek even * if @ops->show() isn't implemented. */ if (ops->show) { count = ops->show(kobj, of->kn->priv, buf); if (count < 0) return count; } /* * The code works fine with PAGE_SIZE return but it's likely to * indicate truncated result or overflow in normal use cases. */ if (count >= (ssize_t)PAGE_SIZE) { print_symbol("fill_read_buffer: %s returned bad count\n", (unsigned long)ops->show); /* Try to struggle along */ count = PAGE_SIZE - 1; } seq_commit(sf, count); return 0; }