aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2012-11-02 15:31:04 -0700
committerBrian Behlendorf <[email protected]>2012-11-06 14:48:56 -0800
commit0e149d42049a0fc89c9ecdac428dbdfc6fd4e20a (patch)
tree788b47a7f5f4c24d49d33e83f65d1192f60fe12a
parentdf870a697fc8669d63534b27a108335269a7884f (diff)
splat: Fix log buffer locking
The Fedora 3.6 debug kernel identified the following issue where we call copy_to_user() under a spin lock(). This used to be safe in older kernels but no longer appears to be true so the spin lock was changed to a mutex. None of this code is performance critical so allowing the process to sleep is harmless. Signed-off-by: Brian Behlendorf <[email protected]>
-rw-r--r--module/splat/splat-ctl.c23
-rw-r--r--module/splat/splat-internal.h6
2 files changed, 15 insertions, 14 deletions
diff --git a/module/splat/splat-ctl.c b/module/splat/splat-ctl.c
index 53bf51dd6..c68281a84 100644
--- a/module/splat/splat-ctl.c
+++ b/module/splat/splat-ctl.c
@@ -71,7 +71,7 @@ splat_open(struct inode *inode, struct file *file)
if (info == NULL)
return -ENOMEM;
- spin_lock_init(&info->info_lock);
+ mutex_init(&info->info_lock);
info->info_size = SPLAT_INFO_BUFFER_SIZE;
info->info_buffer = (char *)vmalloc(SPLAT_INFO_BUFFER_SIZE);
if (info->info_buffer == NULL) {
@@ -100,6 +100,7 @@ splat_release(struct inode *inode, struct file *file)
ASSERT(info);
ASSERT(info->info_buffer);
+ mutex_destroy(&info->info_lock);
vfree(info->info_buffer);
kfree(info);
@@ -114,10 +115,10 @@ splat_buffer_clear(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
ASSERT(info);
ASSERT(info->info_buffer);
- spin_lock(&info->info_lock);
+ mutex_lock(&info->info_lock);
memset(info->info_buffer, 0, info->info_size);
info->info_head = info->info_buffer;
- spin_unlock(&info->info_lock);
+ mutex_unlock(&info->info_lock);
return 0;
}
@@ -132,7 +133,7 @@ splat_buffer_size(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
ASSERT(info);
ASSERT(info->info_buffer);
- spin_lock(&info->info_lock);
+ mutex_lock(&info->info_lock);
if (kcfg->cfg_arg1 > 0) {
size = kcfg->cfg_arg1;
@@ -157,7 +158,7 @@ splat_buffer_size(struct file *file, splat_cfg_t *kcfg, unsigned long arg)
if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg)))
rc = -EFAULT;
out:
- spin_unlock(&info->info_lock);
+ mutex_unlock(&info->info_lock);
return rc;
}
@@ -508,7 +509,7 @@ static ssize_t splat_write(struct file *file, const char __user *buf,
ASSERT(info);
ASSERT(info->info_buffer);
- spin_lock(&info->info_lock);
+ mutex_lock(&info->info_lock);
/* Write beyond EOF */
if (*ppos >= info->info_size) {
@@ -528,7 +529,7 @@ static ssize_t splat_write(struct file *file, const char __user *buf,
*ppos += count;
rc = count;
out:
- spin_unlock(&info->info_lock);
+ mutex_unlock(&info->info_lock);
return rc;
}
@@ -545,7 +546,7 @@ static ssize_t splat_read(struct file *file, char __user *buf,
ASSERT(info);
ASSERT(info->info_buffer);
- spin_lock(&info->info_lock);
+ mutex_lock(&info->info_lock);
/* Read beyond EOF */
if (*ppos >= info->info_size)
@@ -563,7 +564,7 @@ static ssize_t splat_read(struct file *file, char __user *buf,
*ppos += count;
rc = count;
out:
- spin_unlock(&info->info_lock);
+ mutex_unlock(&info->info_lock);
return rc;
}
@@ -579,7 +580,7 @@ static loff_t splat_seek(struct file *file, loff_t offset, int origin)
ASSERT(info);
ASSERT(info->info_buffer);
- spin_lock(&info->info_lock);
+ mutex_lock(&info->info_lock);
switch (origin) {
case 0: /* SEEK_SET - No-op just do it */
@@ -598,7 +599,7 @@ static loff_t splat_seek(struct file *file, loff_t offset, int origin)
rc = offset;
}
- spin_unlock(&info->info_lock);
+ mutex_unlock(&info->info_lock);
return rc;
}
diff --git a/module/splat/splat-internal.h b/module/splat/splat-internal.h
index b15db65e2..14303a105 100644
--- a/module/splat/splat-internal.h
+++ b/module/splat/splat-internal.h
@@ -121,7 +121,7 @@ typedef struct splat_subsystem {
#define SPLAT_INFO_BUFFER_REDZONE 256
typedef struct splat_info {
- spinlock_t info_lock;
+ struct mutex info_lock;
int info_size;
char *info_buffer;
char *info_head; /* Internal kernel use only */
@@ -136,7 +136,7 @@ typedef struct splat_info {
ASSERT(_info_); \
ASSERT(_info_->info_buffer); \
\
- spin_lock(&_info_->info_lock); \
+ mutex_lock(&_info_->info_lock); \
\
/* Don't allow the kernel to start a write in the red zone */ \
if ((int)(_info_->info_head - _info_->info_buffer) > \
@@ -148,7 +148,7 @@ typedef struct splat_info {
_info_->info_head += _rc_; \
} \
\
- spin_unlock(&_info_->info_lock); \
+ mutex_unlock(&_info_->info_lock); \
_rc_; \
})