mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
cb787f4ac0
no_llseek had been defined to NULL two years ago, in commit 868941b144
("fs: remove no_llseek")
To quote that commit,
At -rc1 we'll need do a mechanical removal of no_llseek -
git grep -l -w no_llseek | grep -v porting.rst | while read i; do
sed -i '/\<no_llseek\>/d' $i
done
would do it.
Unfortunately, that hadn't been done. Linus, could you do that now, so
that we could finally put that thing to rest? All instances are of the
form
.llseek = no_llseek,
so it's obviously safe.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
114 lines
2.4 KiB
C
114 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2012 Red Hat, Inc.
|
|
* Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
|
|
*/
|
|
|
|
#include <linux/efi.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mount.h>
|
|
|
|
#include "internal.h"
|
|
|
|
static ssize_t efivarfs_file_write(struct file *file,
|
|
const char __user *userbuf, size_t count, loff_t *ppos)
|
|
{
|
|
struct efivar_entry *var = file->private_data;
|
|
void *data;
|
|
u32 attributes;
|
|
struct inode *inode = file->f_mapping->host;
|
|
unsigned long datasize = count - sizeof(attributes);
|
|
ssize_t bytes;
|
|
bool set = false;
|
|
|
|
if (count < sizeof(attributes))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&attributes, userbuf, sizeof(attributes)))
|
|
return -EFAULT;
|
|
|
|
if (attributes & ~(EFI_VARIABLE_MASK))
|
|
return -EINVAL;
|
|
|
|
data = memdup_user(userbuf + sizeof(attributes), datasize);
|
|
if (IS_ERR(data))
|
|
return PTR_ERR(data);
|
|
|
|
bytes = efivar_entry_set_get_size(var, attributes, &datasize,
|
|
data, &set);
|
|
if (!set && bytes) {
|
|
if (bytes == -ENOENT)
|
|
bytes = -EIO;
|
|
goto out;
|
|
}
|
|
|
|
if (bytes == -ENOENT) {
|
|
drop_nlink(inode);
|
|
d_delete(file->f_path.dentry);
|
|
dput(file->f_path.dentry);
|
|
} else {
|
|
inode_lock(inode);
|
|
i_size_write(inode, datasize + sizeof(attributes));
|
|
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
|
inode_unlock(inode);
|
|
}
|
|
|
|
bytes = count;
|
|
|
|
out:
|
|
kfree(data);
|
|
|
|
return bytes;
|
|
}
|
|
|
|
static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
struct efivar_entry *var = file->private_data;
|
|
unsigned long datasize = 0;
|
|
u32 attributes;
|
|
void *data;
|
|
ssize_t size = 0;
|
|
int err;
|
|
|
|
while (!__ratelimit(&file->f_cred->user->ratelimit))
|
|
msleep(50);
|
|
|
|
err = efivar_entry_size(var, &datasize);
|
|
|
|
/*
|
|
* efivarfs represents uncommitted variables with
|
|
* zero-length files. Reading them should return EOF.
|
|
*/
|
|
if (err == -ENOENT)
|
|
return 0;
|
|
else if (err)
|
|
return err;
|
|
|
|
data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
|
|
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
size = efivar_entry_get(var, &attributes, &datasize,
|
|
data + sizeof(attributes));
|
|
if (size)
|
|
goto out_free;
|
|
|
|
memcpy(data, &attributes, sizeof(attributes));
|
|
size = simple_read_from_buffer(userbuf, count, ppos,
|
|
data, datasize + sizeof(attributes));
|
|
out_free:
|
|
kfree(data);
|
|
|
|
return size;
|
|
}
|
|
|
|
const struct file_operations efivarfs_file_operations = {
|
|
.open = simple_open,
|
|
.read = efivarfs_file_read,
|
|
.write = efivarfs_file_write,
|
|
};
|