runtime/procfs-probes.c - systemtap
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
#ifndef _STP_PROCFS_PROBES_C_
#define _STP_PROCFS_PROBES_C_
#include <linux/mutex.h>
#include <linux/fs.h>
#include <linux/sched.h>
#if 0
#endif
struct stap_procfs_probe {
const char *path;
const struct stap_probe * const read_probe;
const struct stap_probe * const write_probe;
char *buffer;
const size_t bufsize;
size_t count;
int needs_fill;
const int permissions;
struct mutex lock;
int opencount;
wait_queue_head_t waitq;
};
static inline void _spp_init(struct stap_procfs_probe *spp)
{
init_waitqueue_head(&spp->waitq);
spp->opencount = 0;
mutex_init(&spp->lock);
}
#define _spp_lock(spp) mutex_lock(&(spp)->lock)
#define _spp_unlock(spp) mutex_unlock(&(spp)->lock)
#define _spp_shutdown(spp) mutex_destroy(&(spp)->lock)
static int _stp_proc_fill_read_buffer(struct stap_procfs_probe *spp);
static int _stp_process_write_buffer(struct stap_procfs_probe *spp,
const char __user *buf, size_t count);
static int
_stp_proc_open_file(struct inode *inode, struct file *filp)
{
struct stap_procfs_probe *spp;
int res;
spp = (struct stap_procfs_probe *)PDE_DATA(inode);
if (spp == NULL) {
return -EINVAL;
}
res = generic_file_open(inode, filp);
if (res)
return res;
_spp_lock(spp);
if (spp->opencount == 0) {
res = 0;
}
else if (filp->f_flags & O_NONBLOCK) {
res = -EAGAIN;
}
else {
for (res = 0;;) {
if (spp->opencount == 0) {
res = 0;
break;
}
_spp_unlock(spp);
res = wait_event_interruptible(spp->waitq,
spp->opencount == 0);
_spp_lock(spp);
if (res < 0)
break;
}
}
if (likely(res == 0)) {
spp->opencount++;
filp->private_data = spp;
if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
spp->buffer[0] = '\0';
spp->count = 0;
spp->needs_fill = 1;
}
}
_spp_unlock(spp);
return 0;
}
static int
_stp_proc_release_file(struct inode *inode, struct file *filp)
{
struct stap_procfs_probe *spp;
spp = (struct stap_procfs_probe *)filp->private_data;
if (spp != NULL) {
_spp_lock(spp);
spp->opencount--;
_spp_unlock(spp);
wake_up(&spp->waitq);
}
return 0;
}
static ssize_t
_stp_proc_read_file(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct stap_procfs_probe *spp = file->private_data;
ssize_t retval = 0;
if (spp == NULL || spp->read_probe == NULL) {
goto out;
}
if (spp->needs_fill) {
if ((retval = _stp_proc_fill_read_buffer(spp))) {
goto out;
}
}
retval = simple_read_from_buffer(buf, count, ppos, spp->buffer,
spp->count);
out:
return retval;
}
static ssize_t
_stp_proc_write_file(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
struct stap_procfs_probe *spp = file->private_data;
struct _stp_procfs_data pdata;
ssize_t len;
if (spp->write_probe == NULL) {
len = -EIO;
goto out;
}
len = _stp_process_write_buffer(spp, buf, count);
if (len > 0) {
*ppos += len;
}
out:
return len;
}
static struct file_operations _stp_proc_fops = {
.owner = THIS_MODULE,
.open = _stp_proc_open_file,
.read = _stp_proc_read_file,
.write = _stp_proc_write_file,
.llseek = generic_file_llseek,
.release = _stp_proc_release_file,
};
#endif