9ns: Allow racy truncations
[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  * - Hole punching / truncate:  pm_remove_contig() leaves behind pages if they
61  *   were concurrently opened.  We can't detach from the tree since the pm_page
62  *   assumes it is always hooked in.  This means a truncate during a read or
63  *   mmap could leave data behind in the PM, which will be accessible when len
64  *   gets increased again (e.g. seek and write).  Truncate could zero that page,
65  *   though we'd need a history counter so reads don't see a partial value.
66  *   Further, pinned VMRs get skipped.  During trunc, they should get removed
67  *   and generate a SIGBUS on access.
68  * - Heavily integrated with struct page.  Maybe some sort of 'struct page' on
69  *   demand, that is built for an IO mapping.  There might be some huge-page
70  *   stuff here too.
71  * - The pm_ops callbacks and whatnot could use some help, even just the
72  *   arguments and indirections.  Maybe integrate them more into the funcs, e.g.
73  *   fs_file_*().  They probably should be fs_file_ops.  For now, the pm ops
74  *   assume the qlock is held.
75  */
76
77 struct fs_file;
78
79 /* TODO: Once we get rid of the VFS and rework the PM, we can put the PM ops in
80  * here properly. */
81 struct fs_file_ops {
82         struct page_map_operations;     /* readpage and writepage */
83         void (*punch_hole)(struct fs_file *f, off64_t begin, off64_t end);
84         bool (*can_grow_to)(struct fs_file *f, size_t len);
85 };
86
87 #define FSF_DIRTY                               (1 << 1)
88
89 struct fs_file {
90         struct dir                                      dir;
91         int                                                     flags;
92         qlock_t                                         qlock;
93         struct fs_file_ops                      *ops;
94         struct page_map                         *pm;
95         void                                            *priv;
96
97         /* optional inline storage */
98         char                                            static_name[KNAMELEN];  /* for dir->name */
99         struct page_map                         static_pm;                              /* for pm */
100         /* we need to be aligned to 64 bytes for the linker tables. */
101 } __attribute__ ((aligned(64)));
102
103 static inline bool caller_has_file_perms(struct fs_file *f, int omode)
104 {
105         return caller_has_dir_perms(&f->dir, omode);
106 }
107
108 static inline void fs_file_perm_check(struct fs_file *f, int omode)
109 {
110         dir_perm_check(&f->dir, omode);
111 }
112
113 static inline size_t fs_file_get_length(struct fs_file *f)
114 {
115         return ACCESS_ONCE(f->dir.length);
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);