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 <behlendorf1@llnl.gov>
This commit is contained in:
Brian Behlendorf 2012-11-02 15:31:04 -07:00
parent df870a697f
commit 0e149d4204
2 changed files with 15 additions and 14 deletions

View File

@ -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;
}

View File

@ -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_; \
})