diff options
author | Brian Behlendorf <[email protected]> | 2012-11-02 15:31:04 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2012-11-06 14:48:56 -0800 |
commit | 0e149d42049a0fc89c9ecdac428dbdfc6fd4e20a (patch) | |
tree | 788b47a7f5f4c24d49d33e83f65d1192f60fe12a | |
parent | df870a697fc8669d63534b27a108335269a7884f (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.c | 23 | ||||
-rw-r--r-- | module/splat/splat-internal.h | 6 |
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_; \ }) |