summaryrefslogtreecommitdiffstats
path: root/runtime/transport/procfs.c
diff options
context:
space:
mode:
authorhunt <hunt>2007-10-12 19:46:35 +0000
committerhunt <hunt>2007-10-12 19:46:35 +0000
commit77d33bd4cb539f4dbd8e1e3af930d9369daa6e81 (patch)
tree4cce902c90624e8286ff6e010eec2492ce704db7 /runtime/transport/procfs.c
parent2972246a08bfc7c516455ecc4ef976e10c0ddb2c (diff)
downloadsystemtap-steved-77d33bd4cb539f4dbd8e1e3af930d9369daa6e81.tar.gz
systemtap-steved-77d33bd4cb539f4dbd8e1e3af930d9369daa6e81.tar.xz
systemtap-steved-77d33bd4cb539f4dbd8e1e3af930d9369daa6e81.zip
2007-10-12 Martin Hunt <hunt@redhat.com>
* transport.c (_stp_ask_for_symbols): Don't ask for transport_info yet. Need to wait until symbols are received. (_stp_work_queue): Rename _stp_ready_q to _stp_ctl_ready_q. * procfs.c: Create a ".symbols" channel and use it for STP_MODULE and STP_SYMBOLS. Rename "cmd" channel to ".cmd". * control.c: Ditto.
Diffstat (limited to 'runtime/transport/procfs.c')
-rw-r--r--runtime/transport/procfs.c299
1 files changed, 250 insertions, 49 deletions
diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c
index be672825..88740847 100644
--- a/runtime/transport/procfs.c
+++ b/runtime/transport/procfs.c
@@ -12,10 +12,12 @@
#define STP_DEFAULT_BUFFERS 256
static int _stp_current_buffers = STP_DEFAULT_BUFFERS;
-static struct list_head _stp_ready_q;
+static struct list_head _stp_ctl_ready_q;
+static struct list_head _stp_sym_ready_q;
static struct list_head _stp_pool_q;
spinlock_t _stp_pool_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t _stp_ready_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_ctl_ready_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t _stp_sym_ready_lock = SPIN_LOCK_UNLOCKED;
#ifdef STP_BULKMODE
extern int _stp_relay_flushing;
@@ -63,11 +65,10 @@ static struct file_operations _stp_proc_fops = {
};
#endif /* STP_BULKMODE */
-static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int type;
- static int started = 0, initialized = 0;
if (count < sizeof(int))
return 0;
@@ -75,7 +76,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
if (get_user(type, (int __user *)buf))
return -EFAULT;
- //printk ("_stp_proc_write_cmd. count:%d type:%d\n", count, type);
+ kbug ("count:%d type:%d\n", (int)count, type);
if (type == STP_SYMBOLS) {
count -= sizeof(long);
@@ -86,8 +87,45 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
}
switch (type) {
+ case STP_SYMBOLS:
+
+ if (count)
+ count = _stp_do_symbols(buf, count);
+ break;
+ case STP_MODULE:
+ if (count)
+ count = _stp_do_module(buf, count);
+ else {
+ /* count == 0 indicates end of initial modules list */
+ _stp_ctl_send(STP_TRANSPORT, NULL, 0);
+ }
+ break;
+ default:
+ errk ("invalid symbol command type %d\n", type);
+ return -EINVAL;
+ }
+
+ return count;
+}
+static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int type;
+ static int started = 0;
+
+ if (count < sizeof(int))
+ return 0;
+
+ if (get_user(type, (int __user *)buf))
+ return -EFAULT;
+
+ // kbug ("count:%d type:%d\n", count, type);
+
+ count -= sizeof(int);
+ buf += sizeof(int);
+
+ switch (type) {
case STP_START:
- {
if (started == 0) {
struct _stp_msg_start st;
if (count < sizeof(st))
@@ -98,20 +136,6 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
started = 1;
}
break;
- }
-
- case STP_SYMBOLS:
- if (initialized == 0 && count && current->pid == _stp_init_pid)
- count = _stp_do_symbols(buf, count);
- break;
- case STP_MODULE:
- if (initialized == 0 && current->pid == _stp_init_pid) {
- if (count)
- count = _stp_do_module(buf, count);
- else
- initialized = 1;
- }
- break;
case STP_EXIT:
_stp_exit_flag = 1;
break;
@@ -131,6 +155,52 @@ struct _stp_buffer {
};
static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
+static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq);
+
+#ifdef DEBUG
+static void _stp_ctl_write_dbug (int type, void *data, int len)
+{
+ char buf[64];
+ switch (type) {
+ case STP_REALTIME_DATA:
+ break;
+ case STP_START:
+ printk("_stp_ctl_write: sending STP_START\n");
+ break;
+ case STP_EXIT:
+ printk("_stp_ctl_write: sending STP_EXIT\n");
+ break;
+ case STP_OOB_DATA:
+ snprintf(buf, sizeof(buf), "%s", (char *)data);
+ printk("_stp_ctl_write: sending %d bytes of STP_OOB_DATA: %s\n", len, buf);
+ break;
+ case STP_SYSTEM:
+ snprintf(buf, sizeof(buf), "%s", (char *)data);
+ printk("_stp_ctl_write: sending STP_SYSTEM: %s\n", buf);
+ break;
+ case STP_TRANSPORT:
+ printk("_stp_ctl_write: sending STP_TRANSPORT\n");
+ break;
+ default:
+ printk("_stp_ctl_write: ERROR: unknown message type: %d\n", type);
+ break;
+ }
+}
+static void _stp_sym_write_dbug (int type, void *data, int len)
+{
+ switch (type) {
+ case STP_SYMBOLS:
+ printk("_stp_sym_write: sending STP_SYMBOLS\n");
+ break;
+ case STP_MODULE:
+ printk("_stp_sym_write: sending STP_MODULE\n");
+ break;
+ default:
+ printk("_stp_sym_write: ERROR: unknown message type: %d\n", type);
+ break;
+ }
+}
+#endif
static int _stp_ctl_write (int type, void *data, int len)
{
@@ -138,27 +208,31 @@ static int _stp_ctl_write (int type, void *data, int len)
unsigned long flags;
unsigned numtrylock;
+#ifdef DEBUG
+ _stp_ctl_write_dbug(type, data, len);
+#endif
+
#define WRITE_AGG
#ifdef WRITE_AGG
numtrylock = 0;
- while (!spin_trylock_irqsave (&_stp_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
+ while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- if (!list_empty(&_stp_ready_q)) {
- bptr = (struct _stp_buffer *)_stp_ready_q.prev;
+ if (!list_empty(&_stp_ctl_ready_q)) {
+ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.prev;
if (bptr->len + len <= STP_BUFFER_SIZE
&& type == STP_REALTIME_DATA
&& bptr->type == STP_REALTIME_DATA) {
memcpy (bptr->buf + bptr->len, data, len);
bptr->len += len;
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
return len;
}
}
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
#endif
/* make sure we won't overflow the buffer */
@@ -171,8 +245,9 @@ static int _stp_ctl_write (int type, void *data, int len)
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- if (list_empty(&_stp_pool_q)) {
+ if (unlikely(list_empty(&_stp_pool_q))) {
spin_unlock_irqrestore(&_stp_pool_lock, flags);
+ dbug("_stp_pool_q empty\n");
return -1;
}
@@ -187,12 +262,54 @@ static int _stp_ctl_write (int type, void *data, int len)
/* put it on the pool of ready buffers */
numtrylock = 0;
- while (!spin_trylock_irqsave (&_stp_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
+ while (!spin_trylock_irqsave (&_stp_ctl_ready_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
+
if (unlikely (numtrylock >= MAXTRYLOCK))
return 0;
- list_add_tail(&bptr->list, &_stp_ready_q);
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+
+ list_add_tail(&bptr->list, &_stp_ctl_ready_q);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
+
+ return len;
+}
+
+static int _stp_sym_write (int type, void *data, unsigned len)
+{
+ struct _stp_buffer *bptr;
+ unsigned long flags;
+
+#ifdef DEBUG
+ _stp_sym_write_dbug(type, data, len);
+#endif
+
+ /* make sure we won't overflow the buffer */
+ if (unlikely(len > STP_BUFFER_SIZE))
+ return 0;
+
+ spin_lock_irqsave (&_stp_pool_lock, flags);
+ if (unlikely(list_empty(&_stp_pool_q))) {
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+ dbug("_stp_pool_q empty\n");
+ return -1;
+ }
+
+ /* get the next buffer from the pool */
+ bptr = (struct _stp_buffer *)_stp_pool_q.next;
+ list_del_init(&bptr->list);
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+ bptr->type = type;
+ memcpy(bptr->buf, data, len);
+ bptr->len = len;
+
+ /* put it on the pool of ready buffers */
+ spin_lock_irqsave (&_stp_sym_ready_lock, flags);
+ list_add_tail(&bptr->list, &_stp_sym_ready_q);
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+
+ /* OK, it's queued. Now signal any waiters. */
+ wake_up_interruptible(&_stp_sym_wq);
return len;
}
@@ -201,45 +318,89 @@ static int _stp_ctl_write (int type, void *data, int len)
static int _stp_ctl_send (int type, void *data, int len)
{
int err, trylimit = 50;
- kbug("ctl_send: type=%d len=%d\n", type, len);
- while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
- msleep (5);
- kbug("returning %d\n", err);
+ if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) {
+ while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--)
+ msleep (5);
+ } else {
+ while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
+ msleep (5);
+ }
return err;
}
static ssize_t
-_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+_stp_sym_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct _stp_buffer *bptr;
int len;
unsigned long flags;
- /* FIXME FIXME FIXME. assuming count is large enough to hold buffer!! */
+ /* wait for nonempty ready queue */
+ spin_lock_irqsave(&_stp_sym_ready_lock, flags);
+ while (list_empty(&_stp_sym_ready_q)) {
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ if (wait_event_interruptible(_stp_sym_wq, !list_empty(&_stp_sym_ready_q)))
+ return -ERESTARTSYS;
+ spin_lock_irqsave(&_stp_sym_ready_lock, flags);
+ }
+
+ /* get the next buffer off the ready list */
+ bptr = (struct _stp_buffer *)_stp_sym_ready_q.next;
+ list_del_init(&bptr->list);
+ spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
+
+ /* write it out */
+ len = bptr->len + 4;
+ if (len > count || copy_to_user(buf, &bptr->type, len)) {
+ /* now what? We took it off the queue then failed to send it */
+ /* we can't put it back on the queue because it will likely be out-of-order */
+ /* fortunately this should never happen */
+ /* FIXME need to mark this as a transport failure */
+ errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len);
+ return -EFAULT;
+ }
+
+ /* put it on the pool of free buffers */
+ spin_lock_irqsave(&_stp_pool_lock, flags);
+ list_add_tail(&bptr->list, &_stp_pool_q);
+ spin_unlock_irqrestore(&_stp_pool_lock, flags);
+
+ return len;
+}
+
+static ssize_t
+_stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct _stp_buffer *bptr;
+ int len;
+ unsigned long flags;
/* wait for nonempty ready queue */
- spin_lock_irqsave(&_stp_ready_lock, flags);
- while (list_empty(&_stp_ready_q)) {
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
+ while (list_empty(&_stp_ctl_ready_q)) {
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ready_q)))
+ if (wait_event_interruptible(_stp_ctl_wq, !list_empty(&_stp_ctl_ready_q)))
return -ERESTARTSYS;
- spin_lock_irqsave(&_stp_ready_lock, flags);
+ spin_lock_irqsave(&_stp_ctl_ready_lock, flags);
}
/* get the next buffer off the ready list */
- bptr = (struct _stp_buffer *)_stp_ready_q.next;
+ bptr = (struct _stp_buffer *)_stp_ctl_ready_q.next;
list_del_init(&bptr->list);
- spin_unlock_irqrestore(&_stp_ready_lock, flags);
+ spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
/* write it out */
len = bptr->len + 4;
- if (copy_to_user(buf, &bptr->type, len)) {
+ if (len > count || copy_to_user(buf, &bptr->type, len)) {
/* now what? We took it off the queue then failed to send it */
/* we can't put it back on the queue because it will likely be out-of-order */
/* fortunately this should never happen */
/* FIXME need to mark this as a transport failure */
+ errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len);
return -EFAULT;
}
@@ -251,9 +412,28 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp
return len;
}
+static int _stp_sym_opens = 0;
+static int _stp_sym_open_cmd (struct inode *inode, struct file *file)
+{
+ /* only allow one reader */
+ if (_stp_sym_opens)
+ return -1;
+
+ _stp_sym_opens++;
+ return 0;
+}
+
+static int _stp_sym_close_cmd (struct inode *inode, struct file *file)
+{
+ if (_stp_sym_opens)
+ _stp_sym_opens--;
+ return 0;
+}
+
static int _stp_ctl_opens = 0;
static int _stp_ctl_open_cmd (struct inode *inode, struct file *file)
{
+ /* only allow one reader */
if (_stp_ctl_opens)
return -1;
@@ -277,6 +457,13 @@ static struct file_operations _stp_proc_fops_cmd = {
.open = _stp_ctl_open_cmd,
.release = _stp_ctl_close_cmd,
};
+static struct file_operations _stp_sym_fops_cmd = {
+ .owner = THIS_MODULE,
+ .read = _stp_sym_read_cmd,
+ .write = _stp_sym_write_cmd,
+ .open = _stp_sym_open_cmd,
+ .release = _stp_sym_close_cmd,
+};
/* copy since proc_match is not MODULE_EXPORT'd */
static int my_proc_match(int len, const char *name, struct proc_dir_entry *de)
@@ -351,7 +538,8 @@ static int _stp_register_ctl_channel (void)
struct proc_dir_entry *de, *bs = NULL;
struct list_head *p, *tmp;
- INIT_LIST_HEAD(&_stp_ready_q);
+ INIT_LIST_HEAD(&_stp_ctl_ready_q);
+ INIT_LIST_HEAD(&_stp_sym_ready_q);
INIT_LIST_HEAD(&_stp_pool_q);
/* allocate buffers */
@@ -387,15 +575,23 @@ static int _stp_register_ctl_channel (void)
bs = create_proc_read_entry("bufsize", 0, _stp_proc_root, _stp_ctl_read_bufsize, NULL);
#endif /* STP_BULKMODE */
- /* finally create /proc/systemtap/module_name/cmd */
- de = create_proc_entry ("cmd", 0600, _stp_proc_root);
+ /* create /proc/systemtap/module_name/.cmd */
+ de = create_proc_entry (".cmd", 0600, _stp_proc_root);
if (de == NULL)
goto err1;
de->uid = _stp_uid;
de->gid = _stp_gid;
de->proc_fops = &_stp_proc_fops_cmd;
- return 0;
+ /* create /proc/systemtap/module_name/.symbols */
+ de = create_proc_entry (".symbols", 0600, _stp_proc_root);
+ if (de == NULL)
+ goto err2;
+ de->proc_fops = &_stp_sym_fops_cmd;
+
+ return 0;
+err2:
+ remove_proc_entry (".cmd", _stp_proc_root);
err1:
#ifdef STP_BULKMODE
for (de = _stp_proc_root->subdir; de; de = de->next)
@@ -439,7 +635,8 @@ static void _stp_unregister_ctl_channel (void)
remove_proc_entry ("bufsize", _stp_proc_root);
#endif /* STP_BULKMODE */
- remove_proc_entry ("cmd", _stp_proc_root);
+ remove_proc_entry (".symbols", _stp_proc_root);
+ remove_proc_entry (".cmd", _stp_proc_root);
_stp_rmdir_proc_module();
/* free memory pools */
@@ -447,7 +644,11 @@ static void _stp_unregister_ctl_channel (void)
list_del(p);
kfree(p);
}
- list_for_each_safe(p, tmp, &_stp_ready_q) {
+ list_for_each_safe(p, tmp, &_stp_sym_ready_q) {
+ list_del(p);
+ kfree(p);
+ }
+ list_for_each_safe(p, tmp, &_stp_ctl_ready_q) {
list_del(p);
kfree(p);
}