ovl: stack file ops
[linux-block.git] / fs / overlayfs / file.c
1 /*
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
14 static 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
34 static int ovl_open(struct inode *inode, struct file *file)
35 {
36         struct dentry *dentry = file_dentry(file);
37         struct file *realfile;
38         int err;
39
40         err = ovl_open_maybe_copy_up(dentry, file->f_flags);
41         if (err)
42                 return err;
43
44         /* No longer need these flags, so don't pass them on to underlying fs */
45         file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
46
47         realfile = ovl_open_realfile(file);
48         if (IS_ERR(realfile))
49                 return PTR_ERR(realfile);
50
51         file->private_data = realfile;
52
53         return 0;
54 }
55
56 static int ovl_release(struct inode *inode, struct file *file)
57 {
58         fput(file->private_data);
59
60         return 0;
61 }
62
63 static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
64 {
65         struct inode *realinode = ovl_inode_real(file_inode(file));
66
67         return generic_file_llseek_size(file, offset, whence,
68                                         realinode->i_sb->s_maxbytes,
69                                         i_size_read(realinode));
70 }
71
72 const struct file_operations ovl_file_operations = {
73         .open           = ovl_open,
74         .release        = ovl_release,
75         .llseek         = ovl_llseek,
76 };