[alsa-devel] Procfs cleanup in ALSA core
Hi,
the another fixes are clean-ups of procfs interface in ALSA core. The patches below are found in sound git tree topic/core-cleanup branch. (This branch also contains the BKL-cleanup branch, too).
[PATCH 1/5] ALSA: info - Use standard types for info callbacks [PATCH 2/5] ALSA: info - Check file position validity in common layer [PATCH 3/5] ALSA: info - Implement common llseek for binary mode [PATCH 4/5] ALSA: core - Define llseek fops [PATCH 5/5] ALSA: Update the documentation for changes of proc files
Takashi
Use loff_t, size_t and ssize_t for arguments of info callbacks to follow the standard procfs.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/info.h | 24 ++++++++++++------------ sound/drivers/opl4/opl4_proc.c | 21 +++++++++++++-------- sound/isa/gus/gus_mem_proc.c | 16 ++++++++-------- sound/pci/cs4281.c | 16 ++++++++-------- sound/pci/cs46xx/cs46xx_lib.c | 7 ++++--- sound/pci/emu10k1/emuproc.c | 8 ++++---- sound/pci/mixart/mixart.c | 32 ++++++++++++++++---------------- 7 files changed, 65 insertions(+), 59 deletions(-)
diff --git a/include/sound/info.h b/include/sound/info.h index 112e894..4e94cf1 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -51,18 +51,18 @@ struct snd_info_entry_ops { unsigned short mode, void **file_private_data); int (*release)(struct snd_info_entry *entry, unsigned short mode, void *file_private_data); - long (*read)(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos); - long (*write)(struct snd_info_entry *entry, void *file_private_data, - struct file *file, const char __user *buf, - unsigned long count, unsigned long pos); - long long (*llseek)(struct snd_info_entry *entry, - void *file_private_data, struct file *file, - long long offset, int orig); - unsigned int(*poll)(struct snd_info_entry *entry, - void *file_private_data, struct file *file, - poll_table *wait); + ssize_t (*read)(struct snd_info_entry *entry, void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos); + ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data, + struct file *file, const char __user *buf, + size_t count, loff_t pos); + loff_t (*llseek)(struct snd_info_entry *entry, + void *file_private_data, struct file *file, + loff_t offset, int orig); + unsigned int (*poll)(struct snd_info_entry *entry, + void *file_private_data, struct file *file, + poll_table *wait); int (*ioctl)(struct snd_info_entry *entry, void *file_private_data, struct file *file, unsigned int cmd, unsigned long arg); int (*mmap)(struct snd_info_entry *entry, void *file_private_data, diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index 1679300..eb72814 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c @@ -49,9 +49,10 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry, return 0; }
-static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *_buf, - unsigned long count, unsigned long pos) +static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *_buf, + size_t count, loff_t pos) { struct snd_opl4 *opl4 = entry->private_data; long size; @@ -75,9 +76,11 @@ static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_priv return 0; }
-static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_private_data, - struct file *file, const char __user *_buf, - unsigned long count, unsigned long pos) +static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + const char __user *_buf, + size_t count, size_t pos) { struct snd_opl4 *opl4 = entry->private_data; long size; @@ -101,8 +104,10 @@ static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_pri return 0; }
-static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *file_private_data, - struct file *file, long long offset, int orig) +static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + loff_t offset, int orig) { switch (orig) { case SEEK_SET: diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index 2803e22..b2d2dba 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c @@ -31,9 +31,10 @@ struct gus_proc_private { struct snd_gus_card * gus; };
-static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { long size; struct gus_proc_private *priv = entry->private_data; @@ -51,11 +52,10 @@ static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_priva return 0; }
-static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, - void *private_file_data, - struct file *file, - long long offset, - int orig) +static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, + void *private_file_data, + struct file *file, + loff_t offset, int orig) { struct gus_proc_private *priv = entry->private_data;
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9edc650..b0bba2e 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1139,10 +1139,10 @@ static void snd_cs4281_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq); }
-static long snd_cs4281_BA0_read(struct snd_info_entry *entry, - void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { long size; struct cs4281 *chip = entry->private_data; @@ -1157,10 +1157,10 @@ static long snd_cs4281_BA0_read(struct snd_info_entry *entry, return size; }
-static long snd_cs4281_BA1_read(struct snd_info_entry *entry, - void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { long size; struct cs4281 *chip = entry->private_data; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 3f99a5e..08117b1 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2657,9 +2657,10 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { } * proc interface */
-static long snd_cs46xx_io_read(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { long size; struct snd_cs46xx_region *region = entry->private_data; diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index baa7cd5..347b241 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -341,10 +341,10 @@ static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry, #define TOTAL_SIZE_CODE (0x200*8) #define A_TOTAL_SIZE_CODE (0x400*8)
-static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, - void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { long size; struct snd_emu10k1 *emu = entry->private_data; diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 3be8f97..b5df78b 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1102,11 +1102,10 @@ static int snd_mixart_free(struct mixart_mgr *mgr) /* * proc interface */ -static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry, - void *private_file_data, - struct file *file, - long long offset, - int orig) +static loff_t snd_mixart_BA0_llseek(struct snd_info_entry *entry, + void *private_file_data, + struct file *file, + loff_t offset, int orig) { offset = offset & ~3; /* 4 bytes aligned */
@@ -1128,11 +1127,10 @@ static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry, return file->f_pos; }
-static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry, - void *private_file_data, - struct file *file, - long long offset, - int orig) +static loff_t snd_mixart_BA1_llseek(struct snd_info_entry *entry, + void *private_file_data, + struct file *file, + loff_t offset, int orig) { offset = offset & ~3; /* 4 bytes aligned */
@@ -1157,9 +1155,10 @@ static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry, /* mixart_BA0 proc interface for BAR 0 - read callback */ -static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { struct mixart_mgr *mgr = entry->private_data; unsigned long maxsize; @@ -1178,9 +1177,10 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private /* mixart_BA1 proc interface for BAR 1 - read callback */ -static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos) +static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry, + void *file_private_data, + struct file *file, char __user *buf, + size_t count, loff_t pos) { struct mixart_mgr *mgr = entry->private_data; unsigned long maxsize;
Check the validity of the file position in the common info layer before calling read or write callbacks in assumption that entry->size is set up properly to indicate the max file size.
Removed the redundant checks from the callbacks as well.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/info.c | 14 +++++++++-- sound/drivers/opl4/opl4_proc.c | 46 ++++++++++++++-------------------------- sound/isa/gus/gus_mem_proc.c | 14 +++-------- sound/pci/cs4281.c | 24 +++++--------------- sound/pci/cs46xx/cs46xx_lib.c | 12 ++------- sound/pci/emu10k1/emuproc.c | 43 +++++++++++++++++-------------------- sound/pci/mixart/mixart.c | 12 ---------- 7 files changed, 60 insertions(+), 105 deletions(-)
diff --git a/sound/core/info.c b/sound/core/info.c index ff968be..f90a6fd 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -232,10 +232,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, return -EFAULT; break; case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->read) + if (pos >= entry->size) + return 0; + if (entry->c.ops->read) { + size = entry->size - pos; + size = min(count, size); size = entry->c.ops->read(entry, data->file_private_data, - file, buffer, count, pos); + file, buffer, size, pos); + } break; } if ((ssize_t) size > 0) @@ -282,10 +287,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer size = count; break; case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->write) + if (entry->c.ops->write && count > 0) { + size_t maxsize = entry->size - pos; + count = min(count, maxsize); size = entry->c.ops->write(entry, data->file_private_data, file, buffer, count, pos); + } break; } if ((ssize_t) size > 0) diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index eb72814..210b89d 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c @@ -55,25 +55,18 @@ static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry, size_t count, loff_t pos) { struct snd_opl4 *opl4 = entry->private_data; - long size; char* buf;
- size = count; - if (pos + size > entry->size) - size = entry->size - pos; - if (size > 0) { - buf = vmalloc(size); - if (!buf) - return -ENOMEM; - snd_opl4_read_memory(opl4, buf, pos, size); - if (copy_to_user(_buf, buf, size)) { - vfree(buf); - return -EFAULT; - } + buf = vmalloc(count); + if (!buf) + return -ENOMEM; + snd_opl4_read_memory(opl4, buf, pos, count); + if (copy_to_user(_buf, buf, count)) { vfree(buf); - return size; + return -EFAULT; } - return 0; + vfree(buf); + return count; }
static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, @@ -83,25 +76,18 @@ static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, size_t count, size_t pos) { struct snd_opl4 *opl4 = entry->private_data; - long size; char *buf;
- size = count; - if (pos + size > entry->size) - size = entry->size - pos; - if (size > 0) { - buf = vmalloc(size); - if (!buf) - return -ENOMEM; - if (copy_from_user(buf, _buf, size)) { - vfree(buf); - return -EFAULT; - } - snd_opl4_write_memory(opl4, buf, pos, size); + buf = vmalloc(count); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, _buf, count)) { vfree(buf); - return size; + return -EFAULT; } - return 0; + snd_opl4_write_memory(opl4, buf, pos, count); + vfree(buf); + return count; }
static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index b2d2dba..faa2bec 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c @@ -36,20 +36,14 @@ static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry, struct file *file, char __user *buf, size_t count, loff_t pos) { - long size; struct gus_proc_private *priv = entry->private_data; struct snd_gus_card *gus = priv->gus; int err;
- size = count; - if (pos + size > priv->size) - size = (long)priv->size - pos; - if (size > 0) { - if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0) - return err; - return size; - } - return 0; + err = snd_gus_dram_read(gus, buf, pos, count, priv->rom); + if (err < 0) + return err; + return count; }
static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index b0bba2e..6772070 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1144,17 +1144,11 @@ static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry, struct file *file, char __user *buf, size_t count, loff_t pos) { - long size; struct cs4281 *chip = entry->private_data; - size = count; - if (pos + size > CS4281_BA0_SIZE) - size = (long)CS4281_BA0_SIZE - pos; - if (size > 0) { - if (copy_to_user_fromio(buf, chip->ba0 + pos, size)) - return -EFAULT; - } - return size; + if (copy_to_user_fromio(buf, chip->ba0 + pos, count)) + return -EFAULT; + return count; }
static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, @@ -1162,17 +1156,11 @@ static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, struct file *file, char __user *buf, size_t count, loff_t pos) { - long size; struct cs4281 *chip = entry->private_data; - size = count; - if (pos + size > CS4281_BA1_SIZE) - size = (long)CS4281_BA1_SIZE - pos; - if (size > 0) { - if (copy_to_user_fromio(buf, chip->ba1 + pos, size)) - return -EFAULT; - } - return size; + if (copy_to_user_fromio(buf, chip->ba1 + pos, count)) + return -EFAULT; + return count; }
static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 08117b1..aad3708 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2662,17 +2662,11 @@ static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry, struct file *file, char __user *buf, size_t count, loff_t pos) { - long size; struct snd_cs46xx_region *region = entry->private_data; - size = count; - if (pos + (size_t)size > region->size) - size = region->size - pos; - if (size > 0) { - if (copy_to_user_fromio(buf, region->remap_addr + pos, size)) - return -EFAULT; - } - return size; + if (copy_to_user_fromio(buf, region->remap_addr + pos, count)) + return -EFAULT; + return count; }
static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 347b241..bc38dd4 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -346,10 +346,12 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, struct file *file, char __user *buf, size_t count, loff_t pos) { - long size; struct snd_emu10k1 *emu = entry->private_data; unsigned int offset; int tram_addr = 0; + unsigned int *tmp; + long res; + unsigned int idx; if (!strcmp(entry->name, "fx8010_tram_addr")) { offset = TANKMEMADDRREGBASE; @@ -361,30 +363,25 @@ static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, } else { offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; } - size = count; - if (pos + size > entry->size) - size = (long)entry->size - pos; - if (size > 0) { - unsigned int *tmp; - long res; - unsigned int idx; - if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL) - return -ENOMEM; - for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) - if (tram_addr && emu->audigy) { - tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11; - tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; - } else - tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); - if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size)) - res = -EFAULT; - else { - res = size; + + tmp = kmalloc(count + 8, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) { + unsigned int val; + val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); + if (tram_addr && emu->audigy) { + val >>= 11; + val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; } - kfree(tmp); - return res; + tmp[idx] = val; } - return 0; + if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count)) + res = -EFAULT; + else + res = count; + kfree(tmp); + return res; }
static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index b5df78b..be95e00 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1161,13 +1161,7 @@ static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry, size_t count, loff_t pos) { struct mixart_mgr *mgr = entry->private_data; - unsigned long maxsize;
- if (pos >= MIXART_BA0_SIZE) - return 0; - maxsize = MIXART_BA0_SIZE - pos; - if (count > maxsize) - count = maxsize; count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) return -EFAULT; @@ -1183,13 +1177,7 @@ static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry, size_t count, loff_t pos) { struct mixart_mgr *mgr = entry->private_data; - unsigned long maxsize;
- if (pos > MIXART_BA1_SIZE) - return 0; - maxsize = MIXART_BA1_SIZE - pos; - if (count > maxsize) - count = maxsize; count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) return -EFAULT;
The llseek implementation is identical for existing driver implementations, so let's merge to the common layer. The same code for the text proc file can be used even for the binary proc file.
The driver can provide its own llseek method if needed. Then the common code will be skipped.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/info.c | 54 +++++++++++++++++++++------------------ sound/drivers/opl4/opl4_proc.c | 24 ----------------- sound/isa/gus/gus_mem_proc.c | 26 ------------------- sound/pci/mixart/mixart.c | 51 ------------------------------------- 4 files changed, 29 insertions(+), 126 deletions(-)
diff --git a/sound/core/info.c b/sound/core/info.c index f90a6fd..b70564e 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -164,39 +164,43 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) { struct snd_info_private_data *data; struct snd_info_entry *entry; - loff_t ret; + loff_t ret = -EINVAL, size;
data = file->private_data; entry = data->entry; mutex_lock(&entry->access); - switch (entry->content) { - case SNDRV_INFO_CONTENT_TEXT: - switch (orig) { - case SEEK_SET: - file->f_pos = offset; - ret = file->f_pos; - goto out; - case SEEK_CUR: - file->f_pos += offset; - ret = file->f_pos; - goto out; - case SEEK_END: - default: - ret = -EINVAL; - goto out; - } + if (entry->content == SNDRV_INFO_CONTENT_DATA && + entry->c.ops->llseek) { + offset = entry->c.ops->llseek(entry, + data->file_private_data, + file, offset, orig); + goto out; + } + if (entry->content == SNDRV_INFO_CONTENT_DATA) + size = entry->size; + else + size = 0; + switch (orig) { + case SEEK_SET: break; - case SNDRV_INFO_CONTENT_DATA: - if (entry->c.ops->llseek) { - ret = entry->c.ops->llseek(entry, - data->file_private_data, - file, offset, orig); + case SEEK_CUR: + offset += file->f_pos; + break; + case SEEK_END: + if (!size) goto out; - } + offset += size; break; - } - ret = -ENXIO; -out: + default: + goto out; + } + if (offset < 0) + goto out; + if (size && offset > size) + offset = size; + file->f_pos = offset; + ret = offset; + out: mutex_unlock(&entry->access); return ret; } diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index 210b89d..c5c13c4 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c @@ -90,35 +90,11 @@ static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, return count; }
-static loff_t snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, - void *file_private_data, - struct file *file, - loff_t offset, int orig) -{ - switch (orig) { - case SEEK_SET: - file->f_pos = offset; - break; - case SEEK_CUR: - file->f_pos += offset; - break; - case SEEK_END: /* offset is negative */ - file->f_pos = entry->size + offset; - break; - default: - return -EINVAL; - } - if (file->f_pos > entry->size) - file->f_pos = entry->size; - return file->f_pos; -} - static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { .open = snd_opl4_mem_proc_open, .release = snd_opl4_mem_proc_release, .read = snd_opl4_mem_proc_read, .write = snd_opl4_mem_proc_write, - .llseek = snd_opl4_mem_proc_llseek, };
int snd_opl4_create_proc(struct snd_opl4 *opl4) diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index faa2bec..2ccb3fa 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c @@ -46,31 +46,6 @@ static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry, return count; }
-static loff_t snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, - void *private_file_data, - struct file *file, - loff_t offset, int orig) -{ - struct gus_proc_private *priv = entry->private_data; - - switch (orig) { - case SEEK_SET: - file->f_pos = offset; - break; - case SEEK_CUR: - file->f_pos += offset; - break; - case SEEK_END: /* offset is negative */ - file->f_pos = priv->size + offset; - break; - default: - return -EINVAL; - } - if (file->f_pos > priv->size) - file->f_pos = priv->size; - return file->f_pos; -} - static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) { struct gus_proc_private *priv = entry->private_data; @@ -79,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
static struct snd_info_entry_ops snd_gf1_mem_proc_ops = { .read = snd_gf1_mem_proc_dump, - .llseek = snd_gf1_mem_proc_llseek, };
int snd_gf1_mem_proc_init(struct snd_gus_card * gus) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index be95e00..6c3fd4d 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1102,55 +1102,6 @@ static int snd_mixart_free(struct mixart_mgr *mgr) /* * proc interface */ -static loff_t snd_mixart_BA0_llseek(struct snd_info_entry *entry, - void *private_file_data, - struct file *file, - loff_t offset, int orig) -{ - offset = offset & ~3; /* 4 bytes aligned */ - - switch(orig) { - case SEEK_SET: - file->f_pos = offset; - break; - case SEEK_CUR: - file->f_pos += offset; - break; - case SEEK_END: /* offset is negative */ - file->f_pos = MIXART_BA0_SIZE + offset; - break; - default: - return -EINVAL; - } - if(file->f_pos > MIXART_BA0_SIZE) - file->f_pos = MIXART_BA0_SIZE; - return file->f_pos; -} - -static loff_t snd_mixart_BA1_llseek(struct snd_info_entry *entry, - void *private_file_data, - struct file *file, - loff_t offset, int orig) -{ - offset = offset & ~3; /* 4 bytes aligned */ - - switch(orig) { - case SEEK_SET: - file->f_pos = offset; - break; - case SEEK_CUR: - file->f_pos += offset; - break; - case SEEK_END: /* offset is negative */ - file->f_pos = MIXART_BA1_SIZE + offset; - break; - default: - return -EINVAL; - } - if(file->f_pos > MIXART_BA1_SIZE) - file->f_pos = MIXART_BA1_SIZE; - return file->f_pos; -}
/* mixart_BA0 proc interface for BAR 0 - read callback @@ -1186,12 +1137,10 @@ static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry,
static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { .read = snd_mixart_BA0_read, - .llseek = snd_mixart_BA0_llseek };
static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { .read = snd_mixart_BA1_read, - .llseek = snd_mixart_BA1_llseek };
Set no_llseek to llseek file ops of each sound component (but for hwdep). This avoids the implicit BKL invocation via generic_file_llseek() used as default when fops.llseek is NULL.
Also call nonseekable_open() at each open ops to ensure the file flags have no seek bit.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/control.c | 5 +++++ sound/core/oss/mixer_oss.c | 5 +++++ sound/core/oss/pcm_oss.c | 5 +++++ sound/core/pcm_native.c | 10 ++++++++-- sound/core/rawmidi.c | 5 +++++ sound/core/seq/seq_clientmgr.c | 6 ++++++ sound/core/timer.c | 6 ++++++ 7 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/sound/core/control.c b/sound/core/control.c index 439ce64..070aab4 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -50,6 +50,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file) struct snd_ctl_file *ctl; int err;
+ err = nonseekable_open(inode, file); + if (err < 0) + return err; + card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL); if (!card) { err = -ENODEV; @@ -1388,6 +1392,7 @@ static const struct file_operations snd_ctl_f_ops = .read = snd_ctl_read, .open = snd_ctl_open, .release = snd_ctl_release, + .llseek = no_llseek, .poll = snd_ctl_poll, .unlocked_ioctl = snd_ctl_ioctl, .compat_ioctl = snd_ctl_ioctl_compat, diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 54e2eb5..f50ebf2 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -43,6 +43,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) struct snd_mixer_oss_file *fmixer; int err;
+ err = nonseekable_open(inode, file); + if (err < 0) + return err; + card = snd_lookup_oss_minor_data(iminor(inode), SNDRV_OSS_DEVICE_TYPE_MIXER); if (card == NULL) @@ -397,6 +401,7 @@ static const struct file_operations snd_mixer_oss_f_ops = .owner = THIS_MODULE, .open = snd_mixer_oss_open, .release = snd_mixer_oss_release, + .llseek = no_llseek, .unlocked_ioctl = snd_mixer_oss_ioctl, .compat_ioctl = snd_mixer_oss_ioctl_compat, }; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 82d4e33..5c8c7df 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2379,6 +2379,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) int nonblock; wait_queue_t wait;
+ err = nonseekable_open(inode, file); + if (err < 0) + return err; + pcm = snd_lookup_oss_minor_data(iminor(inode), SNDRV_OSS_DEVICE_TYPE_PCM); if (pcm == NULL) { @@ -2977,6 +2981,7 @@ static const struct file_operations snd_pcm_oss_f_reg = .write = snd_pcm_oss_write, .open = snd_pcm_oss_open, .release = snd_pcm_oss_release, + .llseek = no_llseek, .poll = snd_pcm_oss_poll, .unlocked_ioctl = snd_pcm_oss_ioctl, .compat_ioctl = snd_pcm_oss_ioctl_compat, diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index cadba30..5b22443 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2107,7 +2107,9 @@ static int snd_pcm_open_file(struct file *file, static int snd_pcm_playback_open(struct inode *inode, struct file *file) { struct snd_pcm *pcm; - + int err = nonseekable_open(inode, file); + if (err < 0) + return err; pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK); return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); @@ -2116,7 +2118,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) static int snd_pcm_capture_open(struct inode *inode, struct file *file) { struct snd_pcm *pcm; - + int err = nonseekable_open(inode, file); + if (err < 0) + return err; pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_CAPTURE); return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); @@ -3450,6 +3454,7 @@ const struct file_operations snd_pcm_f_ops[2] = { .aio_write = snd_pcm_aio_write, .open = snd_pcm_playback_open, .release = snd_pcm_release, + .llseek = no_llseek, .poll = snd_pcm_playback_poll, .unlocked_ioctl = snd_pcm_playback_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, @@ -3463,6 +3468,7 @@ const struct file_operations snd_pcm_f_ops[2] = { .aio_read = snd_pcm_aio_read, .open = snd_pcm_capture_open, .release = snd_pcm_release, + .llseek = no_llseek, .poll = snd_pcm_capture_poll, .unlocked_ioctl = snd_pcm_capture_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0f5a194..eb68326 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -376,6 +376,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) return -EINVAL; /* invalid combination */
+ err = nonseekable_open(inode, file); + if (err < 0) + return err; + if (maj == snd_major) { rmidi = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_RAWMIDI); @@ -1391,6 +1395,7 @@ static const struct file_operations snd_rawmidi_f_ops = .write = snd_rawmidi_write, .open = snd_rawmidi_open, .release = snd_rawmidi_release, + .llseek = no_llseek, .poll = snd_rawmidi_poll, .unlocked_ioctl = snd_rawmidi_ioctl, .compat_ioctl = snd_rawmidi_ioctl_compat, diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 48eca9f..99a485f 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -318,6 +318,11 @@ static int snd_seq_open(struct inode *inode, struct file *file) int c, mode; /* client id */ struct snd_seq_client *client; struct snd_seq_user_client *user; + int err; + + err = nonseekable_open(inode, file); + if (err < 0) + return err;
if (mutex_lock_interruptible(®ister_mutex)) return -ERESTARTSYS; @@ -2550,6 +2555,7 @@ static const struct file_operations snd_seq_f_ops = .write = snd_seq_write, .open = snd_seq_open, .release = snd_seq_release, + .llseek = no_llseek, .poll = snd_seq_poll, .unlocked_ioctl = snd_seq_ioctl, .compat_ioctl = snd_seq_ioctl_compat, diff --git a/sound/core/timer.c b/sound/core/timer.c index 7394365..8c9a661 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1237,6 +1237,11 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, static int snd_timer_user_open(struct inode *inode, struct file *file) { struct snd_timer_user *tu; + int err; + + err = nonseekable_open(inode, file); + if (err < 0) + return err;
tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (tu == NULL) @@ -1921,6 +1926,7 @@ static const struct file_operations snd_timer_f_ops = .read = snd_timer_user_read, .open = snd_timer_user_open, .release = snd_timer_user_release, + .llseek = no_llseek, .poll = snd_timer_user_poll, .unlocked_ioctl = snd_timer_user_ioctl, .compat_ioctl = snd_timer_user_ioctl_compat,
Signed-off-by: Takashi Iwai tiwai@suse.de --- Documentation/DocBook/writing-an-alsa-driver.tmpl | 27 +++++++++++++------- 1 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 0d0f7b4..0ba149d 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -5518,34 +5518,41 @@ struct _snd_pcm_runtime { ]]> </programlisting> </informalexample> + + For the raw data, <structfield>size</structfield> field must be + set properly. This specifies the maximum size of the proc file access. </para>
<para> - The callback is much more complicated than the text-file - version. You need to use a low-level I/O functions such as + The read/write callbacks of raw mode are more direct than the text mode. + You need to use a low-level I/O functions such as <function>copy_from/to_user()</function> to transfer the data.
<informalexample> <programlisting> <![CDATA[ - static long my_file_io_read(struct snd_info_entry *entry, + static ssize_t my_file_io_read(struct snd_info_entry *entry, void *file_private_data, struct file *file, char *buf, - unsigned long count, - unsigned long pos) + size_t count, + loff_t pos) { - long size = count; - if (pos + size > local_max_size) - size = local_max_size - pos; - if (copy_to_user(buf, local_data + pos, size)) + if (copy_to_user(buf, local_data + pos, count)) return -EFAULT; - return size; + return count; } ]]> </programlisting> </informalexample> + + If the size of the info entry has been set up properly, + <structfield>count</structfield> and <structfield>pos</structfield> are + guaranteed to fit within 0 and the given size. + You don't have to check the range in the callbacks unless any + other condition is required. + </para>
</chapter>
participants (1)
-
Takashi Iwai