vmm: refactor userspace's emsr_fakewrite()
[akaros.git] / kern / include / fs_file.h
1 /* Copyright (c) 2018 Google Inc
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * fs_file: structs and helpers for files for 9ns devices
6  */
7
8 #pragma once
9
10 #include <ns.h>
11 #include <pagemap.h>
12
13 /* fs_file has all the info of the 9ns dir and the dirtab (which is a subset of
14  * struct dir), plus whatever is needed for generic mmappable filesystems.
15  * Specifically, it has a page_map and a few synchronization fields.  It doesn't
16  * need to support mmap either.  Longer range, fs_file can replace dirtab for
17  * static device filesystems.
18  *
19  * Most fs_files will end up being tree_files (see below).  Some devices might
20  * use fs_files that are hooked in to their own tree structures.
21  *
22  * fs_info is for devices to use.  For instance, #mnt will probably have an
23  * actual chan for every walked fs_file.  It will use that chan/FID for all of
24  * its operations on the backend: walking to discover child files, stat()ing to
25  * get fs_file metadata, reading and writing pages for the page cache, etc.
26  *
27  *
28  * Synchronization rules
29  * ------------------
30  * Note this qlock is also used by tree_file code.  See below for details.
31  *
32  * Hold the qlock when changing the metadata of a file.  This includes changing
33  * parts of dir (length, name, permissions/mode, atimes), etc.  Tree files will
34  * hold this qlock when changing a parent's children.  See the notes around
35  * fs_file_punch_hole for details about read, write, trunc, and the length.
36  *
37  * Readers who just 'peak' at atomically-writable fields do not need to grab the
38  * qlock.  For example, you can glance at dir->perms.  In arbitrary cases, you
39  * can't look at name, since we can't change it atomically (it can smear or run
40  * into other issues).  'name' is somewhat special: if you find the tree_file
41  * via a RCU protected wc hash lookup, you can access name.
42  *
43  * There's actually not a lot in dir that is atomically writable.
44  * atime/mtime/ctime won't be when we use timespecs.  We might be able to craft
45  * something for lockless reads of dir state with seq counters.  That would save
46  * a qlock for each fs_file on a readdir.  It's a little tricky; we probably
47  * need to kfree_rcu the dir->name (never leak in a convD2M, even if we retry),
48  * and we need to be careful about multi-field changes where the changer might
49  * block.  i.e. don't hold a seq lock when making a backend op, which could
50  * block.  Not too concerned with this for now, esp since it's not clear how
51  * chown will work.
52  *
53  * Note that even if we can atomically write to the dir, we should still grab
54  * the qlock.  Often we're syncing with other writers anyways, and there may be
55  * readers who want to make sure parts of the dir doesn't change.  When we do
56  * write a field that can be locklessly read, use WRITE_ONCE.
57  *
58  * The PM code is pretty rough.  For now, we're using the old VFS PM code, but
59  * it needs a few changes:
60  * - Heavily integrated with struct page.  Maybe some sort of 'struct page' on
61  *   demand, that is built for an IO mapping.  There might be some huge-page
62  *   stuff here too.
63  * - The pm_ops callbacks and whatnot could use some help, even just the
64  *   arguments and indirections.  Maybe integrate them more into the funcs, e.g.
65  *   fs_file_*().  They probably should be fs_file_ops.  For now, the pm ops
66  *   assume the qlock is held.
67  */
68
69 struct fs_file;
70
71 /* TODO: Once we get rid of the VFS and rework the PM, we can put the PM ops in
72  * here properly. */
73 struct fs_file_ops {
74         struct page_map_operations;     /* readpage and writepage */
75         void (*punch_hole)(struct fs_file *f, off64_t begin, off64_t end);
76         bool (*can_grow_to)(struct fs_file *f, size_t len);
77 };
78
79 #define FSF_DIRTY               (1 << 1)
80
81 struct fs_file {
82         struct dir                      dir;
83         int                             flags;
84         qlock_t                         qlock;
85         struct fs_file_ops              *ops;
86         struct page_map                 *pm;
87         void                            *priv;
88
89         /* optional inline storage */
90         char                            static_name[KNAMELEN];  /* dir->name */
91         struct page_map                 static_pm;              /* for pm */
92         /* we need to be aligned to 64 bytes for the linker tables. */
93 } __attribute__ ((aligned(64)));
94
95 static inline bool caller_has_file_perms(struct fs_file *f, int omode)
96 {
97         return caller_has_dir_perms(&f->dir, omode);
98 }
99
100 static inline void fs_file_perm_check(struct fs_file *f, int omode)
101 {
102         dir_perm_check(&f->dir, omode);
103 }
104
105 static inline size_t fs_file_get_length(struct fs_file *f)
106 {
107         return ACCESS_ONCE(f->dir.length);
108 }
109
110 void fs_file_init(struct fs_file *f, const char *name, struct fs_file_ops *ops);
111 void fs_file_set_basename(struct fs_file *f, const char *name);
112 void fs_file_change_basename(struct fs_file *f, const char *name);
113 void fs_file_init_dir(struct fs_file *f, uint16_t dir_type, uint32_t dir_dev,
114                       struct username *user, int perm);
115 void fs_file_copy_from_dir(struct fs_file *f, struct dir *dir);
116 void cleanup_fs_file(struct fs_file *f);
117
118 #define FSF_ATIME               (1 << 0)
119 #define FSF_BTIME               (1 << 1)
120 #define FSF_CTIME               (1 << 2)
121 #define FSF_MTIME               (1 << 3)
122
123 void __set_acmtime_to(struct fs_file *f, int which, struct timespec *t);
124 void __set_acmtime(struct fs_file *f, int which);
125 void set_acmtime_to(struct fs_file *f, int which, struct timespec *t);
126 void set_acmtime_noperm(struct fs_file *f, int which);
127
128 size_t fs_file_stat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz);
129 void fs_file_truncate(struct fs_file *f, off64_t to);
130 size_t fs_file_read(struct fs_file *f, uint8_t *buf, size_t count,
131                     off64_t offset);
132 size_t fs_file_write(struct fs_file *f, const uint8_t *buf, size_t count,
133                      off64_t offset);
134 size_t fs_file_wstat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz);