aboutsummaryrefslogtreecommitdiff
path: root/fs/efivarfs/file.c
diff options
context:
space:
mode:
authorAlex Shi <alex.shi@linaro.org>2016-03-18 11:41:51 +0800
committerAlex Shi <alex.shi@linaro.org>2016-03-18 16:01:49 +0800
commit70e00db9eb8ffc4dcaf5f035ec6a4440ba428794 (patch)
treeea67e279adedc950c3d4d8e98546b3823a2b3e93 /fs/efivarfs/file.c
parent34e0913e457f8469667faf5fa600447aa93371cf (diff)
parentdfbed80c63bb8d965067da3a6dbcc4682edcce0c (diff)
Merge remote-tracking branch 'lts/linux-3.14.y' into linux-linaro-lsk-v3.14lsk-v3.14-16.03linux-linaro-lsk-v3.14
Conflicts: Most of conflicts are due to efivar_validate() change which introduced a new parameter to check efi guid. I added efi guid for this change in sanity_check()/efivar_create() in drivers/firmware/efi/efivars.c and keep new efivar_validate() in drivers/firmware/efi/vars.c, since it's newer than LSK version. nothing need mentioned in include/linux/efi.h
Diffstat (limited to 'fs/efivarfs/file.c')
-rw-r--r--fs/efivarfs/file.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
index 8dd524f32284..08f105a06fbf 100644
--- a/fs/efivarfs/file.c
+++ b/fs/efivarfs/file.c
@@ -10,6 +10,7 @@
#include <linux/efi.h>
#include <linux/fs.h>
#include <linux/slab.h>
+#include <linux/mount.h>
#include "internal.h"
@@ -108,9 +109,79 @@ out_free:
return size;
}
+static int
+efivarfs_ioc_getxflags(struct file *file, void __user *arg)
+{
+ struct inode *inode = file->f_mapping->host;
+ unsigned int i_flags;
+ unsigned int flags = 0;
+
+ i_flags = inode->i_flags;
+ if (i_flags & S_IMMUTABLE)
+ flags |= FS_IMMUTABLE_FL;
+
+ if (copy_to_user(arg, &flags, sizeof(flags)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+efivarfs_ioc_setxflags(struct file *file, void __user *arg)
+{
+ struct inode *inode = file->f_mapping->host;
+ unsigned int flags;
+ unsigned int i_flags = 0;
+ int error;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (copy_from_user(&flags, arg, sizeof(flags)))
+ return -EFAULT;
+
+ if (flags & ~FS_IMMUTABLE_FL)
+ return -EOPNOTSUPP;
+
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -EPERM;
+
+ if (flags & FS_IMMUTABLE_FL)
+ i_flags |= S_IMMUTABLE;
+
+
+ error = mnt_want_write_file(file);
+ if (error)
+ return error;
+
+ mutex_lock(&inode->i_mutex);
+ inode->i_flags &= ~S_IMMUTABLE;
+ inode->i_flags |= i_flags;
+ mutex_unlock(&inode->i_mutex);
+
+ mnt_drop_write_file(file);
+
+ return 0;
+}
+
+long
+efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
+{
+ void __user *arg = (void __user *)p;
+
+ switch (cmd) {
+ case FS_IOC_GETFLAGS:
+ return efivarfs_ioc_getxflags(file, arg);
+ case FS_IOC_SETFLAGS:
+ return efivarfs_ioc_setxflags(file, arg);
+ }
+
+ return -ENOTTY;
+}
+
const struct file_operations efivarfs_file_operations = {
.open = simple_open,
.read = efivarfs_file_read,
.write = efivarfs_file_write,
.llseek = no_llseek,
+ .unlocked_ioctl = efivarfs_file_ioctl,
};