mm: 9ns: Add support for mmap
[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 contents of a file.  This includes writes
33  * (which need to adjust the len and add data), truncate / hole-punches
34  * (which need to adjust the len and remove data), changing parts of dir (name,
35  * permissions/mode, atimes), etc.  Tree files will hold this qlock when
36  * changing a parent's children.
37  *
38  * Readers who just 'peak' at atomically-writable fields do not need to grab the
39  * qlock.  For example, you can glance at dir->perms.  In arbitrary cases, you
40  * can't look at name, since we can't change it atomically (it can smear or run
41  * into other issues).  'name' is somewhat special: if you find the tree_file
42  * via a RCU protected wc hash lookup, you can access name.
43  *
44  * fs_file_read() can skip the qlock in the common case.  It can try to grab a
45  * page from the PM (if it was there, then some ordering exists on the
46  * concurrent ops where the read partially succeeds).  If the read fails to find
47  * a page, then we'd need to lock, since that interacts with length.
48  *
49  * There's actually not a lot in dir that is atomically writable.
50  * atime/mtime/ctime won't be when we use timespecs.  We might be able to craft
51  * something for lockless reads of dir state with seq counters.  That would save
52  * a qlock for each fs_file on a readdir.  It's a little tricky; we probably
53  * need to kfree_rcu the dir->name (never leak in a convD2M, even if we retry),
54  * and we need to be careful about multi-field changes where the changer might
55  * block.  i.e. don't hold a seq lock when making a backend op, which could
56  * block.  Not too concerned with this for now, esp since it's not clear how
57  * chown will work.
58  *
59  * Note that even if we can atomically write to the dir, we should still grab
60  * the qlock.  The reason is that there may be readers who want to make sure
61  * parts of the dir doesn't change.
62  *
63  * The PM code is pretty rough.  For now, we're using the old VFS PM code, but
64  * it needs a few changes:
65  * - Hole punching / truncate:  pm_remove_contig() leaves behind pages if they
66  *   were concurrently opened.  We can't detach from the tree since the pm_page
67  *   assumes it is always hooked in.  This means a truncate during a read or
68  *   mmap could leave data behind in the PM, which will be accessible when len
69  *   gets increased again (e.g. seek and write).  Truncate could zero that page,
70  *   though we'd need a history counter so reads don't see a partial value.
71  *   Further, pinned VMRs get skipped.  During trunc, they should get removed
72  *   and generate a SIGBUS on access.
73  * - Heavily integrated with struct page.  Maybe some sort of 'struct page' on
74  *   demand, that is built for an IO mapping.  There might be some huge-page
75  *   stuff here too.
76  * - The pm_ops callbacks and whatnot could use some help, even just the
77  *   arguments and indirections.  Maybe integrate them more into the funcs, e.g.
78  *   fs_file_*().  They probably should be fs_file_ops.  For now, the pm ops
79  *   assume the qlock is held.
80  */
81
82 struct fs_file;
83
84 /* TODO: Once we get rid of the VFS and rework the PM, we can put the PM ops in
85  * here properly. */
86 struct fs_file_ops {
87         struct page_map_operations;     /* readpage and writepage */
88         void (*punch_hole)(struct fs_file *f, off64_t begin, off64_t end);
89         bool (*can_grow_to)(struct fs_file *f, size_t len);
90 };
91
92 #define FSF_DIRTY                               (1 << 1)
93
94 struct fs_file {
95         struct dir                                      dir;
96         int                                                     flags;
97         qlock_t                                         qlock;
98         struct fs_file_ops                      *ops;
99         struct page_map                         *pm;
100         void                                            *priv;
101
102         /* optional inline storage */
103         char                                            static_name[KNAMELEN];  /* for dir->name */
104         struct page_map                         static_pm;                              /* for pm */
105         /* we need to be aligned to 64 bytes for the linker tables. */
106 } __attribute__ ((aligned(64)));
107
108 static inline bool caller_has_file_perms(struct fs_file *f, int omode)
109 {
110         return caller_has_dir_perms(&f->dir, omode);
111 }
112
113 static inline void fs_file_perm_check(struct fs_file *f, int omode)
114 {
115         dir_perm_check(&f->dir, omode);
116 }
117
118 void fs_file_init(struct fs_file *f, const char *name, struct fs_file_ops *ops);
119 void fs_file_set_basename(struct fs_file *f, const char *name);
120 void fs_file_change_basename(struct fs_file *f, const char *name);
121 void fs_file_init_dir(struct fs_file *f, int dir_type, int dir_dev,
122                       struct username *user, int perm);
123 void fs_file_copy_from_dir(struct fs_file *f, struct dir *dir);
124 void cleanup_fs_file(struct fs_file *f);
125
126 #define FSF_ATIME                               (1 << 0)
127 #define FSF_BTIME                               (1 << 1)
128 #define FSF_CTIME                               (1 << 2)
129 #define FSF_MTIME                               (1 << 3)
130
131 void __set_acmtime_to(struct fs_file *f, int which, struct timespec *t);
132 void __set_acmtime(struct fs_file *f, int which);
133 void set_acmtime_to(struct fs_file *f, int which, struct timespec *t);
134 void set_acmtime_noperm(struct fs_file *f, int which);
135
136 size_t fs_file_stat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz);
137 void fs_file_truncate(struct fs_file *f, off64_t to);
138 size_t fs_file_read(struct fs_file *f, uint8_t *buf, size_t count,
139                     off64_t offset);
140 size_t fs_file_write(struct fs_file *f, const uint8_t *buf, size_t count,
141                      off64_t offset);
142 size_t fs_file_wstat(struct fs_file *f, uint8_t *m_buf, size_t m_buf_sz);