seq_file
полезна для файлов, которые содержание не хранится где-то, но генерируется на лету, когда пользователь нуждается. Это может быть генерация с использованием единственного формата строки (например, %s\n
в вопросительном столбце) или комбинирования кусков разных или одинаковых типов.
При использовании функции seq_file
, писатель кода не беспокоится о размере буфера для чтения, смещении текущего файла и доступе к __user
данных с copy_to_user()
. Вместо этого концентрируется на создании файла, как будто это поток неограниченного размера. Все остальное обрабатывается автоматически seq_file
.
Например, приведенный пример может быть implememted с помощью seq_file
следующего образом:
int param_show(struct seq_file *m, void *v)
{
(void)v; /* Unused */
seq_printf(m, "%s\n", param); /* Just generate content of the "file" */
return 0;
}
int my_proc_open(struct inode *inode, struct file *filp)
{
return single_open(filp, ¶m_show, NULL);
}
const struct file_operations my_proc_ops = {
.owner = THIS_MODULE,
.open = &my_proc_open,
.read = &seq_read
};
Для сравнения, та же функциональность чтения реализована непосредственно:
ssize_t my_proc_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
{
ssize_t ret;
size_t param_len = strlen(param);
/* Write to buffer everything except terminating '\n' */
ret = simple_read_from_buffer(buffer, count, offset, param, param_len);
/* But processing of additional '\n' is much more complex */
if (ret >= 0 && ret < (ssize_t)count && *offset == param_len) {
char ch = '\n';
int err = put_user(buffer + ret, &ch); /* Try to append '\n' */
if (!err) {
/* Success */
++ret;
++(*offset);
} else if (!ret) {
/* Fail and nothing has been read before */
ret = err;
}
}
return ret;
}
const struct file_operations my_proc_ops = {
.owner = THIS_MODULE,
.read = &my_proc_read
};
Как можно видеть, при чтении готового содержания params
- однострочный (используется вспомогательный simple_read_from_buffer
), дополнительный \n
, который должен быть сгенерирован, делает реализацию намного сложнее ,
Минусом seq_file
является его Perfomance: содержание, генерируется в .show
функции не кэшируются, поэтому каждый последующий read()
системный вызов требует .show
называться снова. Кроме того, для создания содержимого файла используется внутренний буфер, и этот буфер должен быть выделен в кучу.
Но в большинстве случаев файлы, созданные на лету, небольшие и/или редко читаются и/или не критичны по производительности. Так что seq_file
подходит для таких файлов практически во всех случаях.
И ** как вы создаете файл ** с помощью этой '.read' функции? Кроме того, неправильный доступ к буферам '__user' * напрямую * (что также выполняется с помощью' sprintf'): вы должны использовать 'copy_to_user' /' copy_from_user'. – Tsyvarev
Этот файл создается в/proc с помощью функции proc_create из linux/proc_fs.h – anukalp
Хм, и как вы получаете доступ к этому файлу из пользовательского пространства? Используя 'cat' или какую-то рукописную программу C? – Tsyvarev