summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorDavid Smith <dsmith@redhat.com>2010-03-01 15:17:09 -0600
committerDavid Smith <dsmith@redhat.com>2010-03-01 15:17:09 -0600
commitbfbbb76e5d0294cc1d44f42ab6c2d91149067b6c (patch)
tree24bba7fe93496f46cdaa558040c8c3433c4d6510 /runtime
parent6861e05642c23c569ef34d49bfa3fe83e2badc11 (diff)
downloadsystemtap-steved-bfbbb76e5d0294cc1d44f42ab6c2d91149067b6c.tar.gz
systemtap-steved-bfbbb76e5d0294cc1d44f42ab6c2d91149067b6c.tar.xz
systemtap-steved-bfbbb76e5d0294cc1d44f42ab6c2d91149067b6c.zip
Fixed PR 11336 by using a wait queue to wait on procfs file availability.
* runtime/procfs-probes.c: Removed old kernel 2.6.16 code. Simplified _spp_lock macros. (_stp_proc_open_file): If file is busy, use a wait queue to wait on it being available. (_stp_proc_release_file): Decrease open count. * tapset-procfs.cxx (emit_module_init): Updated procfs probe initialization/shutdown routine names. (emit_module_exit): Ditto.
Diffstat (limited to 'runtime')
-rw-r--r--runtime/procfs-probes.c123
1 files changed, 53 insertions, 70 deletions
diff --git a/runtime/procfs-probes.c b/runtime/procfs-probes.c
index 8f9ff113..bf1090d0 100644
--- a/runtime/procfs-probes.c
+++ b/runtime/procfs-probes.c
@@ -3,6 +3,7 @@
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/sched.h>
#if 0
// Currently we have to output _stp_procfs_data early in the
@@ -24,64 +25,22 @@ struct stap_procfs_probe {
char *buffer;
const size_t bufsize;
size_t count;
-
int needs_fill;
+
struct mutex lock;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
- atomic_t lockcount;
-#endif
+ int opencount;
+ wait_queue_head_t waitq;
};
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
-/*
- * Kernels 2.6.16 or less don't really have mutexes. The 'mutex_*'
- * functions are defined as their similar semaphore equivalents.
- * However, there is no semaphore equivalent of 'mutex_is_locked'.
- * So, we'll fake it with an atomic counter.
- */
-static inline void _spp_lock_init(struct stap_procfs_probe *spp)
+static inline void _spp_init(struct stap_procfs_probe *spp)
{
- atomic_set(&spp->lockcount, 0);
+ init_waitqueue_head(&spp->waitq);
+ spp->opencount = 0;
mutex_init(&spp->lock);
}
-static inline int _spp_trylock(struct stap_procfs_probe *spp)
-{
- int ret = mutex_trylock(&spp->lock);
- if (ret) {
- atomic_inc(&spp->lockcount);
- }
- return(ret);
-}
-static inline void _spp_lock(struct stap_procfs_probe *spp)
-{
- mutex_lock(&spp->lock);
- atomic_inc(&spp->lockcount);
-}
-static inline void _spp_unlock(struct stap_procfs_probe *spp)
-{
- atomic_dec(&spp->lockcount);
- mutex_unlock(&spp->lock);
-}
-static inline void _spp_lock_shutdown(struct stap_procfs_probe *spp)
-{
- if (atomic_read(&spp->lockcount) != 0) {
- _spp_unlock(spp);
- }
- mutex_destroy(&spp->lock);
-}
-#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) */
-#define _spp_lock_init(spp) mutex_init(&(spp)->lock)
-#define _spp_trylock(spp) mutex_trylock(&(spp)->lock)
#define _spp_lock(spp) mutex_lock(&(spp)->lock)
#define _spp_unlock(spp) mutex_unlock(&(spp)->lock)
-static inline void _spp_lock_shutdown(struct stap_procfs_probe *spp)
-{
- if (mutex_is_locked(&spp->lock)) {
- mutex_unlock(&spp->lock);
- }
- mutex_destroy(&spp->lock);
-}
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) */
+#define _spp_shutdown(spp) mutex_destroy(&(spp)->lock)
static int _stp_proc_fill_read_buffer(struct stap_procfs_probe *spp);
@@ -92,39 +51,57 @@ static int
_stp_proc_open_file(struct inode *inode, struct file *filp)
{
struct stap_procfs_probe *spp;
- int err;
+ int res;
spp = (struct stap_procfs_probe *)PDE(inode)->data;
if (spp == NULL) {
return -EINVAL;
}
- err = generic_file_open(inode, filp);
- if (err)
- return err;
+ res = generic_file_open(inode, filp);
+ if (res)
+ return res;
/* To avoid concurrency problems, we only allow 1 open at a
- * time. (Grabbing a mutex here doesn't really work. The
- * debug kernel can OOPS with "BUG: lock held when returning
- * to user space!".)
- *
- * If open() was called with
- * O_NONBLOCK, don't block, just return EAGAIN. */
- if (filp->f_flags & O_NONBLOCK) {
- if (_spp_trylock(spp) == 0) {
- return -EAGAIN;
- }
+ * time. */
+
+ _spp_lock(spp);
+
+ /* If the file isn't open yet, ... */
+ if (spp->opencount == 0) {
+ res = 0;
+ }
+ /* If open() was called with O_NONBLOCK, don't block, just
+ * return EAGAIN. */
+ else if (filp->f_flags & O_NONBLOCK) {
+ res = -EAGAIN;
}
+ /* The file is already open, so wait. */
else {
- _spp_lock(spp);
+ 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;
+ }
}
-
- filp->private_data = spp;
- if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
- spp->buffer[0] = '\0';
- spp->count = 0;
- spp->needs_fill = 1;
+ 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;
}
@@ -135,7 +112,13 @@ _stp_proc_release_file(struct inode *inode, struct file *filp)
spp = (struct stap_procfs_probe *)filp->private_data;
if (spp != NULL) {
+ /* Decrement the open count. */
+ _spp_lock(spp);
+ spp->opencount--;
_spp_unlock(spp);
+
+ /* Wake up any tasks waiting to open the file. */
+ wake_up(&spp->waitq);
}
return 0;
}