Skip to content

Commit 0fedefd

Browse files
Valentine Sinitsyngregkh
authored andcommitted
kernfs: sysfs: support custom llseek method for sysfs entries
As of now, seeking in sysfs files is handled by generic_file_llseek(). There are situations where one may want to customize seeking logic: - Many sysfs entries are fixed files while generic_file_llseek() accepts past-the-end positions. Not only being useless by itself, this also means a bug in userspace code will trigger not at lseek(), but at some later point making debugging harder. - generic_file_llseek() relies on f_mapping->host to get the file size which might not be correct for all sysfs entries. See commit 636b21b ("PCI: Revoke mappings like devmem") as an example. Implement llseek method to override this behavior at sysfs attribute level. The method is optional, and if it is absent, generic_file_llseek() is called to preserve backwards compatibility. Signed-off-by: Valentine Sinitsyn <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7360a48 commit 0fedefd

File tree

4 files changed

+44
-1
lines changed

4 files changed

+44
-1
lines changed

fs/kernfs/file.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,33 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait)
903903
return ret;
904904
}
905905

906+
static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence)
907+
{
908+
struct kernfs_open_file *of = kernfs_of(file);
909+
const struct kernfs_ops *ops;
910+
loff_t ret;
911+
912+
/*
913+
* @of->mutex nests outside active ref and is primarily to ensure that
914+
* the ops aren't called concurrently for the same open file.
915+
*/
916+
mutex_lock(&of->mutex);
917+
if (!kernfs_get_active(of->kn)) {
918+
mutex_unlock(&of->mutex);
919+
return -ENODEV;
920+
}
921+
922+
ops = kernfs_ops(of->kn);
923+
if (ops->llseek)
924+
ret = ops->llseek(of, offset, whence);
925+
else
926+
ret = generic_file_llseek(file, offset, whence);
927+
928+
kernfs_put_active(of->kn);
929+
mutex_unlock(&of->mutex);
930+
return ret;
931+
}
932+
906933
static void kernfs_notify_workfn(struct work_struct *work)
907934
{
908935
struct kernfs_node *kn;
@@ -1005,7 +1032,7 @@ EXPORT_SYMBOL_GPL(kernfs_notify);
10051032
const struct file_operations kernfs_file_fops = {
10061033
.read_iter = kernfs_fop_read_iter,
10071034
.write_iter = kernfs_fop_write_iter,
1008-
.llseek = generic_file_llseek,
1035+
.llseek = kernfs_fop_llseek,
10091036
.mmap = kernfs_fop_mmap,
10101037
.open = kernfs_fop_open,
10111038
.release = kernfs_fop_release,

fs/sysfs/file.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,18 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
167167
return battr->mmap(of->file, kobj, battr, vma);
168168
}
169169

170+
static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset,
171+
int whence)
172+
{
173+
struct bin_attribute *battr = of->kn->priv;
174+
struct kobject *kobj = of->kn->parent->priv;
175+
176+
if (battr->llseek)
177+
return battr->llseek(of->file, kobj, battr, offset, whence);
178+
else
179+
return generic_file_llseek(of->file, offset, whence);
180+
}
181+
170182
static int sysfs_kf_bin_open(struct kernfs_open_file *of)
171183
{
172184
struct bin_attribute *battr = of->kn->priv;
@@ -249,6 +261,7 @@ static const struct kernfs_ops sysfs_bin_kfops_mmap = {
249261
.write = sysfs_kf_bin_write,
250262
.mmap = sysfs_kf_bin_mmap,
251263
.open = sysfs_kf_bin_open,
264+
.llseek = sysfs_kf_bin_llseek,
252265
};
253266

254267
int sysfs_add_file_mode_ns(struct kernfs_node *parent,

include/linux/kernfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ struct kernfs_ops {
316316
struct poll_table_struct *pt);
317317

318318
int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma);
319+
loff_t (*llseek)(struct kernfs_open_file *of, loff_t offset, int whence);
319320
};
320321

321322
/*

include/linux/sysfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ struct bin_attribute {
181181
char *, loff_t, size_t);
182182
ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,
183183
char *, loff_t, size_t);
184+
loff_t (*llseek)(struct file *, struct kobject *, struct bin_attribute *,
185+
loff_t, int);
184186
int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
185187
struct vm_area_struct *vma);
186188
};

0 commit comments

Comments
 (0)