blob: 061a22511b5b262523b9da037787925d544a3d21 [file] [log] [blame]
Miklos Szeredid1d04ef2018-07-18 15:44:41 +02001/*
2 * Copyright (C) 2017 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 */
8
9#include <linux/cred.h>
10#include <linux/file.h>
11#include <linux/xattr.h>
12#include "overlayfs.h"
13
14static struct file *ovl_open_realfile(const struct file *file)
15{
16 struct inode *inode = file_inode(file);
17 struct inode *upperinode = ovl_inode_upper(inode);
18 struct inode *realinode = upperinode ?: ovl_inode_lower(inode);
19 struct file *realfile;
20 const struct cred *old_cred;
21
22 old_cred = ovl_override_creds(inode->i_sb);
23 realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME,
24 realinode, current_cred());
25 revert_creds(old_cred);
26
27 pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
28 file, file, upperinode ? 'u' : 'l', file->f_flags,
29 realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
30
31 return realfile;
32}
33
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020034#define OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT)
35
36static int ovl_change_flags(struct file *file, unsigned int flags)
37{
38 struct inode *inode = file_inode(file);
39 int err;
40
41 /* No atime modificaton on underlying */
42 flags |= O_NOATIME;
43
44 /* If some flag changed that cannot be changed then something's amiss */
45 if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
46 return -EIO;
47
48 flags &= OVL_SETFL_MASK;
49
50 if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))
51 return -EPERM;
52
53 if (flags & O_DIRECT) {
54 if (!file->f_mapping->a_ops ||
55 !file->f_mapping->a_ops->direct_IO)
56 return -EINVAL;
57 }
58
59 if (file->f_op->check_flags) {
60 err = file->f_op->check_flags(flags);
61 if (err)
62 return err;
63 }
64
65 spin_lock(&file->f_lock);
66 file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
67 spin_unlock(&file->f_lock);
68
69 return 0;
70}
71
72static int ovl_real_fdget(const struct file *file, struct fd *real)
73{
74 struct inode *inode = file_inode(file);
75
76 real->flags = 0;
77 real->file = file->private_data;
78
79 /* Has it been copied up since we'd opened it? */
80 if (unlikely(file_inode(real->file) != ovl_inode_real(inode))) {
81 real->flags = FDPUT_FPUT;
82 real->file = ovl_open_realfile(file);
83
84 return PTR_ERR_OR_ZERO(real->file);
85 }
86
87 /* Did the flags change since open? */
88 if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME))
89 return ovl_change_flags(real->file, file->f_flags);
90
91 return 0;
92}
93
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020094static int ovl_open(struct inode *inode, struct file *file)
95{
96 struct dentry *dentry = file_dentry(file);
97 struct file *realfile;
98 int err;
99
100 err = ovl_open_maybe_copy_up(dentry, file->f_flags);
101 if (err)
102 return err;
103
104 /* No longer need these flags, so don't pass them on to underlying fs */
105 file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
106
107 realfile = ovl_open_realfile(file);
108 if (IS_ERR(realfile))
109 return PTR_ERR(realfile);
110
111 file->private_data = realfile;
112
113 return 0;
114}
115
116static int ovl_release(struct inode *inode, struct file *file)
117{
118 fput(file->private_data);
119
120 return 0;
121}
122
123static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
124{
125 struct inode *realinode = ovl_inode_real(file_inode(file));
126
127 return generic_file_llseek_size(file, offset, whence,
128 realinode->i_sb->s_maxbytes,
129 i_size_read(realinode));
130}
131
132const struct file_operations ovl_file_operations = {
133 .open = ovl_open,
134 .release = ovl_release,
135 .llseek = ovl_llseek,
136};