diff options
Diffstat (limited to 'runtime/transport/procfs.c')
-rw-r--r-- | runtime/transport/procfs.c | 299 |
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); } |